set_game_demo module
A simple demo of the game of "Set".
Copyright (c) 2016 Ryan Parman.
http://opensource.org/licenses/Apache2.0
#! /usr/bin/env python # -*- coding: utf-8 -*- """ A simple demo of the game of "Set". Copyright (c) 2016 [Ryan Parman](https://github.com/skyzyx). <http://opensource.org/licenses/Apache2.0> """ from __future__ import print_function import argparse import collections import itertools import random import six from prettytable import PrettyTable class SetGame(object): """ "Set" is a card game where a group of players try to identify a _Set_ of cards from those placed face-up on a table. **Game Rules:** Each _Card_ has an image on it with 4 orthogonal attributes: * Color (red, green, or purple) * Shape (diamond, squiggle, or oval) * Shading (solid, empty, or striped) * Number (one, two, or three) Three _Cards_ are a part of a _Set_ if, for each _Property_, the values are all the same or all different. For example: * The _Cards_ "two red solid squiggles", "one green solid diamond", "three purple solid ovals" would make up a _Set_. (number, shape, and color are different, shading is the same) * The _Cards_ "two red solid squiggles", "one green solid squiggles", "three purple solid ovals" would not make up a _Set_, because shape is the same on two _Cards_, but different on the third. * A _Game_ of "Set" starts by dealing 12 _Cards_, face-up. When a player sees three _Cards_ that make up a _Set_, they yell "Set!" and grab the _Cards_. New _Cards_ are dealt from the _Deck_ to replace them. * If no player can find a _Set_, three more _Cards_ are dealt (to make 15, then 18, then 21...) * The _Game_ is over when there are no _Cards_ left in the _Deck_, and no _Sets_ left on the table. The player with the most _Sets_ wins. **Game Requirements:** Your task is to model the _Game_ in code, and implement the following methods: * A method that takes three _Cards_, and determines whether the three _Cards_ make a _Set_. * A method that given a _Board_ of _Cards_, will either find a _Set_, or determine that there are no _Sets_ on the table. * A method that will play an entire _Game_ of "Set", from beginning to end, and return a list of each valid _Sets_ you removed from the _Board_. For this last method, there will be multiple correct solutions, but any valid list of _Sets_ is fine. **Compatibility:** Tested against the following Python versions: * Python 2.7 * Python 3.3 * Python 3.4 * Python 3.5 * Python 3.6 (beta) * Pypy (~2.7.10) * Pypy3 (~3.2.5) **Import:** from set_game_demo import SetGame """ def __init__(self): """ Constructs a new instance of this class. """ self.colors = ["red", "green", "purple"] self.shapes = ["diamond", "squiggle", "oval"] self.shadings = ["solid", "empty", "striped"] self.numbers = ["one", "two", "three"] deck = [] for color in self.colors: for shape in self.shapes: for shading in self.shadings: for number in self.numbers: card = {} card["color"] = color card["shape"] = shape card["shading"] = shading card["number"] = number deck.append(card) random.shuffle(deck) self.deck = collections.deque(deck) self.board = [] self.sets = [] def deal(self, cards=12): """ Deals a given number of cards from the top (front) of the deck. `cards (integer)`: The number of cards to deal out to the board. The default value is `12`. `return (cards[])`: A list (i.e., array) of objects representing cards. """ out = [] for _ in six.moves.range(cards): out.append(self.deck.popleft()) return out def play(self): # pragma: no cover """ Play a (chatty) game of Set. `return (void)` """ # pylint: disable=R0915 # Introduction print("Welcome to a game of Set.") print() six.moves.input("=> Press any key to continue...") # First deal print() print("Dealing 12 cards onto the board.") self.board = self.deal(12) SetGame.display_cards(self.board) print() print("Cards on the board: {}".format(len(self.board))) print("Cards in the deck: {}".format(len(self.deck))) print("Sets discovered: {}".format(len(self.sets))) six.moves.input("=> Press any key to continue...") while len(self.deck) > 0: # Find sets print() sets = self.find_sets(self.board) print("Discovered {quantity}.".format( quantity=SetGame.plural(len(sets), "set", "sets") )) for i, sset in enumerate(sets): print() print("Set #{index}".format(index=(i + 1))) SetGame.display_cards(sset) print() print("These are the remaining {quantity} on the board.".format( quantity=SetGame.plural(len(self.board), "card", "cards") )) SetGame.display_cards(self.board) print() self.sets += sets six.moves.input("=> Press any key to continue...") # Deal 3 more cards print() self.board += self.deal(3) print("Dealing 3 more cards. You now have {quantity} on the board.".format( quantity=SetGame.plural(len(self.board), "card", "cards") )) SetGame.display_cards(self.board) print() print("Cards on the board: {}".format(len(self.board))) print("Cards in the deck: {}".format(len(self.deck))) print("Sets discovered: {}".format(len(self.sets))) six.moves.input("=> Press any key to continue...") # Find the very last set(s) print() sets = self.find_sets(self.board) print("Discovered {quantity}.".format( quantity=SetGame.plural(len(sets), "set", "sets") )) for i, sset in enumerate(sets): print() print("Set #{index}".format(index=(i + 1))) SetGame.display_cards(sset) print() print("These are the remaining {quantity} on the board.".format( quantity=SetGame.plural(len(self.board), "card", "cards") )) SetGame.display_cards(self.board) print() self.sets += sets six.moves.input("=> Press any key to continue...") # No more cards in the deck. print() print("There are no more cards left in the deck.") print() print("These are the {} that are left on the table.".format( SetGame.plural(len(self.board), "card", "cards") )) SetGame.display_cards(self.board) print() six.moves.input("=> Congratulations! You have completed the game. Press any key to see the results.") # Final score. print() print("You discovered {quantity}.".format( quantity=SetGame.plural(len(self.sets), "set", "sets") )) for i, sset in enumerate(self.sets): print() print("Set #{index}".format(index=(i + 1))) SetGame.display_cards(sset) # All done. print() print("Please play again!") print() def play_quiet(self): """ Play a (quiet) game of Set. `return (tuple(integer, sets[]))`: Returns a tuple where the first item is the number of Sets discovered. The second item is the complete list of Sets. """ self.board = self.deal(12) # Find sets and re-deal until we are out of cards. while len(self.deck) > 0: self.sets += self.find_sets(self.board) self.board += self.deal(3) # Find the very last set(s). self.sets += self.find_sets(self.board) # Return a tuple return (len(self.sets), self.sets) @staticmethod def display_cards(cards): # pragma: no cover """ Accepts an array of cards, and renders them for humans in a table to `stdout`. `cards (cards[])`: A list (i.e., array) of objects representing cards. `return (void)` """ table = PrettyTable(["Number", "Color", "Shape", "Shading"]) for card in cards: table.add_row([card["number"], card["color"], card["shape"], card["shading"]]) print(table) @staticmethod def is_a_set(card1, card2, card3): """ Determines whether a group of 3 cards is a _set_ or not. `card1 (card)`: A card object to compare against other card objects. `card2 (card)`: A card object to compare against other card objects. `card3 (card)`: A card object to compare against other card objects. `return (boolean)`: Whether or not the given cards represent a _Set_. A value of `True` means that the group is a set. A value of `False` means that the group is _not_ a set. """ for attribute in ["color", "shape", "shading", "number"]: if (SetGame.__all_unique([ card1[attribute], card2[attribute], card3[attribute], ]) is False and SetGame.__all_same([ card1[attribute], card2[attribute], card3[attribute], ]) is False): return False # Did we actually make it all the way here? return True @staticmethod def find_sets(board): """ Given a _Board_ of cards, determines whether or not it contains a _Set_. `board (cards[])`: A list (i.e., array) of Cards that are on the Board. `return (sets[])`: A list (i.e., array) of Sets. Each Set contains 3 Cards. """ sets = [] # Calculate the initial set of combinations. combinations = itertools.combinations(six.moves.range(len(board)), 3) # Run until we explicitly break. while True: # Grab the combination. combination = next(combinations, None) # As long as we didn't get a `None` back... while combination is not None: # Check to see if the three cards we got back for this combination are a Set. if SetGame.is_a_set(board[combination[0]], board[combination[1]], board[combination[2]]) is True: # If so, save them. sets.append([board[combination[0]], board[combination[1]], board[combination[2]]]) # After we save the Set, remove the cards from the Board. # Python list indexes collapse automatically, so remove from the end first. del board[combination[2]] del board[combination[1]] del board[combination[0]] # This means that we now need to recalculate the Board, and start our loop over again. combinations = itertools.combinations(six.moves.range(len(board)), 3) break else: # Move on to the next combination in the list. combination = next(combinations, None) continue # If we have reached the end of the list of combinations, quit. if combination is None: break # Return all matching sets. return sets @staticmethod def __all_unique(arr): """ Determines whether or not a `List` of values are all unique. `arr (scalar[])`: A list (i.e., array) of scalar values to compare. `return (boolean)`: Whether or not a `List` of values are all different. A value of `True` means that the values are all unique. A value of `False` means that the values are not all unique. """ return len(set(arr)) == len(arr) @staticmethod def __all_same(arr): """ Determines whether or not a `List` of values are all identical. `arr (scalar[])`: A list (i.e., array) of scalar values to compare. `return (boolean)`: Whether or not a `List` of values are all identical. A value of `True` means that the values are all identical. A value of `False` means that the values are not all identical. """ return len(set(arr)) == 1 @staticmethod def plural(count, singular, plural): """ Determines whether a response should be singular or plural, depending on the number of items being referenced. `count (integer)`: The number of items to adjust language for. `singular (string)`: The singular version of the phrasing. `plural (string)`: The plural version of the phrasing. `return (string)`: A properly-formatted string. """ return "{count} {word}".format( count=count, word=singular ) if count == 1 else "{count} {word}".format( count=count, word=plural ) # ------------------------------------------------------------------------------ def main(): # pragma: no cover """ This function is run when the script is executed from the command-line. """ # Available CLI flags. parser = argparse.ArgumentParser( description="Play a game of Set.", ) parser.add_argument( "-q", "--quiet", dest="quiet", action="store_true", help="By default, the game will play in chatty, interactive mode. " "This will enable a quieter, results-only mode.") parser.set_defaults(quiet=False) flags = parser.parse_args() game = SetGame() if flags.quiet: discovered, sets = game.play_quiet() print("You discovered {quantity}.".format( quantity=SetGame.plural(discovered, "set", "sets") )) for i, sset in enumerate(sets): print() print("Set #{index}".format(index=(i + 1))) SetGame.display_cards(sset) else: game.play() if __name__ == "__main__": # pragma: no cover main()
Functions
def main(
)
This function is run when the script is executed from the command-line.
def main(): # pragma: no cover """ This function is run when the script is executed from the command-line. """ # Available CLI flags. parser = argparse.ArgumentParser( description="Play a game of Set.", ) parser.add_argument( "-q", "--quiet", dest="quiet", action="store_true", help="By default, the game will play in chatty, interactive mode. " "This will enable a quieter, results-only mode.") parser.set_defaults(quiet=False) flags = parser.parse_args() game = SetGame() if flags.quiet: discovered, sets = game.play_quiet() print("You discovered {quantity}.".format( quantity=SetGame.plural(discovered, "set", "sets") )) for i, sset in enumerate(sets): print() print("Set #{index}".format(index=(i + 1))) SetGame.display_cards(sset) else: game.play()
Classes
class SetGame
"Set" is a card game where a group of players try to identify a Set of cards from those placed face-up on a table.
Game Rules:
Each Card has an image on it with 4 orthogonal attributes:
- Color (red, green, or purple)
- Shape (diamond, squiggle, or oval)
- Shading (solid, empty, or striped)
- Number (one, two, or three)
Three Cards are a part of a Set if, for each Property, the values are all the same or all different.
For example:
- The Cards "two red solid squiggles", "one green solid diamond", "three purple solid ovals" would make up a Set. (number, shape, and color are different, shading is the same)
- The Cards "two red solid squiggles", "one green solid squiggles", "three purple solid ovals" would not make up a Set, because shape is the same on two Cards, but different on the third.
- A Game of "Set" starts by dealing 12 Cards, face-up. When a player sees three Cards that make up a Set, they yell "Set!" and grab the Cards. New Cards are dealt from the Deck to replace them.
- If no player can find a Set, three more Cards are dealt (to make 15, then 18, then 21...)
- The Game is over when there are no Cards left in the Deck, and no Sets left on the table. The player with the most Sets wins.
Game Requirements:
Your task is to model the Game in code, and implement the following methods:
- A method that takes three Cards, and determines whether the three Cards make a Set.
- A method that given a Board of Cards, will either find a Set, or determine that there are no Sets on the table.
- A method that will play an entire Game of "Set", from beginning to end, and return a list of each valid Sets you removed from the Board.
For this last method, there will be multiple correct solutions, but any valid list of Sets is fine.
Compatibility:
Tested against the following Python versions:
- Python 2.7
- Python 3.3
- Python 3.4
- Python 3.5
- Python 3.6 (beta)
- Pypy (~2.7.10)
- Pypy3 (~3.2.5)
Import:
from set_game_demo import SetGame
class SetGame(object): """ "Set" is a card game where a group of players try to identify a _Set_ of cards from those placed face-up on a table. **Game Rules:** Each _Card_ has an image on it with 4 orthogonal attributes: * Color (red, green, or purple) * Shape (diamond, squiggle, or oval) * Shading (solid, empty, or striped) * Number (one, two, or three) Three _Cards_ are a part of a _Set_ if, for each _Property_, the values are all the same or all different. For example: * The _Cards_ "two red solid squiggles", "one green solid diamond", "three purple solid ovals" would make up a _Set_. (number, shape, and color are different, shading is the same) * The _Cards_ "two red solid squiggles", "one green solid squiggles", "three purple solid ovals" would not make up a _Set_, because shape is the same on two _Cards_, but different on the third. * A _Game_ of "Set" starts by dealing 12 _Cards_, face-up. When a player sees three _Cards_ that make up a _Set_, they yell "Set!" and grab the _Cards_. New _Cards_ are dealt from the _Deck_ to replace them. * If no player can find a _Set_, three more _Cards_ are dealt (to make 15, then 18, then 21...) * The _Game_ is over when there are no _Cards_ left in the _Deck_, and no _Sets_ left on the table. The player with the most _Sets_ wins. **Game Requirements:** Your task is to model the _Game_ in code, and implement the following methods: * A method that takes three _Cards_, and determines whether the three _Cards_ make a _Set_. * A method that given a _Board_ of _Cards_, will either find a _Set_, or determine that there are no _Sets_ on the table. * A method that will play an entire _Game_ of "Set", from beginning to end, and return a list of each valid _Sets_ you removed from the _Board_. For this last method, there will be multiple correct solutions, but any valid list of _Sets_ is fine. **Compatibility:** Tested against the following Python versions: * Python 2.7 * Python 3.3 * Python 3.4 * Python 3.5 * Python 3.6 (beta) * Pypy (~2.7.10) * Pypy3 (~3.2.5) **Import:** from set_game_demo import SetGame """ def __init__(self): """ Constructs a new instance of this class. """ self.colors = ["red", "green", "purple"] self.shapes = ["diamond", "squiggle", "oval"] self.shadings = ["solid", "empty", "striped"] self.numbers = ["one", "two", "three"] deck = [] for color in self.colors: for shape in self.shapes: for shading in self.shadings: for number in self.numbers: card = {} card["color"] = color card["shape"] = shape card["shading"] = shading card["number"] = number deck.append(card) random.shuffle(deck) self.deck = collections.deque(deck) self.board = [] self.sets = [] def deal(self, cards=12): """ Deals a given number of cards from the top (front) of the deck. `cards (integer)`: The number of cards to deal out to the board. The default value is `12`. `return (cards[])`: A list (i.e., array) of objects representing cards. """ out = [] for _ in six.moves.range(cards): out.append(self.deck.popleft()) return out def play(self): # pragma: no cover """ Play a (chatty) game of Set. `return (void)` """ # pylint: disable=R0915 # Introduction print("Welcome to a game of Set.") print() six.moves.input("=> Press any key to continue...") # First deal print() print("Dealing 12 cards onto the board.") self.board = self.deal(12) SetGame.display_cards(self.board) print() print("Cards on the board: {}".format(len(self.board))) print("Cards in the deck: {}".format(len(self.deck))) print("Sets discovered: {}".format(len(self.sets))) six.moves.input("=> Press any key to continue...") while len(self.deck) > 0: # Find sets print() sets = self.find_sets(self.board) print("Discovered {quantity}.".format( quantity=SetGame.plural(len(sets), "set", "sets") )) for i, sset in enumerate(sets): print() print("Set #{index}".format(index=(i + 1))) SetGame.display_cards(sset) print() print("These are the remaining {quantity} on the board.".format( quantity=SetGame.plural(len(self.board), "card", "cards") )) SetGame.display_cards(self.board) print() self.sets += sets six.moves.input("=> Press any key to continue...") # Deal 3 more cards print() self.board += self.deal(3) print("Dealing 3 more cards. You now have {quantity} on the board.".format( quantity=SetGame.plural(len(self.board), "card", "cards") )) SetGame.display_cards(self.board) print() print("Cards on the board: {}".format(len(self.board))) print("Cards in the deck: {}".format(len(self.deck))) print("Sets discovered: {}".format(len(self.sets))) six.moves.input("=> Press any key to continue...") # Find the very last set(s) print() sets = self.find_sets(self.board) print("Discovered {quantity}.".format( quantity=SetGame.plural(len(sets), "set", "sets") )) for i, sset in enumerate(sets): print() print("Set #{index}".format(index=(i + 1))) SetGame.display_cards(sset) print() print("These are the remaining {quantity} on the board.".format( quantity=SetGame.plural(len(self.board), "card", "cards") )) SetGame.display_cards(self.board) print() self.sets += sets six.moves.input("=> Press any key to continue...") # No more cards in the deck. print() print("There are no more cards left in the deck.") print() print("These are the {} that are left on the table.".format( SetGame.plural(len(self.board), "card", "cards") )) SetGame.display_cards(self.board) print() six.moves.input("=> Congratulations! You have completed the game. Press any key to see the results.") # Final score. print() print("You discovered {quantity}.".format( quantity=SetGame.plural(len(self.sets), "set", "sets") )) for i, sset in enumerate(self.sets): print() print("Set #{index}".format(index=(i + 1))) SetGame.display_cards(sset) # All done. print() print("Please play again!") print() def play_quiet(self): """ Play a (quiet) game of Set. `return (tuple(integer, sets[]))`: Returns a tuple where the first item is the number of Sets discovered. The second item is the complete list of Sets. """ self.board = self.deal(12) # Find sets and re-deal until we are out of cards. while len(self.deck) > 0: self.sets += self.find_sets(self.board) self.board += self.deal(3) # Find the very last set(s). self.sets += self.find_sets(self.board) # Return a tuple return (len(self.sets), self.sets) @staticmethod def display_cards(cards): # pragma: no cover """ Accepts an array of cards, and renders them for humans in a table to `stdout`. `cards (cards[])`: A list (i.e., array) of objects representing cards. `return (void)` """ table = PrettyTable(["Number", "Color", "Shape", "Shading"]) for card in cards: table.add_row([card["number"], card["color"], card["shape"], card["shading"]]) print(table) @staticmethod def is_a_set(card1, card2, card3): """ Determines whether a group of 3 cards is a _set_ or not. `card1 (card)`: A card object to compare against other card objects. `card2 (card)`: A card object to compare against other card objects. `card3 (card)`: A card object to compare against other card objects. `return (boolean)`: Whether or not the given cards represent a _Set_. A value of `True` means that the group is a set. A value of `False` means that the group is _not_ a set. """ for attribute in ["color", "shape", "shading", "number"]: if (SetGame.__all_unique([ card1[attribute], card2[attribute], card3[attribute], ]) is False and SetGame.__all_same([ card1[attribute], card2[attribute], card3[attribute], ]) is False): return False # Did we actually make it all the way here? return True @staticmethod def find_sets(board): """ Given a _Board_ of cards, determines whether or not it contains a _Set_. `board (cards[])`: A list (i.e., array) of Cards that are on the Board. `return (sets[])`: A list (i.e., array) of Sets. Each Set contains 3 Cards. """ sets = [] # Calculate the initial set of combinations. combinations = itertools.combinations(six.moves.range(len(board)), 3) # Run until we explicitly break. while True: # Grab the combination. combination = next(combinations, None) # As long as we didn't get a `None` back... while combination is not None: # Check to see if the three cards we got back for this combination are a Set. if SetGame.is_a_set(board[combination[0]], board[combination[1]], board[combination[2]]) is True: # If so, save them. sets.append([board[combination[0]], board[combination[1]], board[combination[2]]]) # After we save the Set, remove the cards from the Board. # Python list indexes collapse automatically, so remove from the end first. del board[combination[2]] del board[combination[1]] del board[combination[0]] # This means that we now need to recalculate the Board, and start our loop over again. combinations = itertools.combinations(six.moves.range(len(board)), 3) break else: # Move on to the next combination in the list. combination = next(combinations, None) continue # If we have reached the end of the list of combinations, quit. if combination is None: break # Return all matching sets. return sets @staticmethod def __all_unique(arr): """ Determines whether or not a `List` of values are all unique. `arr (scalar[])`: A list (i.e., array) of scalar values to compare. `return (boolean)`: Whether or not a `List` of values are all different. A value of `True` means that the values are all unique. A value of `False` means that the values are not all unique. """ return len(set(arr)) == len(arr) @staticmethod def __all_same(arr): """ Determines whether or not a `List` of values are all identical. `arr (scalar[])`: A list (i.e., array) of scalar values to compare. `return (boolean)`: Whether or not a `List` of values are all identical. A value of `True` means that the values are all identical. A value of `False` means that the values are not all identical. """ return len(set(arr)) == 1 @staticmethod def plural(count, singular, plural): """ Determines whether a response should be singular or plural, depending on the number of items being referenced. `count (integer)`: The number of items to adjust language for. `singular (string)`: The singular version of the phrasing. `plural (string)`: The plural version of the phrasing. `return (string)`: A properly-formatted string. """ return "{count} {word}".format( count=count, word=singular ) if count == 1 else "{count} {word}".format( count=count, word=plural )
Ancestors (in MRO)
Static methods
def display_cards(
cards)
Accepts an array of cards, and renders them for humans in a table to stdout
.
cards (cards[])
: A list (i.e., array) of objects representing cards.
return (void)
@staticmethod def display_cards(cards): # pragma: no cover """ Accepts an array of cards, and renders them for humans in a table to `stdout`. `cards (cards[])`: A list (i.e., array) of objects representing cards. `return (void)` """ table = PrettyTable(["Number", "Color", "Shape", "Shading"]) for card in cards: table.add_row([card["number"], card["color"], card["shape"], card["shading"]]) print(table)
def find_sets(
board)
Given a Board of cards, determines whether or not it contains a Set.
board (cards[])
: A list (i.e., array) of Cards that are on the Board.
return (sets[])
: A list (i.e., array) of Sets. Each Set contains 3 Cards.
@staticmethod def find_sets(board): """ Given a _Board_ of cards, determines whether or not it contains a _Set_. `board (cards[])`: A list (i.e., array) of Cards that are on the Board. `return (sets[])`: A list (i.e., array) of Sets. Each Set contains 3 Cards. """ sets = [] # Calculate the initial set of combinations. combinations = itertools.combinations(six.moves.range(len(board)), 3) # Run until we explicitly break. while True: # Grab the combination. combination = next(combinations, None) # As long as we didn't get a `None` back... while combination is not None: # Check to see if the three cards we got back for this combination are a Set. if SetGame.is_a_set(board[combination[0]], board[combination[1]], board[combination[2]]) is True: # If so, save them. sets.append([board[combination[0]], board[combination[1]], board[combination[2]]]) # After we save the Set, remove the cards from the Board. # Python list indexes collapse automatically, so remove from the end first. del board[combination[2]] del board[combination[1]] del board[combination[0]] # This means that we now need to recalculate the Board, and start our loop over again. combinations = itertools.combinations(six.moves.range(len(board)), 3) break else: # Move on to the next combination in the list. combination = next(combinations, None) continue # If we have reached the end of the list of combinations, quit. if combination is None: break # Return all matching sets. return sets
def is_a_set(
card1, card2, card3)
Determines whether a group of 3 cards is a set or not.
card1 (card)
: A card object to compare against other card objects.
card2 (card)
: A card object to compare against other card objects.
card3 (card)
: A card object to compare against other card objects.
return (boolean)
: Whether or not the given cards represent a Set. A value of True
means that the group is
a set. A value of False
means that the group is not a set.
@staticmethod def is_a_set(card1, card2, card3): """ Determines whether a group of 3 cards is a _set_ or not. `card1 (card)`: A card object to compare against other card objects. `card2 (card)`: A card object to compare against other card objects. `card3 (card)`: A card object to compare against other card objects. `return (boolean)`: Whether or not the given cards represent a _Set_. A value of `True` means that the group is a set. A value of `False` means that the group is _not_ a set. """ for attribute in ["color", "shape", "shading", "number"]: if (SetGame.__all_unique([ card1[attribute], card2[attribute], card3[attribute], ]) is False and SetGame.__all_same([ card1[attribute], card2[attribute], card3[attribute], ]) is False): return False # Did we actually make it all the way here? return True
def plural(
count, singular, plural)
Determines whether a response should be singular or plural, depending on the number of items being referenced.
count (integer)
: The number of items to adjust language for.
singular (string)
: The singular version of the phrasing.
plural (string)
: The plural version of the phrasing.
return (string)
: A properly-formatted string.
@staticmethod def plural(count, singular, plural): """ Determines whether a response should be singular or plural, depending on the number of items being referenced. `count (integer)`: The number of items to adjust language for. `singular (string)`: The singular version of the phrasing. `plural (string)`: The plural version of the phrasing. `return (string)`: A properly-formatted string. """ return "{count} {word}".format( count=count, word=singular ) if count == 1 else "{count} {word}".format( count=count, word=plural )
Instance variables
var board
var colors
var deck
var numbers
var sets
var shadings
var shapes
Methods
def __init__(
self)
Constructs a new instance of this class.
def __init__(self): """ Constructs a new instance of this class. """ self.colors = ["red", "green", "purple"] self.shapes = ["diamond", "squiggle", "oval"] self.shadings = ["solid", "empty", "striped"] self.numbers = ["one", "two", "three"] deck = [] for color in self.colors: for shape in self.shapes: for shading in self.shadings: for number in self.numbers: card = {} card["color"] = color card["shape"] = shape card["shading"] = shading card["number"] = number deck.append(card) random.shuffle(deck) self.deck = collections.deque(deck) self.board = [] self.sets = []
def deal(
self, cards=12)
Deals a given number of cards from the top (front) of the deck.
cards (integer)
: The number of cards to deal out to the board. The default value is 12
.
return (cards[])
: A list (i.e., array) of objects representing cards.
def deal(self, cards=12): """ Deals a given number of cards from the top (front) of the deck. `cards (integer)`: The number of cards to deal out to the board. The default value is `12`. `return (cards[])`: A list (i.e., array) of objects representing cards. """ out = [] for _ in six.moves.range(cards): out.append(self.deck.popleft()) return out
def play(
self)
Play a (chatty) game of Set.
return (void)
def play(self): # pragma: no cover """ Play a (chatty) game of Set. `return (void)` """ # pylint: disable=R0915 # Introduction print("Welcome to a game of Set.") print() six.moves.input("=> Press any key to continue...") # First deal print() print("Dealing 12 cards onto the board.") self.board = self.deal(12) SetGame.display_cards(self.board) print() print("Cards on the board: {}".format(len(self.board))) print("Cards in the deck: {}".format(len(self.deck))) print("Sets discovered: {}".format(len(self.sets))) six.moves.input("=> Press any key to continue...") while len(self.deck) > 0: # Find sets print() sets = self.find_sets(self.board) print("Discovered {quantity}.".format( quantity=SetGame.plural(len(sets), "set", "sets") )) for i, sset in enumerate(sets): print() print("Set #{index}".format(index=(i + 1))) SetGame.display_cards(sset) print() print("These are the remaining {quantity} on the board.".format( quantity=SetGame.plural(len(self.board), "card", "cards") )) SetGame.display_cards(self.board) print() self.sets += sets six.moves.input("=> Press any key to continue...") # Deal 3 more cards print() self.board += self.deal(3) print("Dealing 3 more cards. You now have {quantity} on the board.".format( quantity=SetGame.plural(len(self.board), "card", "cards") )) SetGame.display_cards(self.board) print() print("Cards on the board: {}".format(len(self.board))) print("Cards in the deck: {}".format(len(self.deck))) print("Sets discovered: {}".format(len(self.sets))) six.moves.input("=> Press any key to continue...") # Find the very last set(s) print() sets = self.find_sets(self.board) print("Discovered {quantity}.".format( quantity=SetGame.plural(len(sets), "set", "sets") )) for i, sset in enumerate(sets): print() print("Set #{index}".format(index=(i + 1))) SetGame.display_cards(sset) print() print("These are the remaining {quantity} on the board.".format( quantity=SetGame.plural(len(self.board), "card", "cards") )) SetGame.display_cards(self.board) print() self.sets += sets six.moves.input("=> Press any key to continue...") # No more cards in the deck. print() print("There are no more cards left in the deck.") print() print("These are the {} that are left on the table.".format( SetGame.plural(len(self.board), "card", "cards") )) SetGame.display_cards(self.board) print() six.moves.input("=> Congratulations! You have completed the game. Press any key to see the results.") # Final score. print() print("You discovered {quantity}.".format( quantity=SetGame.plural(len(self.sets), "set", "sets") )) for i, sset in enumerate(self.sets): print() print("Set #{index}".format(index=(i + 1))) SetGame.display_cards(sset) # All done. print() print("Please play again!") print()
def play_quiet(
self)
Play a (quiet) game of Set.
return (tuple(integer, sets[]))
: Returns a tuple where the first item is the number of Sets discovered. The
second item is the complete list of Sets.
def play_quiet(self): """ Play a (quiet) game of Set. `return (tuple(integer, sets[]))`: Returns a tuple where the first item is the number of Sets discovered. The second item is the complete list of Sets. """ self.board = self.deal(12) # Find sets and re-deal until we are out of cards. while len(self.deck) > 0: self.sets += self.find_sets(self.board) self.board += self.deal(3) # Find the very last set(s). self.sets += self.find_sets(self.board) # Return a tuple return (len(self.sets), self.sets)