Friday, July 22, 2016

Network Euchre Server and Client

I've been working on a network euchre server and client. The server implements a normal set of euchre rules, and can support one game with 4 players at a time. The client emulates 4 players, which interact with the server in order to play a game.

Server: euchred
The server is written in C, and is based on a version I wrote in 1999, with parts reworked as I wrote the client package. The server code is hosted on GitHub, and can be cloned with this command:
git clone git@github.com:Thump/euchred
Client: peuchre
The client package is written in Python, and can emulate up to 4 players. (It can also do fewer, so a manual client could be used with peuchre in order to allow a human player to play against peuchre's emulated players.) The peuchre code can be cloned with this command:
git clone git@github.com:Thump/peuchre
Building It
The euchred package can be built with these commands from inside the cloned source directory:
make
The binary can be found in src/euchred

The peuchre package doesn't need to be built, it's just an executable script in the root of the peuchre source directory, ./peuchre.

Running It
The server can be run from the euchred source directory with:
./src/euchred
It will open a listen socket on port 1234, and wait for clients to connect

The client can be run from the peuchre source directory with:
./peuchred
Player Logic
By default, peuchre will instantiate 4 player objects based on the Player object in the randomplayer.py file. This implements a player with the following behaviour:

  • always orders, never goes alone
  • never defends alone
  • when ordered up, it will drop a random card from its hand in place of the card being ordered
  • when offered to lead, it will lead a random card
  • when offered to follow, it will follow with a random legal card

It's clearly not a very smart algorithm, but it has the benefit of being easy to code, and can hopefully produce some interesting results.

New Player Logic
The mechanics of the client-server interaction for each player is in the EuchrePlayer object, in the euchreplayer.py file. New player logic can be created by sub-classing this object, as the Player object in the randomplayer.py file does. A new player class must meet these requirements:

  • regardless of the name of the file, the object inside the file must be called Player
  • the object must implement the following methods:
# returns one of ORDER, ORDERALONE, or PASS
def decideOrderPass(self):

# returns a card from self.hand to drop when ordered up
def decideDrop(self):

# returns either DEFEND or DEFENDPASS
def decideDefend(self):

# returns a card from self.hand to lead play
def decidePlayLead(self):

# returns a card from self.hand to follow play
def decidePlayFollow(self):
In this way, more intelligent players can be developed using peuchre. A new player logic file called foo.py can be passed to peuchre via the --team1 or --team2 command line switch:
./peuchre --team1 foo
Note that you need to remove the .py extension from the filename when passing it to the --team1 or --team2 switches.

Stats
With no options, the peuchre client will create 4 player objects, run a game, then delete the players, re-create them, run another game, etc. Unless limited by the --numgames option, it will continue looping and running games.

The normal output from the peuchre client is a stream of log messages showing the interaction with the euchred server:

root@thistle 368> ./peuchre
2016-07-22 18:42:45 :: This is peuchre
2016-07-22 18:42:45 :: p0t1 g0h0t0 : join successful
2016-07-22 18:42:45 :: p1t2 g0h0t0 : join successful
2016-07-22 18:42:45 :: p2t1 g0h0t0 : join successful
2016-07-22 18:42:45 :: p3t2 g0h0t0 : join successful
2016-07-22 18:42:45 ::
2016-07-22 18:42:45 :: game: everyone is joined, sending start 0
2016-07-22 18:42:45 ::
2016-07-22 18:42:45 :: p2t1 g0h0t0 : cards: Jc Tc 9c Th Js
2016-07-22 18:42:45 :: p2t1 g0h0t0 : I will order Qh to p1t2
2016-07-22 18:42:45 ::
2016-07-22 18:42:45 :: p1t2 g0h0t0 : cards: Ac Qc Qd Td Ah
2016-07-22 18:42:45 :: p1t2 g0h0t0 : gonna drop: Ac

The peuchre client collects stats from various parts of the game as it runs. These stats include:

  • games/s
  • hands/s
  • % of possible hands seen
  • % of hands ending euchre
  • % of hand playable at each trick

When run with the --stats option, the peuchre client will not show the stream of log messages, and will instead show a live view of these stats:

Peuchre Stats ( 0d 00:02:08 ) Team 1: randomplayer Team 2: randomplayer

Games:
Total: 48
Games/s: 0.37

Hands:
Total: 493 Euchres: 297
Hands/s: 3.83 %euchres: 60.24
Hands/g: 10.27

Call Hands:
Total: 493 Max Reps: 2
Unique: 488 Avg Reps: 1.01
%cover: 2.18

License

Both euchred and peuchre are licensed under GPL version 2.

How Many Hands of Euchre Can Be Played

Euchre is a 4 player team-based trump card game. Each of the 4 players begins a hand with 5 cards chosen from a deck of 24, a trump suit is selected by one of the players, and then play begins. A hand is played as a series of tricks: each player plays one card per trick, and thus there are 5 tricks per hand. To play a trick, a card is led by a selected player, and then the other players must follow with a card of the same suit if they have one, or they can otherwise play any card in their hand. Each card is ranked by its value and suit, and the player who played the strongest card wins the trick and leads for the next trick. At the end of the hand, if the team that called trump has won all 5 tricks they score 2 points, if they've won 3 or 4 tricks they score 1 point, and if they've won fewer than 3 tricks, the opposing team scores 2 points. The first team to a total of 10 points over successive hands wins the game.

How many possible euchre hands can be dealt?

If we deal 5 card hands to each of 4 players, the number of possible dealt hands is:

(24 choose 5)(19 choose 5)(14 choose 5)(9 choose 5)

which is 1.25e14, or roughly 125 trillion unique euchre hands dealt.

How many ways can a euchre hand be played?

Once the hand is dealt, a trump suit is chosen. There are 4 ways trump can be called:

- one of the 4 players can call trump: this results in a 4 player hand
- one of the 4 players can call trump alone (ie. play without a partner): this results in a 3 player hand
- one of the 4 players can call trump and an opponent can defend alone (ie. play without a partner): this also results in a 3 player hand
- one of the 4 players can call trump alone and an opponent can defend alone: this results in a 2 player hand

There are 8 possible ways to call trump in a 4 player hand: each of the 2 teams can choose from 4 suits. (We need only consider the choice by teams, since for a 4 player hand, it doesn't matter which of the team members actually chooses trump, the possible plays remain the same.)

There are 16 possible ways to arrive at a 3 player hand via a go alone: 4 players, each of whom can choose to go alone in one of 4 suits. Similarly, there are 16 possible ways for a defend alone to occur: 2 teams which can choose from 4 suits, with 2 opposing players who can each choose to defend alone. (There can be a rule restricting defending alone after passing, which I'm ignoring: it's not a common rule and it only reduces the number of possible 3 player defend alone hands from 16 to 12.) So there are 32 unique ways to call trump which results in a 3 player hand.

There are 32 possible ways to call trump in a 2 player hand via a go alone and defend alone: 4 players, each of whom can choose from 4 suits alone, with 2 opposing players who can choose to defend alone.

So looking at the number of unique ways to call trump, we have:

- 8 unique ways to call trump in a 4 player hand
- 32 unique ways to call trump in a 3 player hand
- 32 unique ways to call trump in a 2 player hand

Once trump is selected in a 2, 3, or 4 player hand, play begins with the leader playing a card, and then each remaining player playing one card in turn. For the first trick of the hand, the leader is pre-determined (the first participating player left of the dealer), while for subsequent tricks the leader can be any of the players, depending on who won the previous trick.

The leader can freely choose to play any card in their hand. The remaining players must follow this card's suit if they can: if the leader plays a heart and the next player has one or more hearts, then that player must play one of those hearts. If a player does not have any of the led suit, they can choose any of their cards to play. Whether a player has to follow or not affects the hand permutations, but it's difficult to determine this analytically. Thus I'm going to assume a player never has to follow, which will mean this calculation will give an over-estimate on the number of unique ways to play a hand. Once I have statistical data on the follow probability, I can re-analyze.

For the first trick in a 4 player hand, there are 5 possible cards for the leader to play, and then each subsequent player can follow with any of their 5 cards (per the above simplification). So the number of unique card combinations for the first trick is 5^4. For the second trick, there are 4 possible players to lead, each of whom can lead one of 4 cards, with each subsequent player choosing from their own set of 4 cards, making the total number of combinations for the second trick 4(4^4). Similarly, there are 4(3^4) combinations for the third trick, 4(2^4) for the fourth, and 4(1^4) for the fifth. In general, these terms can be read as:

(#leaders)(#cards ^ (#players))

Altogether, the number of unique card combinations for a 4 player hand multiplied by the number of ways a 4 player hand can be set is:

8(1(5^4))(4(4^4))(4(3^4))(4(2^4))(4(1^4))

which is 4.25e11, or roughly 425 billion ways to play a 4 player hand of euchre.

Considering the possible combinations for a 3 player hand of euchre multiplied by the number of ways a 3 player hand can be set, we get:

32(1(5^3))(3(4^3))(3(3^3))(3(2^3))(3(1^3))

which is 4.48e9, or about 4.48 billion.

And for a 2 player hand of euchre, the number of play combinations multiplied by the number of ways a 2 player hand can be set is:

32(1(5^2))(2(4^2))(2(3^2))(2(2^2))(2(1^2))

which is 7.37e6, or about 7.37 million.

To arrive at the total number of euchre hands that can be played, we take the number of unique dealt euchre hands and multiply by the number of ways a euchre hand can be played:

1.25e14(4.25e11 + 4.48e9 + 7.37e6)

which is 5.35e25, or about a 53 trillion trillion different played hands of euchre.

There are a number of over-estimates in this calculation: as discussed, we have not accounted for players having to follow, and there will be hands in which card distribution and trump selection will rule out particular players from ever leading, reducing the number of play combinations. However, this works as an upper bound on the number of euchre hands that can be played.

A Google spreadsheet with these calculations is here:

https://docs.google.com/spreadsheets/d/1KNStpy2w9dmemeT1gfbHMtncN1WTM9G5L7fw0VdxXoY/edit?usp=sharing

Blog Archive