Example #1
0
        public Guid CreateGame(Guid player, Guid room)
        {
            using (var context = new MilleBornesEntities())
            {
                var playerEntity = context.User
                    .Where(us => us.LoggedInUser != null)
                    .SingleOrDefault(us => us.LoggedInUser.Token == player);
                if (playerEntity == null)
                {
                    throw new FaultException("Le joueur n'est pas valide ou est hors-ligne.");
                }

                var roomEntity = context.Room
                    .SingleOrDefault(rm => rm.Token == room);
                if (roomEntity == null)
                {
                    throw new FaultException("La salle n'est pas trouvée.");
                }

                if (roomEntity.MasterUserId != playerEntity.UserId)
                {
                    throw new FaultException("Seul le maître de la salle peut démarrer la partie.");
                }

                var newGame = new Game()
                {
                    Token = Guid.NewGuid(),
                    StartDate = DateTime.UtcNow,
                    IsTakingDisconnectDecision = false
                };

                FillPlayerConfig(context, roomEntity, newGame);

                roomEntity.Game = newGame;
                roomEntity.Started = true;
                context.Game.Add(newGame);
                try
                {
                    context.SaveChanges();
                }
                catch (System.Data.Entity.Infrastructure.DbUpdateException dbue)
                {
                    throw;
                }

                InitializeGame(newGame);
                try
                {
                    context.SaveChanges();
                }
                catch (System.Data.Entity.Infrastructure.DbUpdateException dbue)
                {
                    throw;
                }

                return newGame.Token;
            }
        }
Example #2
0
        private static void FillPlayerConfig(MilleBornesEntities context, Room roomEntity, Game newGame)
        {
            // Essayer en premier lieu avec le service, sinon
            // regarder directement dans la base de données.

            List<PlayerGame> playerGameSource = new List<PlayerGame>();
#if false
            try
            {
                using (var client = new LobbyGameProxy.LobbyServiceClient())
                {
                    var configEntries = client.GetPlayerConfig(roomEntity.Token);

                    foreach (var entry in configEntries)
                    {
                        var user = context.User
                            .Where(us => us.LoggedInUser != null)
                            .SingleOrDefault(us => us.LoggedInUser.Token == entry.UserToken);

                        if (user == null)
                        {
                            continue;
                        }

                        var playerGame = new PlayerGame()
                        {
                            Game = newGame,
                            UserId = user.UserId,
                            User = user,
                            LastHeartbeat = DateTime.UtcNow,
                            Order = entry.Order,
                            Team = entry.Team + 1,
                            HasJoined = user.UserId == roomEntity.MasterUserId
                        };
                    }
                }
            }
#endif
            //catch (Exception ex)
            //{
                playerGameSource = roomEntity.PlayerRoomState.Select((prs, inx) => new PlayerGame()
                {
                    Game = newGame,
                    UserId = prs.UserId,
                    User = prs.User,
                    LastHeartbeat = DateTime.UtcNow,
                    Order = inx,
                    Team = prs.Team + 1,
                    HasJoined = prs.UserId == roomEntity.MasterUserId
                })
                .ToList();
            //}

            newGame.PlayerGame = playerGameSource;
        }
Example #3
0
 private void EndGame(Game game, GameEndReason reason)
 {
     game.EndDate = DateTime.UtcNow;
     game.EndToken = Guid.NewGuid();
     game.EndReason = reason;
 }
Example #4
0
        private Tuple<int, List<DrawCardEvent>>[] GetAllPlayersHands(Game game)
        {
            var playerHands = game.GameEvent
                .Where(ge => ge.Type == GameEventType.DRAW_CARD)
                .Cast<DrawCardEvent>()
                .Where(dc => dc.PlayCardEvent.Count == 0)
                .GroupBy(dc => dc.PlayerId)
                .Select(g => Tuple.Create(g.Key, g.ToList()))
                .ToArray();

            return playerHands;
        }
Example #5
0
        private bool CheckGameEnd(Game game)
        {
            // Finir la partie en gagnant.

            var teamStates = GetTeamsState(game);

            foreach (var teamState in teamStates)
            {
                if (teamState.DistanceTraveled == 1000)
                {
                    EndGame(game, GameEndReason.WON_THOUSAND_MILES);
                    return true;
                }
            }

            // Finir la partie en épuisant toutes les cartes.
            // (Dans la pile et celle dans les mains des joueurs)

            var playerHands = GetAllPlayersHands(game);

            if (playerHands.All(x => x.Item2.Count == 0))
            {
                EndGame(game, GameEndReason.EXHAUSTED_DECK);
                return true;
            }

            return false;
        }
Example #6
0
        private void ChangePlayer(Game game, int newPlayerId)
        {
            game.GameEvent.Add(new PlayerChangeEvent()
            {
                ServerEvent = true,
                Date = DateTime.UtcNow,
                Type = GameEventType.PLAYER_CHANGE,

                NewPlayerId = newPlayerId
            });
        }
Example #7
0
        private bool CanPlayCard(Game game, DrawCardEvent drawEvent, int playerTeamIndex, int targetTeamIndex)
        {
            if (targetTeamIndex == 0)
            {
                return true;
            }

            var targetTeamState = GetTeamState(game, targetTeamIndex);
            var card = CardDefinitions.Cards
                .Single(cd => cd.CardId == drawEvent.CardIndex);

            switch (card.CardType)
            {
                case CardType.VALUE:
                {
                    if (playerTeamIndex != targetTeamIndex)
                    {
                        return false;
                    }

                    if (targetTeamState.CanGo && !targetTeamState.CurrentlyBrokenDown)
                    {
                        bool canPlayCard = true;
                        if (targetTeamState.IsUnderSpeedLimit)
                        {
                            canPlayCard = card.Value <= 50;
                        }

                        if (!canPlayCard)
                        {
                            return false;
                        }

                        return (targetTeamState.DistanceTraveled + card.Value) <= 1000;
                    }
                    else
                    {
                        return false;
                    }
                }
                case CardType.EFFECT_POSITIVE:
                {
                    if (playerTeamIndex != targetTeamIndex)
                    {
                        return false;
                    }

                    switch (card.EffectType)
                    {
                        case EffectCardType.ACCIDENT:
                        {
                            return targetTeamState.HasAccident;
                        }
                        case EffectCardType.FUEL:
                        {
                            return targetTeamState.IsOutOfFuel;
                        }
                        case EffectCardType.TIRE:
                        {
                            return targetTeamState.HasFlatTire;
                        }
                        case EffectCardType.SPEED_LIMIT:
                        {
                            return targetTeamState.IsUnderSpeedLimit;
                        }
                        case EffectCardType.TRAFFIC_LIGHT:
                        {
                            return !targetTeamState.CanGo && !targetTeamState.CurrentlyBrokenDown;
                        }
                        case EffectCardType.NONE:
                        default:
                        {
                            return false;
                        }
                    }
                }
                case CardType.EFFECT_NEGATIVE:
                {
                    if (playerTeamIndex == targetTeamIndex)
                    {
                        return false;
                    }

                    switch (card.EffectType)
                    {
                        case EffectCardType.ACCIDENT:
                        {
                            return !targetTeamState.CurrentlyBrokenDown &&
                                !targetTeamState.InvincibleToAccidents;
                        }
                        case EffectCardType.FUEL:
                        {
                            return !targetTeamState.CurrentlyBrokenDown &&
                                !targetTeamState.InvincibleToFuel;
                        }
                        case EffectCardType.TIRE:
                        {
                            return !targetTeamState.CurrentlyBrokenDown &&
                                !targetTeamState.InvincibleToTire;
                        }
                        case EffectCardType.SPEED_LIMIT:
                        {
                            return !targetTeamState.IsUnderSpeedLimit &&
                                !targetTeamState.InvinciblePriority;
                        }
                        case EffectCardType.TRAFFIC_LIGHT:
                        {
                            return targetTeamState.CanGo &&
                                !targetTeamState.InvinciblePriority;
                        }
                        case EffectCardType.NONE:
                        default:
                        {
                            return false;
                        }
                    }
                }
                case CardType.EFFECT_INVINCIBLE:
                {
                    switch (card.EffectType)
                    {
                        case EffectCardType.ACCIDENT:
                        {
                            return !targetTeamState.InvincibleToAccidents;
                        }
                        case EffectCardType.FUEL:
                        {
                            return !targetTeamState.InvincibleToFuel;
                        }
                        case EffectCardType.TIRE:
                        {
                            return !targetTeamState.InvincibleToTire;
                        }
                        case EffectCardType.SPEED_LIMIT | EffectCardType.TRAFFIC_LIGHT:
                        {
                            return !targetTeamState.InvinciblePriority;
                        }
                        case EffectCardType.NONE:
                        default:
                        {
                            return false;
                        }
                    }
                }
                default:
                {
                    return false;
                }
            }
        }
Example #8
0
        private void DrawInitialHands(Game game)
        {
            Random random = new Random();
            var remainingCards = CardDefinitions.Deck.ToList();

            foreach (var player in GetPlayersInGame(game))
            {
                for (int i = 0; i < 5; i++)
                {
                    int listIndex = random.Next(remainingCards.Count);

                    DrawCard(game, player.User, remainingCards[listIndex]);
                    remainingCards.RemoveAt(listIndex);
                }
            }
        }
Example #9
0
        private TeamState GetTeamState(Game game, int teamIndex)
        {
            if (teamIndex == 0)
            {
                return null;
            }

            var teams = game.PlayerGame
                .Select(pg => pg.Team)
                .Distinct()
                .ToArray();

            if (!teams.Contains(teamIndex))
            {
                return null;
            }

            var cardsPlayedOnTeam = game.GameEvent
                .Where(ge => ge.Type == GameEventType.PLAY_CARD)
                .Cast<PlayCardEvent>()
                .Where(pc => pc.TargetTeamIndex == teamIndex)
                .ToList()
                .Join(
                    CardDefinitions.Cards,
                    pc => pc.DrawCardEvent.CardIndex,
                    cd => cd.CardId,
                    (pc, cd) => Tuple.Create(pc, cd)
                )
                .OrderByDescending(x => x.Item1.GameEventId);

            var teamState = new TeamState()
            {
                TeamIndex = teamIndex
            };

            teamState.HasAccident = IsTeamUnderEffect(
                cardsPlayedOnTeam,
                EffectCardType.ACCIDENT
            );

            teamState.IsOutOfFuel = IsTeamUnderEffect(
                cardsPlayedOnTeam,
                EffectCardType.FUEL
            );

            teamState.HasFlatTire = IsTeamUnderEffect(
                cardsPlayedOnTeam,
                EffectCardType.TIRE
            );

            teamState.IsUnderSpeedLimit = IsTeamUnderEffect(
                cardsPlayedOnTeam,
                EffectCardType.SPEED_LIMIT
            );

            ComputePlayedCardEffects(cardsPlayedOnTeam, teamState);
            bool accidentPlayed = teamState.PlayedCardEffects.HasFlag(EffectCardType.ACCIDENT);
            bool outOfFuelPlayed = teamState.PlayedCardEffects.HasFlag(EffectCardType.FUEL);
            bool flatTirePlayed = teamState.PlayedCardEffects.HasFlag(EffectCardType.TIRE);

            // Une équipe peut partir si elle a joué un feu vert.
            // Elle doit aussi, pour chaque effet dans [accident, essence, pneus],
            // avoir joué la carte qui la contre si une carte d'effet négatif
            // a été jouée contre l'équipe (les trois ifs).
            //
            // Le booléen détermine aussi si une carte feu vert peut être jouée,
            // les ifs évitent qu'un feu vert peut être joué lorsqu'il y a bris
            // non-réglé.
            //
            teamState.CanGo = IsTeamUnderEffect(
                cardsPlayedOnTeam,
                EffectCardType.TRAFFIC_LIGHT
            );

            if (accidentPlayed)
            {
                if (teamState.HasAccident)
                {
                    teamState.CanGo = false;
                }
            }
            if (outOfFuelPlayed)
            {
                if (teamState.IsOutOfFuel)
                {
                    teamState.CanGo = false;
                }
            }
            if (flatTirePlayed)
            {
                if (teamState.HasFlatTire)
                {
                    teamState.CanGo = false;
                }
            }

            // Une équipe ne peut partir immédiatement après un bris.
            if (teamState.CanGo)
            {
                var cardsPlayedOnTeamWithOrder = cardsPlayedOnTeam
                    .OrderBy(tu => tu.Item1.GameEventId)
                    .Select((tu, inx) => Tuple.Create(tu.Item1, tu.Item2, inx));

                var lastAccident = GetLastCardEffectPlayedForTeam(
                    cardsPlayedOnTeamWithOrder,
                    EffectCardType.ACCIDENT
                );
                var lastFuel = GetLastCardEffectPlayedForTeam(
                    cardsPlayedOnTeamWithOrder,
                    EffectCardType.FUEL
                );
                var lastTire = GetLastCardEffectPlayedForTeam(
                    cardsPlayedOnTeamWithOrder,
                    EffectCardType.TIRE
                );

                var lastLight = GetLastCardEffectPlayedForTeam(
                    cardsPlayedOnTeamWithOrder,
                    EffectCardType.TRAFFIC_LIGHT
                );

                if (lastAccident != null && lastAccident.Item3 > lastLight.Item3)
                {
                    teamState.CanGo = false;
                }
                if (lastFuel != null && lastFuel.Item3 > lastLight.Item3)
                {
                    teamState.CanGo = false;
                }
                if (lastTire != null && lastTire.Item3 > lastLight.Item3)
                {
                    teamState.CanGo = false;
                }
            }

            teamState.IsBrokenDown = teamState.CurrentlyBrokenDown;

            teamState.DistanceTraveled = cardsPlayedOnTeam
                .Where(x => x.Item2.CardType == CardType.VALUE)
                .Sum(x => x.Item2.Value);

            CalculateInvincibility(cardsPlayedOnTeam, teamState);

            return teamState;
        }
Example #10
0
        private TeamState[] GetTeamsState(Game game)
        {
            var teams = game.PlayerGame
               .Select(pg => pg.Team)
               .Distinct()
               .ToArray();

            TeamState[] teamStates = new TeamState[teams.Length];

            int index = 0;
            foreach (var team in teams)
            {
                teamStates[index] = GetTeamState(game, team);
                index++;
            }

            return teamStates;
        }
Example #11
0
        private User GoToNextPlayer(Game game)
        {
            var playerHands = GetAllPlayersHands(game);
            if (playerHands.All(x => x.Item2.Count == 0))
            {
                throw new Exception("Impossible de passer au prochain joueur comme toutes les cartes ont été jouées.");
            }

            var players = GetPlayersInGame(game)
                .OrderBy(pg => pg.Order)
                .ToArray();

            var playersWithHands = players
                .Join(playerHands,
                    pg => pg.UserId,
                    x => x.Item1,
                    (pg, x) => Tuple.Create(pg, x.Item2)
                )
                .ToArray();

            var currentPlayerId = GetCurrentPlayerUserId(game);

            var newPlayerIndex = players
                .Select((pg, inx) => new { pg, inx })
                .Single(x => x.pg.UserId == currentPlayerId)
                .inx;
            newPlayerIndex = (newPlayerIndex + 1) % playersWithHands.Length;

            var newPlayer = playersWithHands[newPlayerIndex];

            // Trouver un joueur qui a des cartes à jouer, sinon le jeu va
            // attendre qu'il joue une carte dans une main vide.
            while (newPlayer.Item2.Count == 0)
            {
                newPlayerIndex = (newPlayerIndex + 1) % playersWithHands.Length;
                newPlayer = playersWithHands[newPlayerIndex];
            }

            ChangePlayer(game, newPlayer.Item1.UserId);
            return newPlayer.Item1.User;
        }
Example #12
0
        private User GetCurrentPlayer(Game game)
        {
            var lastPlayerChangeEvent = GetLastPlayerChangeEvent(game);

            return lastPlayerChangeEvent.User;
        }
Example #13
0
        private int GetCurrentPlayerUserId(Game game)
        {
            var lastPlayerChangeEvent = GetLastPlayerChangeEvent(game);

            return lastPlayerChangeEvent.NewPlayerId;
        }
Example #14
0
 private PlayerChangeEvent GetLastPlayerChangeEvent(Game game)
 {
     return game.GameEvent
         .Where(ge => ge.Type == GameEventType.PLAYER_CHANGE)
         .Cast<PlayerChangeEvent>()
         .OrderByDescending(ge => ge.GameEventId)
         .FirstOrDefault();
 }
Example #15
0
 /// <summary>
 /// Obtient les joueurs qui sont connectés, soit ceux que leur ordre est positif.
 /// 
 /// Les joueurs déconnectés dans une partie qui continue ont comme ordre
 /// la valeur négative de celle-ci.
 /// </summary>
 /// <param name="game"></param>
 /// <returns></returns>
 private IEnumerable<PlayerGame> GetPlayersInGame(Game game)
 {
     return game.PlayerGame
         .Where(pg => pg.Order >= 0);
 }
Example #16
0
        private void DrawCard(Game game, User user, int cardId)
        {
            game.GameEvent.Add(new DrawCardEvent()
            {
                ServerEvent = true,
                Date = DateTime.UtcNow,
                Type = GameEventType.DRAW_CARD,

                CardIndex = cardId,
                Token = Guid.NewGuid(),
                User = user
            });
        }
Example #17
0
        private void InitializeGame(Game game)
        {
            DrawInitialHands(game);

            var firstPlayer = GetPlayersInGame(game)
                .OrderBy(pg => pg.Order)
                .FirstOrDefault();

            ChangePlayer(game, firstPlayer.UserId);
        }
Example #18
0
        private void PlayCardInGame(Game game, DrawCardEvent drawEvent, int targetTeamIndex)
        {
            game.GameEvent.Add(new PlayCardEvent()
            {
                ServerEvent = false,
                Date = DateTime.UtcNow,
                Type = GameEventType.PLAY_CARD,

                TargetTeamIndex = targetTeamIndex,
                DrawCardEventId = drawEvent.GameEventId
            });
        }
Example #19
0
        private bool CheckAllPlayersHeartbeat(Game game)
        {
            if (GetPlayersInGame(game)
                .Where(pg => pg.HasJoined)
                .Any(pg => !ValidatePlayerHeartbeat(pg)))
            {
                // S'assurer qu'il reste plus d'un joueur, sinon terminer la partie.
                if (GetPlayersInGame(game)
                    .Where(pg => pg.HasJoined)
                    .Where(pg => ValidatePlayerHeartbeat(pg))
                    .Count() <= 1)
                {
                    EndGame(game, GameEndReason.PLAYER_DISCONNECTION);

                    return false;
                }

                var masterPlayerId = game.Room.First().MasterUserId;

                // S'assurer que le maître de la salle est présent pour prendre
                // la décision, sionon terminer la partie aussi.
                if (GetPlayersInGame(game)
                    .Where(pg => pg.HasJoined)
                    .Where(pg => ValidatePlayerHeartbeat(pg))
                    .Where(pg => pg.UserId == masterPlayerId)
                    .Count() != 1)
                {
                    EndGame(game, GameEndReason.PLAYER_DISCONNECTION);

                    return false;
                }

                game.IsTakingDisconnectDecision = true;
                return false;
            }

            return true;
        }
Example #20
0
        private int[] GetRemainingCards(Game game)
        {
            var deck = CardDefinitions.Deck.ToList();

            var playedCards = game.GameEvent
                .Where(ge => ge.Type == GameEventType.DRAW_CARD)
                .Cast<DrawCardEvent>();

            foreach (var card in playedCards)
            {
                deck.Remove(card.CardIndex);
            }

            return deck.ToArray();
        }
Example #21
0
        private void DrawNewCardToPlayer(Game game, User user)
        {
            var remainingDeck = GetRemainingCards(game);

            if (remainingDeck.Length <= 0)
            {
                return;
            }

            Random random = new Random();
            int listIndex = random.Next(remainingDeck.Length);
            DrawCard(game, user, remainingDeck[listIndex]);
        }