Покер сервер в качестве сервиса


Это очень простой покер сервер. Цель-это сервер, остальные.

В реальном покере вы не действовать до того момента, пока на вас (вы ж не положено).

На сервере это хорошо, чтобы принять действие (бет, колл, колл любой, рейз, и фолд) заранее, а потом только когда приходит очередь игрока. Это делает для более быстрой игры и более масштабируемой. Я бы предпочел не дискутировать, если это правильная модель. В этой упрощенной модели есть только одно действие за это время, что номинально бет/колл.

Следующим шагом будет сложить игрока, если они не действуют в Х период времени. Я хотела попросить для обратной связи на этой относительно простой модели. Вещи довольно быстро фоновой обработки.

В качестве испытания он принимает меры для 1, 2, 4 и когда действие представлено 3 процессы 3 и 4.

Тест - я знаю не большое испытание

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}");
            Task taskA = new Task(() => ProcessQueue());
            taskA.Start();
            //below for test only
            taskA.Wait();
        }
        //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);
        pkrPlayers.Add(pp);
        pp = new PkrPlayer(2, this);
        pp.SbmtAction(12);
        pkrPlayers.Add(pp);
        PkrPlayer pp3 = new PkrPlayer(3, this);
        pkrPlayers.Add(pp3);//this player has not submitted action
        pp = new PkrPlayer(4, this);
        pp.SbmtAction(12);
        pkrPlayers.Add(pp);

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


155
3
задан 1 апреля 2018 в 11:04 Источник Поделиться
Комментарии
1 ответ

Название: не используйте аббревиатуры для уже короткие слова. Amount вместо Amt, Poker вместо Pkr, Sbmt вместо Submit; вас не будет взиматься по характеру. Не используйте очень похожие имена. Похоже, что у вас есть занятия PokerPlayer и PkrPlayerи переменные pokerPlayers и pkrPlayers? Если вы действительно не могу вспомнить названия, отличающие их, они одинаковые?

Структура: ProcessQueue подразумевает для меня, что вы собираетесь перебирать все ваши сообщения и обрабатывать каждый из них, но это не то, что это делает. Следует ProcessQueue возвращает значение, показывающее как он был в состоянии обрабатывать любые сообщения? Ваш foreach(PkrPlayer pp in pkrPlayers) петли довольно запутанным; тесты с/обновление waitingOn трудно следовать.

Я бы предложил 2 основные изменения. Во-первых, просто отслеживать следующий игрок и он всегда будет иметь значение null. Во-вторых, хранить входящую действия в Dictionary<PokerPlayer, PokerAction>. Это позволит сделать его легким, чтобы найти следующего действия или определить, что вы должны ждать определенное сообщение, чтобы прийти в. ProcessQueue (или как вы переименовать его) может возвращать значение, указывающее, что он был в состоянии двигаться вперед или если это ждет игрока действий.

2
ответ дан 21 июля 2018 в 02:07 Источник Поделиться