public override List <HandType> HandleRequest(IEnumerable <RoundTile> tiles, List <HandType> handTypes)
        {
            if (tiles == null)
            {
                return(handTypes);
            }

            var result = RoundTileHelper.DetermineHandCanWin(tiles);

            if (result == HandType.Triplets || result == HandType.Straight || result == HandType.Chicken)
            {
                handTypes.Add(result);
            }
            else
            {
                //cant win
                //short circuit
                return(handTypes);
            }

            if (_successor != null)
            {
                return(_successor.HandleRequest(tiles, handTypes));
            }
            else
            {
                return(handTypes);
            }
        }
Beispiel #2
0
 public void CreateRound()
 {
     TestDataContext.Rounds.Add(new Round
     {
         GameId       = GameId,
         Wind         = WindDirection.East,
         DateCreated  = DateTime.Now,
         RoundTiles   = RoundTileHelper.CreateTiles(TestDataContext).Shuffle(),
         RoundResults = new List <RoundResult>(),
         RoundPlayers = new List <RoundPlayer>
         {
             new RoundPlayer
             {
                 GamePlayerId = 1,
                 Wind         = WindDirection.South
             },
             new RoundPlayer
             {
                 GamePlayerId = 2,
                 Wind         = WindDirection.East
             },
             new RoundPlayer
             {
                 GamePlayerId = 3,
                 Wind         = WindDirection.West
             },
             new RoundPlayer
             {
                 GamePlayerId = 4,
                 Wind         = WindDirection.North
             }
         }
     });
 }
Beispiel #3
0
            private bool DetermineIfUserCanChow(IEnumerable <RoundTile> playerTiles, RoundTile boardTile)
            {
                //player tiles can't be in graveyard when pong from board
                //when someone throw a tile, there should not be a justpicked status tile
                if (boardTile.Tile.TileType == TileType.Wind || boardTile.Tile.TileType == TileType.Dragon || boardTile.Tile.TileType == TileType.Flower)
                {
                    return(false);
                }

                var possibleChowTiles = RoundTileHelper.FindPossibleChowTiles(boardTile, playerTiles);

                return(possibleChowTiles.Count() >= 1);
            }
        public static void SetNextPlayer(Round round, IPointsCalculator pointCalculator)
        {
            var playerThatHasTurn = round.RoundPlayers.FirstOrDefault(p => p.IsMyTurn == true);

            playerThatHasTurn.IsMyTurn  = false;
            playerThatHasTurn.MustThrow = false;

            var nextPlayer = GetNextPlayer(round.RoundPlayers, playerThatHasTurn.Wind);

            nextPlayer.IsMyTurn  = true;
            nextPlayer.MustThrow = true;

            //in case there is other player that has my turn set to true
            var otherPlayers = round.RoundPlayers.Where(u => u.IsMyTurn == true &&
                                                        u.GamePlayer.Player.UserName != nextPlayer.GamePlayer.Player.UserName &&
                                                        u.GamePlayer.Player.UserName != playerThatHasTurn.GamePlayer.Player.UserName);

            foreach (var otherPlayerTurn in otherPlayers)
            {
                otherPlayerTurn.IsMyTurn = false;
            }

            //automatically pick tile for next player
            //unless remaining tile is 1, give user give up action
            var unopenTiles = round.RoundTiles.Where(t => string.IsNullOrEmpty(t.Owner));

            if (unopenTiles.Count() == 1)
            {
                nextPlayer.RoundPlayerActions.Add(new RoundPlayerAction {
                    ActionType = ActionType.GiveUp
                });
                nextPlayer.MustThrow = false;
            }
            else
            {
                var newTiles = RoundTileHelper.PickTile(round, nextPlayer.GamePlayer.Player.UserName);
                if (newTiles == null)
                {
                    round.IsEnding = true;
                }
                CheckSelfAction(round, nextPlayer, pointCalculator);
            }
        }
Beispiel #5
0
            public async Task <IEnumerable <RoundDto> > Handle(Command request, CancellationToken cancellationToken)
            {
                var round = await _context.Rounds.FindAsync(request.RoundId);

                if (round == null)
                {
                    throw new RestException(HttpStatusCode.NotFound, new { Round = "Could not find round" });
                }

                var tileToThrow = round.RoundTiles.FirstOrDefault(t => t.Id == request.TileId);

                if (tileToThrow == null)
                {
                    throw new RestException(HttpStatusCode.NotFound, new { RoundTile = "Could not find the tile" });
                }

                var currentPlayer = round.RoundPlayers.FirstOrDefault(p => p.GamePlayer.Player.UserName == request.UserName);

                if (currentPlayer == null)
                {
                    throw new RestException(HttpStatusCode.NotFound, new { Round = "Could not find current player" });
                }

                if (!currentPlayer.MustThrow && !currentPlayer.IsMyTurn)
                {
                    throw new RestException(HttpStatusCode.NotFound, new { Round = "Player not suppose to throw" });
                }

                //clear all player actions initially every time throw command invoked
                round.RoundPlayers.ForEach(p =>
                {
                    p.RoundPlayerActions.Clear();
                });

                //previous active tile on board to be no longer active
                var existingActiveTileOnBoard = round.RoundTiles.FirstOrDefault(t => t.Status == TileStatus.BoardActive);

                if (existingActiveTileOnBoard != null)
                {
                    existingActiveTileOnBoard.Status = TileStatus.BoardGraveyard;
                }

                //mark current user's just picked tile to be active
                var userJustPickedTile = round.RoundTiles.Where(t => t.Owner == request.UserName && t.Status == TileStatus.UserJustPicked);

                if (userJustPickedTile != null && userJustPickedTile.Count() > 0)
                {
                    userJustPickedTile.ForEach(t =>
                    {
                        t.Status = TileStatus.UserActive;
                    });
                }

                //update thrown tile props and increase the tilecounter
                tileToThrow.ThrownBy = request.UserName;
                tileToThrow.Owner    = DefaultValue.board;
                tileToThrow.Status   = TileStatus.BoardActive;
                tileToThrow.BoardGraveyardCounter = round.TileCounter;
                round.TileCounter++;

                //don't change user's turn if there is player with action
                //----------------------------------------------------------
                var gotAction = AssignPlayerActions(round, currentPlayer);

                if (gotAction)
                {
                    //action has priority list: win > pong|kong > chow
                    var winActionPlayer = round.RoundPlayers.Where(rp => rp.RoundPlayerActions.Any(rpa => rpa.ActionType == ActionType.Win));
                    if (winActionPlayer.Count() > 0)
                    {
                        bool multipleWinners = winActionPlayer.Count() > 1;
                        foreach (var winner in winActionPlayer)
                        {
                            if (multipleWinners)
                            {
                                winner.RoundPlayerActions.Where(ac => ac.ActionType == ActionType.Win).ForEach(a => a.ActionStatus = ActionStatus.Active);
                            }
                            else
                            {
                                winner.RoundPlayerActions.ForEach(a => a.ActionStatus = ActionStatus.Active);
                            }
                        }
                    }
                    else
                    {
                        var pongOrKongActionPlayer = round.RoundPlayers.Where(
                            rp => rp.RoundPlayerActions.Any(
                                rpa => rpa.ActionType == ActionType.Pong ||
                                rpa.ActionType == ActionType.Kong
                                )
                            ).FirstOrDefault();
                        if (pongOrKongActionPlayer != null)
                        {
                            pongOrKongActionPlayer.RoundPlayerActions.ForEach(a => a.ActionStatus = ActionStatus.Active);
                        }
                        //check if next player has chow action
                        else
                        {
                            var chowActionPlayer = round.RoundPlayers.Where(rp => rp.RoundPlayerActions.Any(rpa => rpa.ActionType == ActionType.Chow)).FirstOrDefault();
                            if (chowActionPlayer != null)
                            {
                                chowActionPlayer.RoundPlayerActions.ForEach(a => a.ActionStatus = ActionStatus.Active);
                            }
                        }
                    }
                }
                else
                {
                    RoundHelper.SetNextPlayer(round, _pointCalculator);

                    currentPlayer.IsMyTurn = false;

                    //check if theres more remaining tile, if no more tiles, then set round to ending
                    var remainingTiles = round.RoundTiles.FirstOrDefault(t => string.IsNullOrEmpty(t.Owner));
                    if (remainingTiles == null)
                    {
                        round.IsEnding = true;
                    }
                }
                currentPlayer.MustThrow = false;

                if (!currentPlayer.IsManualSort)
                {
                    var playerAliveTiles = round.RoundTiles.Where(rt => rt.Owner == request.UserName && (rt.Status == TileStatus.UserActive || rt.Status == TileStatus.UserJustPicked)).ToList();
                    RoundTileHelper.AssignAliveTileCounter(playerAliveTiles);
                }

                var success = await _context.SaveChangesAsync() > 0;

                List <RoundDto> results = new List <RoundDto>();

                foreach (var p in round.RoundPlayers)
                {
                    results.Add(_mapper.Map <Round, RoundDto>(round, opt => opt.Items["MainRoundPlayer"] = p));
                }

                if (success)
                {
                    return(results);
                }

                throw new Exception("Problem throwing tile");
            }
Beispiel #6
0
            public async Task <IEnumerable <RoundDto> > Handle(Command request, CancellationToken cancellationToken)
            {
                var game = await _context.Games.FirstOrDefaultAsync(x => x.Code == request.GameCode.ToUpper());

                if (game == null)
                {
                    throw new RestException(HttpStatusCode.BadRequest, new { Game = "Game does not exist" });
                }

                Round lastRound = game.Rounds.OrderByDescending(r => r.DateCreated).FirstOrDefault();

                if (lastRound != null && !lastRound.IsOver)
                {
                    throw new RestException(HttpStatusCode.BadRequest, new { Round = "Last round is not over" });
                }

                var newRound = new Round
                {
                    GameId       = game.Id,
                    DateCreated  = DateTime.Now,
                    RoundTiles   = RoundTileHelper.CreateTiles(_context).Shuffle(),
                    RoundPlayers = new List <RoundPlayer>(),
                    RoundResults = new List <RoundResult>()
                };

                List <RoundPlayer> roundPlayers = new List <RoundPlayer>();

                if (lastRound == null)
                {
                    game.Status = GameStatus.Playing;
                    Player firstDealer = game.GamePlayers.First(u => u.InitialSeatWind == WindDirection.East).Player;
                    newRound.Wind         = WindDirection.East;
                    newRound.RoundCounter = 1;
                    foreach (var gp in game.GamePlayers)
                    {
                        var rp = new RoundPlayer {
                            GamePlayerId = gp.Id, GamePlayer = gp, Round = newRound, Wind = gp.InitialSeatWind.Value, Points = gp.Points
                        };
                        if (gp.PlayerId == firstDealer.Id)
                        {
                            rp.IsInitialDealer = true;
                            rp.IsDealer        = true;
                            rp.IsMyTurn        = true;
                            rp.MustThrow       = true;
                        }
                        roundPlayers.Add(rp);
                    }
                }
                else
                {
                    newRound.RoundCounter = lastRound.RoundCounter + 1;
                    var lastRoundDealer = lastRound.RoundPlayers.First(u => u.IsDealer);

                    //if this is not the first round
                    //last round check
                    //1.) if the winner of last round == dealer then no wind change
                    //2.) if last round "IsTied" set to true then no wind change
                    if (lastRound.IsTied)
                    {
                        newRound.Wind = lastRound.Wind;
                        roundPlayers.AddRange(GetNewUserRounds(lastRound.RoundPlayers, sameRound: true, lastRoundDealer.Wind));
                    }
                    else
                    {
                        //if last game is not tied, then there gotta be a winner here
                        //could be more than one winners here
                        var lastRoundWinners   = lastRound.RoundResults.Where(x => x.PlayResult == PlayResult.Win);
                        var dealerWonLastRound = lastRoundWinners.Any(x => x.PlayerId == lastRoundDealer.GamePlayer.Player.Id);

                        if (dealerWonLastRound)
                        {
                            newRound.Wind = lastRound.Wind;
                            roundPlayers.AddRange(GetNewUserRounds(lastRound.RoundPlayers, sameRound: true, lastRoundDealer.Wind));
                        }
                        else
                        {
                            //determine nextdealer
                            var windOfNextDealer = NextWindClockWise(lastRoundDealer.Wind);
                            roundPlayers.AddRange(GetNewUserRounds(lastRound.RoundPlayers, sameRound: false, windOfNextDealer));
                            var roundWindChanged = roundPlayers.Any(p => p.IsDealer == true && p.IsInitialDealer == true);
                            newRound.Wind = roundWindChanged ? NextWindClockWise(lastRound.Wind) : lastRound.Wind;
                        }
                    }
                }

                foreach (var ur in roundPlayers)
                {
                    newRound.RoundPlayers.Add(ur);
                }

                var theDealer = roundPlayers.First(u => u.IsDealer);

                var dealerId = theDealer.GamePlayerId;

                //for debugging
                //RoundTileHelper.SetupForWinPongChowPriority(newRound.RoundTiles);

                //tiles assignment and sorting
                foreach (var gamePlayer in game.GamePlayers)
                {
                    if (gamePlayer.Id == dealerId)
                    {
                        RoundTileHelper.AssignTilesToUser(14, gamePlayer.Player.UserName, newRound.RoundTiles);
                        //set one tile status to be justpicked
                        newRound.RoundTiles.First(rt => rt.Owner == gamePlayer.Player.UserName && rt.Tile.TileType != TileType.Flower).Status = TileStatus.UserJustPicked;
                        var playerTiles = newRound.RoundTiles.Where(rt => rt.Owner == gamePlayer.Player.UserName && (rt.Status == TileStatus.UserActive || rt.Status == TileStatus.UserJustPicked)).ToList();
                        RoundTileHelper.AssignAliveTileCounter(playerTiles);
                    }
                    else
                    {
                        RoundTileHelper.AssignTilesToUser(13, gamePlayer.Player.UserName, newRound.RoundTiles);
                        var playerTiles = newRound.RoundTiles.Where(rt => rt.Owner == gamePlayer.Player.UserName && rt.Status == TileStatus.UserActive).ToList();
                        RoundTileHelper.AssignAliveTileCounter(playerTiles);
                    }
                }

                _context.Rounds.Add(newRound);

                var success = await _context.SaveChangesAsync() > 0;

                List <RoundDto> results = new List <RoundDto>();

                foreach (var p in newRound.RoundPlayers)
                {
                    results.Add(_mapper.Map <Round, RoundDto>(newRound, opt => opt.Items["MainRoundPlayer"] = p));
                }

                if (success)
                {
                    return(results);
                }

                throw new Exception("Problem creating a new round");
            }
Beispiel #7
0
            public async Task <IEnumerable <RoundDto> > Handle(Command request, CancellationToken cancellationToken)
            {
                //Note to consider when kong tile:
                //if player has pong in their graveyard, it can be kong
                //-player turn changed
                //-flag when user can kong
                //-when kong tile user need to grab a new tile.
                //-kong doesnt rely on board active tile when its "User's turn", it could be just from player list of active tiles
                //-user can kong anytime when it's their turn n it could be more than 1 set to kong
                //assign tile ownership to current user
                //weird situation is when it's user's turn, user can kong their active tiles and can kong board active tiles

                var updatedTiles = new List <RoundTile>();
                var round        = await _context.Rounds.FindAsync(request.RoundId);

                if (round == null)
                {
                    throw new RestException(HttpStatusCode.NotFound, new { Round = "Could not find round" });
                }

                var currentPlayer = round.RoundPlayers.FirstOrDefault(u => u.GamePlayer.Player.UserName == request.UserName);

                if (currentPlayer == null)
                {
                    throw new RestException(HttpStatusCode.BadRequest, new { Round = "there are no user with this username in the round" });
                }

                List <RoundTile> userActiveTilesToKong = new List <RoundTile>();
                var currentUserTiles = round.RoundTiles.Where(t => t.Owner == request.UserName);

                //if it's user's turn, check if user has all 4 same tiles first in the user active tiles
                //because the request has tile type and tile value, there can only one possible kong
                //if user has pong tile, user can kong matching tile
                var tilesToKong = currentUserTiles
                                  .Where(t => t.Tile.TileType == request.TileType &&
                                         t.Tile.TileValue == request.TileValue);

                if (tilesToKong.Count() == 4)
                {
                    if (currentPlayer.IsMyTurn)
                    {
                        //if its not konged already, then user can kong it
                        var kongedTile = tilesToKong.Where(t => t.TileSetGroup == TileSetGroup.Kong);
                        if (kongedTile.Count() == 0)
                        {
                            updatedTiles.AddRange(tilesToKong);
                        }
                    }
                }

                //this means that user need to kong from board
                if (tilesToKong.Count() == 3)
                {
                    //if user only have three and its already ponged, then player can't kong
                    var tilesAlreadyPonged = tilesToKong.Where(t => t.TileSetGroup == TileSetGroup.Pong);
                    if (tilesAlreadyPonged.Count() == 3)
                    {
                        throw new RestException(HttpStatusCode.BadRequest, new { Round = "Can't do kong when all tiles ponged" });
                    }

                    var boardActiveTiles = round.RoundTiles.FirstOrDefault(t => t.Status == TileStatus.BoardActive);
                    if (boardActiveTiles == null)
                    {
                        throw new RestException(HttpStatusCode.BadRequest, new { Round = "there are no board active tile to kong" });
                    }
                    var boardActiveMatchedWithRequest = (boardActiveTiles.Tile.TileType == request.TileType && boardActiveTiles.Tile.TileValue == request.TileValue);

                    if (boardActiveMatchedWithRequest)
                    {
                        //only have 3 active tiles then board must exist to kong
                        var allTilesAreActive = tilesToKong.Where(t => t.Status != TileStatus.UserGraveyard);
                        if (boardActiveMatchedWithRequest && allTilesAreActive.Count() == 3)
                        {
                            updatedTiles.AddRange(tilesToKong);
                            updatedTiles.Add(boardActiveTiles);
                        }
                    }
                }

                if (updatedTiles.Count() == 4)
                {
                    updatedTiles.GoGraveyard(request.UserName, TileSetGroup.Kong, round.RoundTiles.GetLastGroupIndex(request.UserName));
                }
                else
                {
                    throw new RestException(HttpStatusCode.BadRequest, new { Kong = "Not possible to kong" });
                }

                //set existing justpicked tile to useractive;
                var existingJustPicked = round.RoundTiles.FirstOrDefault(rt => rt.Owner == request.UserName && rt.Status == TileStatus.UserJustPicked);

                if (existingJustPicked != null)
                {
                    existingJustPicked.Status = TileStatus.UserActive;
                    updatedTiles.Add(existingJustPicked);
                }

                //clear existing action
                currentPlayer.RoundPlayerActions.Clear();

                //add new tile for user
                var newTiles = RoundTileHelper.PickTile(round, request.UserName, true);

                if (newTiles.Count() > 0)
                {
                    //assign new tile to user that kong the tile
                    foreach (var tile in newTiles)
                    {
                        updatedTiles.Add(tile);
                    }
                    RoundHelper.CheckSelfAction(round, currentPlayer, _pointsCalculator);
                }
                else
                {
                    //TODO: what if user kong when there is no more tile
                }

                currentPlayer.IsMyTurn = true;
                //because new tile automatically added, player must throw set to true
                currentPlayer.MustThrow = true;

                if (round.IsEnding)
                {
                    round.IsEnding = false;
                }

                var otherPlayers = round.RoundPlayers.Where(u => u.IsMyTurn == true && u.GamePlayer.Player.UserName != request.UserName);

                foreach (var otherPlayerTurn in otherPlayers)
                {
                    otherPlayerTurn.IsMyTurn = false;
                }

                try
                {
                    var success = await _context.SaveChangesAsync() > 0;

                    List <RoundDto> results = new List <RoundDto>();

                    foreach (var p in round.RoundPlayers)
                    {
                        results.Add(_mapper.Map <Round, RoundDto>(round, opt => opt.Items["MainRoundPlayer"] = p));
                    }

                    if (success)
                    {
                        return(results);
                    }
                }
                catch (DbUpdateConcurrencyException)
                {
                    throw new RestException(HttpStatusCode.BadRequest, new { Round = "tile was modified" });
                }

                throw new Exception("Problem kong ing tile");
            }
Beispiel #8
0
            public async Task <IEnumerable <RoundDto> > Handle(Command request, CancellationToken cancellationToken)
            {
                //Note to consider when picking tile:
                //-tile is flower
                //-no more tile to pick
                //-only 1 more tile to pick because player have an option not to take the last tile.
                var round = await _context.Rounds.FindAsync(request.RoundId);

                if (round == null)
                {
                    throw new RestException(HttpStatusCode.NotFound, new { Round = "Could not find round" });
                }

                var currentPlayer = round.RoundPlayers.FirstOrDefault(p => p.GamePlayer.Player.UserName == request.UserName);

                if (currentPlayer == null)
                {
                    throw new RestException(HttpStatusCode.NotFound, new { Round = "Could not find current player" });
                }

                currentPlayer.MustThrow = true;

                //TODO only allow pick tile when it's player's turn

                var newTiles = RoundTileHelper.PickTile(round, request.UserName);

                if (newTiles == null)
                {
                    round.IsEnding = true;
                }

                //pick action now only available on last tile
                //check if user can win if they pick on last tile
                var remainingTiles = round.RoundTiles.FirstOrDefault(t => string.IsNullOrEmpty(t.Owner));

                if (remainingTiles == null)
                {
                    currentPlayer.RoundPlayerActions.Clear();
                    if (RoundHelper.DetermineIfUserCanWin(round, currentPlayer, _pointCalculator))
                    {
                        currentPlayer.RoundPlayerActions.Add(new RoundPlayerAction {
                            ActionType = ActionType.Win
                        });
                    }
                }

                try
                {
                    var success = await _context.SaveChangesAsync() > 0;

                    List <RoundDto> results = new List <RoundDto>();

                    foreach (var p in round.RoundPlayers)
                    {
                        results.Add(_mapper.Map <Round, RoundDto>(round, opt => opt.Items["MainRoundPlayer"] = p));
                    }

                    if (success)
                    {
                        return(results);
                    }
                }
                catch (DbUpdateConcurrencyException)
                {
                    throw new RestException(HttpStatusCode.BadRequest, new { Round = "player status was modified" });
                }

                throw new Exception("Problem picking tile");
            }