comp10001-project03/project03

197 lines
9.3 KiB
Text

--------------------------------------------------------------------------------
Part 1 - Valid table
Write a function comp10001huxxy_valid_table() which takes a single argument:
- groups, a list of lists of cards (each a 2-element string, where the first
letter is the card value and the second letter is the card suit, e.g. '3H' for
the 3 of Hearts), where each list of cards represents a single group on the
table, and the combined list of lists represents the combined groups played to
the table.
Your function should return a bool, which evaluates whether the table state is
valid or not. Recall from the rules of the game that the table is valid if all
groups are valid, where a group can take one of the following two forms:
- an N-of-a-kind (i.e. three or more cards of the same value), noting that in
the case of a 3-of-a-kind, each card must have a unique suit (e.g. ['2S',
'2S', '2C'] is not a valid 3-of-a-kind, as the Two of Spades has been played
twice), and if there are 4 or more cards, all suits must be present.
- a run (i.e. a group of 3 or more cards, starting from the lowest-valued card,
and ending with the highest-valued card, forming a continuous sequence in
terms of value, and alternating in colour; note that the specific ordering of
cards in the list is not significant, i.e. ['2C', '3D', '4S'] and ['4S', '2C',
'3D'] both make up the same run.
Example function calls are as follows:
>>> comp10001huxxy_valid_table([])
True
>>> comp10001huxxy_valid_table([['AC']])
False
>>> # run too short
>>> comp10001huxxy_valid_table([['AC', '2S']])
False
>>> # run doesn't alternate in colour
>>> comp10001huxxy_valid_table([['AC', '2S', '3H']])
False
>>> # values not adjacent
>>> comp10001huxxy_valid_table([['AC', '2S', '4H']])
False
>>> comp10001huxxy_valid_table([['AC', '2H', '3S']])
True
>>> # test unsorted run
>>> comp10001huxxy_valid_table([['3C', 'AS', '2H']])
True
>>> comp10001huxxy_valid_table([['0C', 'JH', 'QS', 'KH', '9D']])
True
>>> # n-of-kind too short
>>> comp10001huxxy_valid_table([['2C', '2H']])
False
>>> # same suit twice for 3-of-kind
>>> comp10001huxxy_valid_table([['2C', '2H', '2C']])
False
>>> # same suit twice for 4-of-kind
>>> comp10001huxxy_valid_table([['2C', '2H', '2S', '2C']])
False
>>> comp10001huxxy_valid_table([['2C', '2H', '2S']])
True
>>> comp10001huxxy_valid_table([['2C', '2H', '2S', '2D']])
True
>>> comp10001huxxy_valid_table([['2C', '2H', '2S', '2D', '2S']])
True
>>> comp10001huxxy_valid_table([['2C', '2H', '2S', '2D', '2S'],
['0D', '9C', '8H']])
True
--------------------------------------------------------------------------------
Part 2 - Group validation
Write a function comp10001go_valid_groups() which takes a single argument:
- groups, a list of groups, each of which is a list of cards (following the same
definition as Part 1)
Your function should return a Boolean indicating whether all groups are valid or
not (i.e. a singleton card, a valid N-of-a-kind or a valid run). Note that the
function may be used to validate a grouping of partial discards or the full set
of discards, i.e. the total number of cards in groups will be between 0 and 10.
Example function calls are as follows:
>>> comp10001go_valid_groups([['KC', 'KH', 'KS', 'KD'], ['2C']])
True
>>> comp10001go_valid_groups([['KC', 'KH', 'KS', 'AD'], ['2C']])
False
>>> comp10001go_valid_groups([['KC', 'KH', 'KS', 'KD'], ['2C', '3H']])
False
>>> comp10001go_valid_groups([])
True
--------------------------------------------------------------------------------
Part 3 - Play and Group!
The third question requires that you implement the two functions that are called
in the tournament: (1) comp10001_play, which is used to select a discard over
the 10 turns of a game; and (2) comp10001_group, which is used to group the
discards into groups for scoring. We combine these together into a single
question in Grok as a means of validating that you have a complete player that
is qualified to enter the tournament. Note that in each case, we provide only a
single test case (and no hidden test cases) for two reasons: (1) there are very
few game states where there is a single possible option to either play a discard
or group the discards, and testing relies on there only being one possible
output; and (2) the real testing occurs in simulation mode in the actual
tournament, in the form of random games against other players. On validation of
implementations of each of the two functions, you will be given the option to
submit your player to the tournament.
First, write a function comp10001go_play() which takes three arguments:
- discard_history, a list of lists of four cards, each representing the discards
from each of the four players in preceding turns (up to 9 turns) in sequence
of player number (i.e. the first element in each list of four cards is for
Player 0, the second is for Player 1, etc.). Note that the list is sequenced
based on the turns, i.e. the first list of four cards corresponds to the first
turn, and the last list of four cards corresponds to the last turn.
- player_no, an integer between 0 and 3 inclusive, indicating which player is
being asked to play. player_no can also be used to determine the discards for
that player from discard_history by indexing within each list of four cards.
- hand, a list of cards held by the player.
Your function should return a single card to discard from hand.
An example function call is as follows:
>>> comp10001go_play([['0S', 'KH', 'AC', '3C'], ['JH', 'AD', 'QS', '5H'],
['9C', '8S', 'QH', '9S'], ['8C', '9D', '0D', 'JS'],
['5C', 'AH', '5S', '4C'], ['8H', '2D', '6C', '2C'],
['8D', '4D', 'JD', 'AS'], ['0H', '6S', '2H', 'KC'],
['KS', 'KD', '7S', '6H']], 3, ['QC'])
'QC'
Second, write a function comp10001go_group() which takes two arguments:
- discard_history, a list of lists of four cards, each representing the discards
from each of the four players in preceding turns in sequence of player number
(i.e., the first element in each list of four cards is for Player 0, the
second is for Player 1, etc.). Note that the list is sequenced based on the
turns, i.e. the first list of four cards corresponds to the first turn, and
the last list of four cards corresponds to the last turn. Additionally note
that the number of turns contained in discard_history will always be 10.
- player_no, an integer between 0 and 3 inclusive, indicating which player is
being asked to play. player_no can also be used to determine the discards for
that player from discard_history by indexing within each list of four cards.
Your function should return a list of lists of cards based on the discard
history of player_no, to use in scoring the player. Note that the grouping of
cards represented by the output must be valid (i.e. each list of cards must be a
singleton card, or a valid N-of-a-kind or run), but that the ordering of cards
within groups, and the ordering of groups is not significant.
An example function call is as follows:
>>> comp10001go_group([['0S', 'KH', 'AC', '3C'], ['JH', 'AD', 'QS', '5H'],
['9C', '8S', 'QH', '9S'], ['8C', '9D', '0D', 'JS'],
['5C', 'AH', '5S', '4C'], ['8H', '2D', '6C', '2C'],
['8D', '4D', 'JD', 'AS'], ['0H', '6S', '2H', 'KC'],
['KS', 'KD', '7S', '6H'], ['JC', 'QD', '4H', 'QC']], 3)
[['3C'], ['5H'], ['9S'], ['JS'], ['4C'],
['2C'], ['AS'], ['KC'], ['6H'], ['QC']]
--------------------------------------------------------------------------------
Part 4 - Optimal grouping
The final question is for bonus marks, and is deliberately quite a bit harder
than the four basic questions (and the number of marks on offer is, as always,
deliberately not commensurate with the amount of effort required). Only attempt
this is you have completed the earlier questions, and are up for a challenge!
Write a function comp10001go_best_partitions() which takes a single argument:
- cards, a list of up to 10 cards
Your function should return a list of list of lists of cards, representing the
groupings of cards that score the most points from cards. Note that the ordering
of the groupings is not significant, and neither is the ordering of the groups
within a grouping, nor the order of cards within a group.
One area of particular focus with this question is efficiency: there are strict
time limits associated with running your code over each example, that you must
work within, or you will fail the test. Good luck!
Example function calls are as follows:
>>> comp10001go_best_partitions(['0H', '8S', '6H', 'AC', '0S',
'JS', '8C', '7C', '6D', 'QS'])
[[['AC'], ['0H', '0S'], ['JS'], ['8S', '8C'], ['7C'], ['6H', '6D'], ['QS']]]
>>> comp10001go_best_partitions(['9D', '2S', '4D', '4H', '6D',
'AH', '2C', 'JH', '3C', '9H'])
[[['4D', '4H'], ['6D'], ['AH'], ['2S', '2C'],
['JH'], ['3C'], ['9D', '9H']]]
>>> comp10001go_best_partitions(['3C', '5H', '9S', 'JS', '4C',
'2C', 'AS', 'KC', '6H', 'QC'])
[[['3C'], ['5H'], ['9S'], ['JS'], ['4C'], ['2C'], ['AS'], ['KC'], ['6H'], ['QC']]]
>>> comp10001go_best_partitions(['0D', 'AS', '5C', '8H',
'KS', 'AH', 'QH', 'AC'])
[[['AS', '5C', '8H', 'AH'], ['0D', 'KS', 'QH', 'AC']],
[['0D', 'AS', 'KS', 'QH'], ['5C', '8H', 'AH', 'AC']]]