Gin-Rummy-OCaml is a terminal game version of the classic card game Gin Rummy. Developed in OCaml, it supports multiplayer gameplay for up to 5 players. This project was created as a final project and collaboration for the Cornell CS 3110 course on Functional Programming.
There are two methods to install Gin-Rummy-OCaml: using the installation script or manually installing dependencies.
For Debian-based systems with APT, you can use the provided script:
git clone https://github.com/hgreenstein/Gin-Rummy-OCaml.git
cd Gin-Rummy-OCaml
chmod +x install.sh
./install.sh
Alternatively, you can manually install the necessary dependencies. Replace the apt
command with your preferred package manager or read the OCaml documentation for even more installation methods for opam on all systems:
sudo apt install opam
opam init
eval $(opam env)
opam install ounit2 -y
opam install ocamlfind
opam install ocamlbuild
opam install ANSITerminal
eval $(opam env)
make build
make game
Running the make game
command in the git repo after building at any time will start a new game
If you want to easily be able to play gin from any directory, you can add an alias to your .bashrc
similar to this:
alias playgin='cd /path/to/Gin-Rummy-OCaml && make game'
new game <PlayerNames>
: Starts a new game with the given player names. Accepts between 2 to 5 player names. This is the initial command to begin gameplay.
- The game includes mechanisms to shuffle the deck and initialize the game state, ensuring a fair and randomized start for each new game.
take from discard
: The current player takes the top card from the discard pile. This command is only valid if the discard pile is not empty.take from deck
: The current player draws the top card from the deck.pass
: The current player ends their turn without making any other action. This command moves the game to the next player.gin
: Player declares "Gin" if they believe they have a winning hand, the game will automatically check if they are correct. If the declaration is incorrect, the turn continues.
drop <Card>
: After drawing a card, the player uses this command to discard a card from their hand. The card to be discarded is specified in the format<Rank> of <Suit>
, e.g.,drop Ace of Spades
.
quit
: Exits the game at any point.
- After a game concludes (either by a draw, a player winning by declaring Gin, or the deck running low), players are prompted to either start a new game with specified player names or quit the game.
- Invalid inputs during the game will prompt the player to enter a valid command, ensuring the smooth continuation of the game.
Each card in the Gin-Rummy-OCaml deck is uniquely represented by a prime number. This representation is integral to the game's winning check mechanism.
- Clubs 1 (Ace of Clubs): 2
- Spades 1 (Ace of Spades): 3
- Hearts 1 (Ace of Hearts): 5
- Diamonds 1 (Ace of Diamonds): 7
- ...
Melds in Gin Rummy are combinations of cards that form valid sets or runs. In our game, these melds are defined as the product of the prime numbers representing each card in the meld. For example:
- Meld of Ace of Clubs, Spades, Hearts, Diamonds: 2 * 3 * 5 * 7
- Other melds follow a similar pattern, represented by the product of prime numbers.
To declare a gin, a player's hand must consist of two melds. The game checks for this using two key functions:
prime_product
Function: Calculates the product of the prime numbers representing each card in the player's hand.check_melds
Function: Verifies if the hand's prime product can be evenly divided by the prime products of valid melds. To declare a gin, the division must be exact (i.e., the quotient is 1) for two separate melds.check_win
Function: Determines if the hand is a winning hand by using the above calculations. The hand is a winning hand if it matches the prime products of two melds in the melds list.
Consider a hand with the following cards:
- Ace of Clubs, Spades, Hearts, Diamonds (2 * 3 * 5 * 7 = 210)
- 2 of Clubs, Spades, Hearts, Diamonds (11 * 13 * 17 * 19 = 46189)
If the hand's prime product matches these two melds' prime products, the hand is considered a winning hand, enabling the player to declare a gin.
The testing file, test.ml
, is essential for ensuring the proper functioning of individual functions in the larger game. Due to the randomized nature of deck shuffling, many functions are more effectively tested manually using the utop
interface rather than through automated tests. The development process employs test-driven development, with test cases often written independently from the function implementation.
test_draw_card
: Tests the functionality of drawing a card from the deck.test_get_suit
/test_get_rank
/test_get_prime
: Verify card properties like suit, rank, and prime value.test_to_string
: Ensures correct string representation of cards.test_check_win
: Checks if a hand is a winning hand.test_is_in
/test_remove
/test_add_card
: Tests for card presence, removal, and addition in a deck.test_to_card
: Converts string representations to card objects.test_deck_to_string
/test_display_hand
: Tests for converting decks to string format and displaying hands.test_draw_from_deck
: Evaluates drawing a card from the deck in a game state.test_get_num_players
/test_get_name
/test_get_hand
/test_get_deck
: Tests various game state and player properties.
Run the suite using OUnit2
framework and the make test
command to execute all tests and validate game functionality.
Note: For a complete list of tests and their descriptions, refer to the test.ml file in the project's root directory.
make
(default): Builds the project.make build
: Compiles the project.make test
: Runs the suite of unit tests with debug tags.make check
: Performs environment and type checks.make finalcheck
: Executes a comprehensive check script.make clean
: Cleans up build files.make game
: Compiles and runs the game.make docs
: Generates both public and private documentation.
- Use
make game
for normal gameplay after initially building. - Additional utility commands like
zip
for archiving project files are also available.