От ливадите до Лас Вегас (и назад)
- Краен срок:
- 15.11.2022 18:00
- Точки:
- 10
Срокът за предаване на решения е отминал
Небезизвестен факт е, че меката на хазарта е Лас Вегас.
Фактът, че името "Лас Вегас" значи "ливади", обаче, не е чак толкова известен.
Това, което ги свързва, е, че стандартното тесте карти за игра е еднакво полулярно, както в Лас Вегас, така и по селските ливади. Само игрите (в повечето случаи) са различни.
С днешната задача ще направим един мост между двата свята и ще напишем код, който е еднакво полезен и на двата фронта.
Целта на задачата е да подготвим гръбнака на онлайн игра, която позволява да се играят Белот и Покер.
Защо точно онлайн? Едва ли има значение за решението на задачата ви, но както е казал един велик български шоумен:
Най-хубавите сайтове са в Интернет!
Напишете следните класове.
-
Клас Card, който представлява една единствена карта от тестето. Класът има следната спецификация.
Аргументи, които класът очаква при инициализиране:
-
suit
- боя на картата от типstr
- 'clubs', 'diamonds', 'hearts', 'spades'; -
face
- стойност на картата от типstr
- '2',...'9', '10', 'J', 'Q', 'K' или 'A'.
Методи, които класът имплементира:
-
get_suit()
- връща стойността на боята на картата в типstr
; -
get_face()
- връща стойността на лицето на картата в типstr
.
-
-
Клас Deck, който представлява стандартно тесте от 52 карти (т.е. без жокерите), използвайки класа
Card
. Класът има следната спецификация.Аргументи, които класът очаква при инициализиране:
-
face_filter
- optional аргумент, който представлява списък от дефиниция на карти, подадени катоlist
отstr
. Ако при инициализация класът получи този аргумент, инстанцираното тесте трябва да съдържа само картите, които са подадени в списъка. Списъкът съдържа само вида карта, без нейната боя - всички карти от този тип, независимо от боята, остават в игра.
Напримерface_filter = ['K', 'A']
значи, че искам да играя игра, в която участват само Поп и Асо от всички 4 бои.
Методи, които класът имплементира:
-
cut()
- цепи тестето, т.е. взима една или повече карти отгоре и ги слага отдолу; -
shuffle()
- разбърква картите в тестето; -
get_cards()
- връща списък от карти катоlist
отCard
- картите, които в момента са налични за игра, в реда, в който са подредени в момента.
-
-
Клас Player - представлява играч на произволна игра. Класът има следната спецификация.
Аргументи, които класът очаква при инициализиране:
- Няма
Методи, които класът имплементира:
-
get_cards()
- връща списък от карти катоlist
отCard
, които играчът притежава в момента.
-
Клас Game - представлява игра с карти. Класът има следната спецификация.
Аргументи, които класът очаква при инициализиране:
-
number_of_players
- брой играчи, нужни за играта в типint
; -
dealing_direction
- посока на раздаване на картите в типstr
('ltr' или 'rtl', съответно left-to-right /от ляво надясно/ и right-to-left /от дясно наляво/); -
dealing_instructions
- инструкции за раздаване катоtuple
отint
. Всеки елемент от tuple-а дефинира брой карти при едно завъртане около играчите. Може да има произволен брой завъртания, стига картите да стигат (приемете, че винаги ще стигат и няма да тестваме за невъзможни инструкции).
Напримерdealing_instructions((1, 2))
значи, че първо ще раздам по една карта на всеки играч (в реда, дефиниран отdealing_direction
), след което ще раздам по още две карти в същия ред.
Методи, които класът имплементира:
-
get_players()
- връща списък с играчи катоlist
отPlayer
, които играят играта, в ред от ляво надясно, започвайки от произволен играч; -
prepare_deck()
- събира раздадените карти от играчите, разбърква тестето и го цепи; -
deal(<Player>)
- раздава тесте карти на играчите, в нужната посока, започвайки от този, подаден като аргумент; -
get_deck()
- връща тестето от карти в типDeck
, което се използва за играта. При вече раздадени карти се очаква обектът, който връщате, да съдържа само тези карти, които не са били раздадени на играчите.
-
-
Клас Belot - представлява игра с карти на Белот. Класът се възползва от дефинираните по-горе класове и инициализира игра със следните спецификации:
- брой играчи - 4;
- посока на раздаване - от ляво надясно;
- инструкции за раздаване - първо по 2 на всеки играч, после по още 3 и накрая по още 3;
- нужни карти - 7, 8, 9, 10, J, Q, K, A.
Аргументи, които класът очаква при инициализиране:
- Няма
-
Клас Poker - представлява игра с карти на Покер. Класът се възползва от дефинираните по-горе класове и инициализира игра със следните спецификации:
- брой играчи - 9;
- посока на раздаване - от дясно наляво;
- инструкции за раздаване - 1 по 1 на всеки играч, докато всички имат по 5;
- нужни карти - цялото тесте.
Аргументи, които класът очаква при инициализиране:
- Няма
FAQ
Q: Защо има толкова много get функции? Нужни ли са те за този дизайн?
A: По-скоро не, не са нужни. Нужни са, обаче, за да можем да изтестваме кода ви без да ви казваме конкретно какви имена на атрибути да използвате.
Q: Как да разбъркам тестето?
А: Все още не сме говорили за модули, така че получавате това наготово:
import random
random.shuffle(<колекция>)
Разбира се, може да използвате и други опции от random
модула - разгледайте документацията и си изберете.
Q: Какво значи, че раздавам или дефинирам ред на играчите от ляво надясно или от дясно наляво?
A: За външния свят няма значение как записваш играчите си в данните и как определяш посоката. Просто се подсигури, че всички методи, които връщат информация за играчите, са консистентни. "От ляво надясно" трябва да е обратната посока на "от дясно наляво".
Q: Имам ли право да дефинирам методи и атрибути, които не са споменати в условието?
A: Да, но класът ти трябва да очаква точно тези аргументи, които сме дефинирали, за да можем да изтестваме кода. Ако например твоят клас Player очаква аргумент при инициализиране, а нашият тест се опита да инстанцира Player без подаден аргумент, ние ще получим грешка, а ти фейлващ тест, т.е. по-малко точки.
Q: Може ли да дадете пример за това как клиентът би използвал това?
A: Може:
belot = Belot()
players = belot.get_players()
belot.prepare_deck()
belot.deal(players[0])
# Play the game, argue about the rules, curse, fight, argue about who should deal the cards during second round...
belot.prepare_deck()
belot.deal(players[1])