Ну от класно ж, на початку зими витягти з шафи зимову куртку і в кишені знайти щось приємне — цукерку, забуту купюру або щасливий квиток. Так буває і в Python – працюєш, ліпиш, видумуєш, а потім виявляється, що все можна зробити гарніше і простіше. Що розумні люди цей велосипед давно вже придумали. Бери та й катайся.
Сьогодні розберемо задачу 835 з e-olymp – з назвою ПОКЕР.
Умова:
Задано 5 цілих чисел. Серед них:
- якщо однакові 5, то вивести "Impossible", інакше
- якщо однакові 4, то вивести "Four of a Kind", інакше
- якщо однакові 3 і 2, то вивести "Full House", інакше
- якщо є 5 послідовних, то вивести "Straight", інакше
- якщо однакові 3, то вивести "Three of a Kind", інакше
- якщо однакові 2 і 2, то вивести "Two Pairs", інакше
- якщо однакові 2, то вивести "One Pair", інакше
- вивести "Nothing".
Вхідні дані
У першому рядку задано 5 чисел (від 1 до 13 включно) через пропуск.
Вихідні дані
Виводиться один рядок - результат аналізу.
Ліміт часу 1 секунда
Ліміт використання пам'яті 64 MB
Приклади:
Sample 1
1 3 9 3 2
One Pair
Sample 2
1 5 5 4 4
Two Pairs
Sample 3
1 5 2 4 3
Straight
Sample 4
10 11 12 13 1
Nothing
У більшості мов програмування закидаємо числа в масив або список і граємося за допомогою комбінацій IF. Чи можна так розв’язати задачу? Звичайно. Але пайтон — то як модна куртка з купою кишень. І в деяких кишенях ховаються справжні смаколики. Сьогодні дістанемо модуль сollection. При чому цей модуль дістанемо зі стандартної бібліотеки, не треба гукати pip або GitHub.
А в модулі сollection є чудова штука - Counter - вид словника, який дозволяє рахувати кількість незмінних об'єктів.
А функція most_common ([n]) повертає n елементів, що найчастіше зустрічаються, в порядку убування зустрічальності (сподіваюсь, що мене не читають філологі, бо приб’ють).
Якщо n не вказано, повертаються всі елементи.
Давайте на прикладі:
import collections
girls = ['гарна', 'дуже гарна', 'гарна', 'страшно гарна', 'неймовірно гарна', 'дуже гарна', 'дуже гарна']
c = collections.Counter(girls)
Ось як воно працює, якщо попросити всі елементи і частоту їх в послідовності:
print(c.most_common())
# [('дуже гарна', 3), ('гарна', 2), ('страшно гарна', 1), ('неймовірно гарна', 1)]
Визначити елемент, що зустрічається частіше за всіх і його лічильник можна так:
print(c.most_common(1)[0][0])
# 'дуже гарна'
print(c.most_common(1)[0][1])
# 3
Можна сформувати повний список, а не лише одну пару (елемент-лічильник) і знайти, наприклад, який елемент другий по популярності в послідовності і скільки разів він зустрічається:
print(c.most_common()[1][0])
# 'гарна'
print(c.most_common()[1][1])
# 2
Перейдемо до задачі про покер. Як дізнатися, що елемент в послідовності зустрічається 5 разів?
if c.most_common(1)[0][1] == 5:
print('Impossible')
Ну і так далі. Думаю, зрозуміло. Але там є хитрість щодо варіанта "Straight", тобто якщо є 5 послідовних, наприклад 1 5 2 4 3.
Тут, як на мене, варто відсортувати список елементів і порівняти значення першого і останнього. Якщо різниця між ними – чотири, то це і буде те, що нам треба. Але перевірку на "Straight" необхідно проводити в самому кінці програми, тому що інакше програма невірно відпрацює, наприклад, варіант «1 5 5 4 4». Тому нехай спочатку відпрацюють всі попередні правила, а лише потім перевіримо послідовність на "Straight".
І ще, давайте оптимізуємо програму, щоб якомога рідше викликати most_common(). Все ж функція хоч і внутрішня, оптимізована, але час для роботи їй потрібен. Тим більше, що нам треба лише два перших значення лічильника. При чому, якщо послідовність буде «1 1 1 1 1», то другого значення лічильника взагалі не отримаємо, тому що всі елементи однакові.
Враховуючи описані вище нюанси, пропоную свій варіант програми. Своїх учнів я прошу уважно переглянути кожен рядок. Всі варіанти оптимізації або власних підходів – вітаються як завжди.
# Задача 835
# www.e-olymp.com/uk/problems/835
import collections
lst = [int(x) for x in input().split()]
lst.sort()
c = collections.Counter(lst)
first_counter = c.most_common(1)[0][1]
second_counter = c.most_common(2)[1][1] if first_counter != 5 else 0
if first_counter == 5:
print('Impossible')
elif first_counter == 4:
print('Four of a Kind')
elif first_counter == 3 and second_counter == 2:
print('Full House')
elif first_counter == 3:
print('Three of a Kind')
elif first_counter == 2 and second_counter == 2:
print('Two Pairs')
elif first_counter == 2:
print('One Pair')
elif lst[4] - lst[0] == 4:
print('Straight')
else:
print('Nothing')