Simple demo of the game of Set.

## Project description

“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.

This project uses Semantic Versioning for managing backwards-compatibility.

## The Game

### Core Concepts

• Each Card has 4 Properties: color, shape, shading, and number.

• The Deck is a collection of all of the Cards.

• The Board is a subset of the Deck, containing only the cards that are currently in-play.

• A Set is a collection of 3 cards which meet certain criteria (discussed below). When a Set is found in-play on the Board, the Set is removed from play and logged as such.

• The Game encapsulates all of these concepts and keeps track of them.

### 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.

### Assumptions

“Three cards are a part of a set if, for each property, the values are all the same or all different.”

This is phrased ambiguously, and the examples given lead me to believe that the following is a more specific description of the rules.

• Take 3 cards and look at each of their properties one-by-one.

• If all cards have a different value for that property OR all cards have the same value for that property, then it may be a set.

• If any properties of step 2 fail the test, then the group is not a set.

### Problem Parameters

• This problem uses mathematical combinations (as opposed to permutations). This results in 81 combinations (3^4).

• Any failure of being a Set means that the group is not a set, so fail as early as possible and move-on.

### Logic

(Whereas “Combination” refers to the mathematical concept.)

1. Create the deck of available cards by ensuring that every card is unique, and that all Combinations of properties are represented. Also, shuffle the deck by default.

2. Deal 12 cards to the Board.

3. Calculate all possible Combinations of the cards on the Board, in groups of 3.

4. Iterate over each Combination, applying logic to determine whether or not this Combination represents a Set.

5. Collect the Sets by removing the Cards which are determined to be part of a Set.

6. When no more Sets can be found, deal another 3 Cards from the Deck.

7. Repeat steps 3–6 until the Deck is empty.

## Requirements

• Python 2.7, 3.3+, Pypy

• Pip

• VirtualEnv is recommended, but not required

## Installation

# Install from Pypi
pip install skyzyx-set-game-demo

# Install from local code
pip install -e .

And either include it in your scripts:

from set_game_demo import SetGame

…or run it from the command line.

# Application help
set-game-demo -h

## Usage/Examples

From the Python REPL or a Python script…

from __future__ import print_function
from set_game_demo import SetGame

# Initialize the game.
game = SetGame()

# Chatty, interactive version of the game.
game.play()

# Quiet version of the game. Good for code.
discovered, sets = game.play_quiet()
print("Sets discovered: {}".format(discovered))
for set in sets:
game.display_cards(set)

From the Terminal…

# Chatty, interactive version of the game.
set-game-demo

# Quiet version of the game.
set-game-demo --quiet

## Known Issues

• In a final release, it would be wise to update the requirements.txt to allow for ranges of known-good versions instead of locking to one specific version.

• Conversely, if this is the sole project running in this virtual environment, locking to a specific known-good version ensures fewer version-compatibility issues.

## Future Improvements

• Update the test_deal unit test to verify that we do not attempt to deal a larger number of cards than the deck contains (couldn’t quite figure out the right way to call assertRaises() from the unittest package through the nose2 interface).

• Support multiple Players who can collect sets and compete for scores.

## Development

• You can develop in any supported version of Python.

• Using pyenv to manage your Pythons is highly-recommended. Testing locally depends on it.

• Install VirtualEnv for your development environment, and activate the environment.

pip install virtualenv
virtualenv .vendor
source .vendor/bin/activate
• Install the requirements.txt.

pip install -r requirements.txt
• When you make changes, make sure that you run the linter and fix anything that’s broken.

make lint

## Testing

We use tox to handle local testing across multiple versions of Python. We install multiple versions of Python at a time with pyenv.

Testing occurs against the following versions:

• Python 2.7

• Python 3.3

• Python 3.4

• Python 3.5

• Python 3.6

• Python 3.7

• Pypy

• Pypy3

To begin…

1. Install pyenv on your own before running tests.

2. You need to install all of the supported versions of Python. (This will take a while.) If you would prefer to install your own copies of the supported Python versions (listed above), feel free to manage them yourself.

pyenv install 3.7.1 && \
pyenv install 3.6.7 && \
pyenv install 3.5.6 && \
pyenv install 3.4.9 && \
pyenv install 3.3.7 && \
pyenv install 2.7.15 && \
pyenv install pypy-5.7.1 && \
pyenv install pypy3.5-6.0.0 && \
pyenv rehash && \
eval "$(pyenv init -)" && \ pyenv global system 2.7.15 3.3.7 3.4.9 3.5.6 3.6.7 3.7.1 pypy-5.7.1 pypy3.5-6.0.0 To verify that the installation and configuration were successful, you can run pyenv versions. You should see a * character in front of every version that we just installed. $ pyenv versions
* system (set by ~/.pyenv/version)
* 2.7.12 (set by ~/.pyenv/version)
* 3.3.6 (set by ~/.pyenv/version)
* 3.4.5 (set by ~/.pyenv/version)
* 3.5.2 (set by ~/.pyenv/version)
* 3.6.0b1 (set by ~/.pyenv/version)
* pypy-5.3.1 (set by ~/.pyenv/version)
* pypy3-2.4.0 (set by ~/.pyenv/version)
3. The following command will package-up your module and install it locally, then run nose2 to execute the tests in the default system Python.

make test
4. After you’ve run that, you can then execute the tests in all supported versions of Python with the following:

tox

## API Reference

### Building local docs

make docs
open docs/set_game_demo/index.html

### Building and pushing docs

make pushdocs

Docs can be viewed at https://skyzyx.github.io/set-game-demo/.

## Deploying

1. The Makefile (yes, Makefile) has a series of commands to simplify the development and deployment process.

2. Also install Chag. This is used for managing the CHANGELOG and annotating the Git release correctly.

### Updating the CHANGELOG

Make sure that the CHANGELOG.md is human-friendly. See http://keepachangelog.com if you don’t know how.

### make

Running make by itself will show you a list of available sub-commands.

\$ make
all
buildpip
clean
docs
lint
pushdocs
pushpip
tag
test
version

If you make changes to README.md, then this will use Pandoc to output a README.rst file in the reStructuredText format used by distutils, Sphinx and most of the Python community.

You must have Pandoc installed on your local system.

NOTE: Initial install via brew install pandoc takes about 8–10 hours. Updates are much faster. Using the installer is much faster for initial installation, but updates are entirely manual.

### make version

Sets the version number that will be used by other make tasks related to packaging and bundling.

### make tag

This will make sure that the CHANGELOG.md is properly datestamped, add the CHANGELOG contents to the Git commit message, commit them, then create a Git commit which can be pushed upstream.

### make pushpip

This will take your bundled package and upload it securely to Pypi using the twine package.

### Drafting a GitHub release

1. Find the new tag that you just pushed. Click the ellipsis () to see the commit notes. Copy these.

2. To the right, choose Add release notes. Your Tag version should be pre-filled.

3. The Release title should match your Tag version.

4. Inside Describe this release, paste the notes that you copied on the previous page.

5. Choose Publish release.

6. Your release should now be the latest. https://github.com/skyzyx/set-game-demo/releases/latest

## Contributing

Here’s the process for contributing:

1. Fork this project to your GitHub account.

2. Clone your GitHub copy of the repository into your local workspace.

3. Write code, fix bugs, and add tests with 100% code coverage.

5. You submit a GitHub pull request with a description of what the change is.

6. The contribution is reviewed. Maybe there will be some banter back-and-forth in the comments.

7. If all goes well, your pull request will be accepted and your changes are merged in.

## Project details

Uploaded source
Uploaded py2 py3