# Poker server as a service

This is very simple poker server. Target is a REST server.

In real poker you do not act until action is on you (well you are not supposed to).

On a server it is nice to accept action (bet, call, call any, raise, and fold) in advance and then only process when it comes the player's turn. It makes for faster play and is more scalable. I would prefer not to debate if this is a proper model. In this simplified model there is only one action at this time that is nominally bet/call.

Next step would be to fold a player if they do not act in x period of time. I wanted to ask for feedback on this relatively simple model. Things get sticky fast background processing.

As tested it takes action for 1, 2, 4 and when action is submitted by 3 it processes 3 and 4.

Test - I know not a great test

PkrTable pkrTable = new PkrTable(new List<PokerPlayer>());
Debug.WriteLine("test submit action ID = 3");
pkrTable.pkrPlayers.FirstOrDefault(x => x.ID == 3).SbmtAction(14);


.

public class PkrAction
{
//in real poker there are different actions
//this is just simplified
public PkrPlayer PkrPlayer { get; }
public int Amt { get; }
public PkrAction(PkrPlayer pkrPlayer, int amt)
{
PkrPlayer = pkrPlayer;
Amt = amt;
}
}


.

public class PkrPlayer
{
private PkrTable pkrTable;

public int ID { get; }

public void SbmtAction(int amount)
{
PkrAction pa = new PkrAction(this, amount);
pkrTable.SbmtAction(pa);
}

public override int GetHashCode()
{
return ID;
}
public override bool Equals(object obj)
{
if (obj == null || !(obj is PokerPlayer))
return false;
else
return ID == ((PokerPlayer)obj).ID;
}

public PkrPlayer(int id, PkrTable _pkrTable)
{
ID = id;
pkrTable = _pkrTable;
}
}


.

public class PkrTable
{
//the next two will be private - temp public for test
public List<PkrAction> pkrActions = new List<PkrAction>();
public List<PkrPlayer> pkrPlayers = new List<PkrPlayer>();
private PkrPlayer waitingOn = null;

public void SbmtAction(PkrAction pkrAction)
{
//on the main thread and the idea is to keep this open
//on a real table players are not supposed to act out of turn
//an a server a player can act out of turn as you just don't show it to other players
//for scale and speed the server will take action out of turn
//this will be a REST service
Debug.WriteLine($"SbmtAction {pkrAction.PkrPlayer.ID}"); pkrActions.RemoveAll(x => x.PkrPlayer == pkrAction.PkrPlayer);//only keep the latest action //List is not concurrent - will put in a concurrent List later pkrActions.Add(pkrAction); //in final code will not add if the action is cancel if (BeenWaitinOnYou(pkrAction)) { Debug.WriteLine($"   SbmtAction BeenWaitinOnYou {pkrAction.PkrPlayer.ID}");
//below for test only
}
//in final code need to figure out how to fold out a player that does not submitt action in x time
//need to send notice to player that they are on the clock
}

private bool BeenWaitinOnYou(PkrAction pkrAction)
{
if(waitingOn != null && waitingOn == pkrAction.PkrPlayer)
{
return true;
}
return false;
}
private bool ProcessAction(PkrAction pa)
{
return true; //for now assume any action is sucessful
}
private void ProcessQueue()
{
//in final product will be more complex as action can be more than one round
Debug.WriteLine("ProcessQueue");
foreach(PkrPlayer pp in pkrPlayers)
{
Debug.WriteLine($" ProcessQueue {pp.ID}"); if(waitingOn != null && waitingOn != pp) { Debug.WriteLine($"  ProcessQueue continue {pp.ID}");
continue;
}
waitingOn = null;
PkrAction pa = pkrActions.FirstOrDefault(x => x.PkrPlayer == pp);
if(pa == null)
{
//need to wait on the player
Debug.WriteLine($" ProcessQueue waitingOn {pp.ID}"); waitingOn = pp; break; } else { Debug.WriteLine($"  ProcessQueue ProcessAction {pp.ID}");
if (ProcessAction(pa))
{
pkrActions.Remove(pa);
}
else
{
throw new Exception("process action failed - it should not");
}
}
}
}

public PkrTable(List<PokerPlayer> pokerPlayers)
{

//below is for test
//not a great test but for now what I have
PkrPlayer pp = new PkrPlayer(1, this);
pp.SbmtAction(12);
pp = new PkrPlayer(2, this);
pp.SbmtAction(12);
PkrPlayer pp3 = new PkrPlayer(3, this);
pkrPlayers.Add(pp3);//this player has not submitted action
pp = new PkrPlayer(4, this);
pp.SbmtAction(12);

//the idea is to leave SbmtAction open on main thread
taskA.Wait();  // this is only for test
Debug.WriteLine("PkrTable ctor done");
}
}

• Is Pkr really that much shorter than Poker and couldn't you just type Pok and hit tab for auto-complete? Abbreviations to already short words confuse me. – Shelby115 Apr 2 '18 at 19:05
• Wait, what's the difference between PkrPlayer and PokerPlayer? And why isn't PokerPlayer included above? – Shelby115 Apr 2 '18 at 19:07
• @Shelby115 Because I am just working on one small piece of it right now. – paparazzo Apr 3 '18 at 15:36

Naming: Don't use abbreviations for already-short words. Amount instead of Amt, Poker instead of Pkr, Sbmt instead of Submit; you aren't being charged by the character. Don't use very similar names. It looks like you have classes PokerPlayer and PkrPlayer, and variables pokerPlayers and pkrPlayers? If you really can't think of names that differentiate them, are they the same?
Structure: ProcessQueue implies to me that you are going to iterate over all of your messages and process each one, but that's not what this does. Should ProcessQueue return a value to indicate whether it was able to process any messages? Your foreach(PkrPlayer pp in pkrPlayers) loop is pretty confusing; the tests against/updating of waitingOn are hard to follow.
I would suggest 2 major changes. First, just track the next player and have it always be non-null. Second, store the incoming actions in a Dictionary<PokerPlayer, PokerAction>. This will make it easy to find the next action or determine that you need to wait for a particular message to come in. ProcessQueue (or whatever you rename it to) can return a value indicating that it was able to move forward or if it is waiting for a player's action.