Rummy is a simple card game for two or more players, played with a standard 52 card deck. Each player is dealt seven cards, and that aim is to swap your cards until you get a winning combination of seven cards before you opponent does.
The deck of cards is shuffled and each player is dealt seven cards. After dealing, the remaining cards are placed in a pile face down, and the one card on the top of this pile is turned over and placed next to the pile.
In turn, each player makes thier move. The first decision for the player is either to take the exposed face up card, or to take the top most card off the pile of face down cards.
The chosen card is added to the players hand. The player then has to choose a single card to return out of the eight the player is holding. The rejected card is returned to the face up pile, in view of the opposition. The next player in line may choose to pick that card.
Once that step of returning a card is complete, if the remaining seven cards form a winning hand, the game is over and that player has won. A winning hand is constructed as follows.
A hand needs to use all seven cards in a valid "set" or "run" of three or four cards. A set is three or four cards of the same face (or number value) but different suits.
A run is a sequence of three or four cards of the same suit, of continuous value. Aces may be high or low, but not both. (So a run of King/ Ace/ Two is not valid.)
If the last face-down card is taken, then before the player returns a card, the pile of face-up cards are turned over. No shuffling takes place.
If the game lasts so long that each player has had 150 rounds, a stalemate is declared and the game is drawn.
On the surface, Rummy appears as players competing against the deck of cards, with the player fastest at beating the deck of cards wins. However, there are ways to be more active through observation.
You do not know which cards your opponent has been dealt. Nor do you know what cards have been picked up from the face-down deck of cards.
Some of your opponents moves are visible. If you can make observations and conclude what you think your opponent is collecting, you may get the opportunity to keep a card your opponent needs, giving you the opportunity to find the cards you need.
However, you can observe the cards that your opponents pick up from the face-up pile. If you see that an opponent has picked up (say) the five of hearts, and then you see the same opponent take the five or diamonds. Perhaps that opponent is collecting fives. If you have an opportunity to keep another five, perhaps you should keep it for now, until you have a winning hand.
You can also observe the cards players reject. If you know an opponent has the (say) king of spades, and you see the same opponent pass up the opportunity to take the king of clubs, perhaps that opponent is collecting high value spades instead.
Additionally, you can observe the cards your opponent rejects. Say you had previously observed an opponent take a queen of diamonds, you don't yet know if this means collecting queens or high diamonds. Say that opponent later returns the queen of spades to the face-up pile, that probably means they are collecting high diamonds.
Finally, you can often conclude what cards are remaining by keeping note of what cards you have not yet seen. If the deck has turned, then you can know which cards are in the face-down pile in which order.
So what can a player do when they find themselves on the sharp end of a highly observant opponent? Keep 'em guessing.
If you have the choice of rejecting one of two cards. Would rejecting one over the other give some information away to your opponent? Perhaps your opponents know you have one of the two cards up for rejection, but do they know you are considering giving it away? Perhaps retain it as a red herring, or give it away if they already know you don't need it.
Since even declining to take a face-up card could potentially give information away. Consider if it is worth taking a face-up card you don't need as a red herring. It could be wasting a turn, so if you do consider this, use it sparingly.
Say you have the ace of hearts and the two of hearts. You also have the eight of diamonds and the eight of spades. What would it take to complete these into a set or run of three?
The only way to complete the run of low hearts is with the three of hearts. However, you can complete the set of eights with either the eight of hearts or the eight of clubs. If you have to give up one of these, perhaps the set of eights has a higher worth, as you have double the chances of completing it.
The same considerations can be made with observations. If you know, or can guess, that your opponents are holding the other two eights, then the run would have the higher value instead.
To take part in Tourk, you need to get the Tourk core installed and running.
To supply your own player, you need to write a new .c file, which includes just your code for playing the game.
The basis for a rummy player could look like this.
/* Standard C header file #includes. */ #define PLAYER_NAME name-of-player #include "rumplay.h" /* Extra player functions and global variables, declared as static. */ static void powerup(sernum_t sn) { /* Code for player startup. sn is the player serial number. */ } static void newgame(sernum_t sn, card_t *hand) { /* Code to initialise a new game. sn is the serial number and hand is a pointer to the first item of an array of seven card values, the hand you've been dealt. */ } static void shutdown(sernum_t sn) { /* The system is shuting down. Use this opportunity to free memory, etc. sn is the player serial number. */ } static int phase0(sernum_t you, round_t round, card_t *hand, card_t exposed) { /* Code for phase zero of a round. You may either choose the exposed card or pick the top most face down card. Return 1 for the face-down card or zero for the exposed card. It is a foul move to return any other value. you is the player serial number and round is the round number. */ } static card_t phase1(sernum_t you, round_t round, card_t *hand) { /* Code for phase one of a round. You have eight cards and you need to decide which card to return. The return value of this function is the card number you want to return. It is a foul move to try and return a card you do not have. */ } static void phase2(sernum_t you, round_t round, card_t *hand, sernum_t who, card_t exposed, int choice, card_t returned) { /* Code for phase two, the observation phase. Once any player has made a move, all players are informed using this function. you is your serial number. round is the round number. hand is your current hand of cards. who is the player we are observing. exposed is the card on offer to that player. choice is thier choice of phase zero. returned is the card returned to the face up pile at the end. */ }
Player code may make use of the standard C library, except that it may not make any use of the I/O system or the timers or clocks. Only the standard library provisioned by the ISO C standard, used within the limits of the standard, is permitted. POSIX, Win32, GNU, etc extensions are not allowed.
Player code using malloc() may assume that so long as the total memory allocated at one time does not exceed 512k, malloc() calls will succeed. It is a foul to ask for more than 512k. (This does not include the overhead required by heap managers.)
All allocated memory must be freed. It is a foul to leave any memory freed once the call to shutdown() has concluded.
A psuedo random number generator (PRNG) is supplied, pre-seeded. It is a Mersenne Twister PRNG, courtesy of Makoto Matsumoto and Takuji Nishimura. (Thanks.) Simply call rand() as normal. You do not need to include <stdlib.h>.
The following types are provided by the Tourk system.
card_t | A number to store a single card value. Supplied macros are;
These three macros return nonsense values when passed in out of range vales. A valid card_t value ranges from 0 to 51 inclusive, so it useful for array indexing. |
sernum_t | A player serial number. Each player is assigned a number as the game starts, and players are referenced by this number. |
round_t | Round number type. This value increases as the game goes on. |
Debug messages are controlled by the Tourk core. When you run a game, your code may generate debug. How much you want to keep is up to the operator at run time.
The function for generating a debug message is called debugmsg. The function behaves in a similar manner to printf.
Debug levels
4-9. Reserved for the player code, with levels 1, 2 and 3. |
The first parameter is the debug level. Higher values represent more debug. Levels 4-9 are for the player code. A debug message of level 6 will only be displayed when debug level 6, 7, 8 or 9 is selected at the command line.
The remaining parameters to debugmsg are the same as printf. A printf style format string followed by any extra values to be displayed.