Data object containing information about a player in the game
Ejemplo n.º 1
0
 public MainActions(Player player, GameController controller)
 {
     this.player = player;
     this.controller = controller;
     valid = true;
     this.hasPlayedDevCard = false;
     this.isAfterDieRoll = false;
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Let a player build a road without a requirement for connectivity and free of charge
        /// The road may not be placed on top of another road
        /// Connectivity with previously placed settlement should be controlled elsewhere (in StartActions.cs)
        /// </summary>
        /// <param name="player">The player placing the road</param>
        /// <param name="edge">The edge to build the road on</param>
        public GameState BuildFirstRoad(Player player, Edge edge)
        {
            if (board.GetRoad(edge) != -1)
                throw new IllegalBuildPositionException("The chosen position is occupied by another road");
            if (!board.CanBuildRoad(edge))
                throw new IllegalBuildPositionException("The chosen position is not valid");

            player.RoadsLeft--;
            board = board.PlaceRoad(edge, player.Id);
            return CurrentGamestate();
        }
Ejemplo n.º 3
0
 public GameState(IBoard board, List<DevelopmentCard> deck, int[] resourceBank, Player[] players, int curPlayer, List<LogEvent> log, int longestRoad, int largestArmy)
 {
     Board = board;
     DevelopmentCards = deck == null ? 0 : deck.Count;
     ResourceBank = resourceBank == null ? null : resourceBank.ToArray();
     this.players = players;
     this.curPlayer = curPlayer;
     this.log = log;
     if (players == null) players = new Player[0];
     AllPlayerIds = players.Select(p => p.Id).ToArray();
     LongestRoadId = longestRoad;
     LargestArmyId = largestArmy;
 }
Ejemplo n.º 4
0
        /// <summary>
        /// Let a player upgrade a settlement to a city
        /// If the player doesn't have enough resources to build a city a InsufficientResourcesException is thrown
        /// If the player tries to build at a position where he doesn't have a settlement a IllegalBuildPosition is thrown
        /// If the player doesn't have any more city pieces left to place a IllegalActionException is thrown
        /// The required resources are taken from the player and placed back at the resource bank
        /// The settlement previously on the location is given back to the player
        /// </summary>
        /// <param name="player">The player upgrading to a city</param>
        /// <param name="intersection">The intersection to upgrade to a city on</param>
        /// <returns></returns>
        public GameState BuildCity(Player player, Intersection intersection)
        {
            var r = player.Resources;
            if (!(r.Count(c => c == Resource.Ore) >= 3 && r.Count(c => c == Resource.Grain) >= 2))
                throw new InsufficientResourcesException("Not enough resources to buy a city");
            if (player.CitiesLeft == 0)
                throw new IllegalActionException("No more city pieces left of your color");

            Piece piece = board.GetPiece(intersection);
            if (piece == null || piece.Player != player.Id || piece.Token != Token.Settlement)
                throw new IllegalBuildPositionException("The chosen position does not contain one of your settlements");

            PayResource(player, Resource.Ore, 3);
            PayResource(player, Resource.Grain, 2);

            Log(new BuildPieceLogEvent(player.Id, Token.City, intersection));

            player.CitiesLeft--;
            player.SettlementsLeft++;

            board = board.PlacePiece(intersection, new Piece(Token.City, player.Id));
            return CurrentGamestate();
        }
Ejemplo n.º 5
0
        public GameState CompleteTrade(Player player, int playerid)
        {
            if (!proposedTrades.ContainsKey(player.Id))
                throw new IllegalActionException("Tried to complete a trade, but no trade proposed");
            if (!proposedTrades[player.Id].ContainsKey(playerid) || playerid < 0 || playerid >= players.Length)
                throw new IllegalActionException("Tried to complete a trade with an illegal player Id");

            var trade = proposedTrades[player.Id][playerid]; //remember that the trade is as seen from the opponents pov
            var opponent = players[playerid];
            if (trade.Status == TradeStatus.Declined)
                throw new IllegalActionException("Tried to complete a declined trade");

            //Validate trade

            if (trade.Give.Count > 1 || trade.Take.Count > 1)
            {
                throw new IllegalActionException("Player " + player.Id + "(" +  player.Agent.GetName() + ") tried to complete an invalid trade with Player " + opponent.Id + "(" +  opponent.Agent.GetName() + ")");
            }
            //Validate that players have enough resources (maybe do this earlier?)

            foreach (Resource resource in Enum.GetValues(typeof(Resource)))
            {
                //Give - other must have
                if (trade.Give[0].Count(r => r == resource) > opponent.Resources.Count(r => r == resource))
                    throw new InsufficientResourcesException("Player " + opponent.Id + "(" +  opponent.Agent.GetName() + ") does not have enough resource to complete trade");
                //Take - this must have
                if (trade.Take[0].Count(r => r == resource) > player.Resources.Count(r => r == resource))
                    throw new InsufficientResourcesException("Player " + player.Id + "(" + player.Agent.GetName() + ") does not have enough resource to complete trade");
            }

            //Complete trade
            foreach (var res in trade.Give[0])
            {
                opponent.Resources.Remove(res);
                player.Resources.Add(res);
            }
            foreach (var res in trade.Take[0])
            {
                player.Resources.Remove(res);
                opponent.Resources.Add(res);
            }

            Log(new AcceptTradeLogEvent(player.Id, playerid, trade.Give[0], trade.Take[0]));

            return CurrentGamestate();
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Let a player move the robber to a new location and draw a random card from a player with a building on the tile
        /// If the agent moves the robber to a water tile or the tile that it was already on, nothing will happen
        /// If the agent tries to draw a card from a unaffected player, no cards will be drawn
        /// </summary>
        /// <param name="player">The player that must move the robber</param>
        /// <param name="gameState">The gamestate to send to the player</param>
        private void MoveRobber(Player player, GameState gameState)
        {
            int robberPosition = player.Agent.MoveRobber(gameState);
            if (board.GetTile(robberPosition).Terrain == Terrain.Water || robberPosition == board.GetRobberLocation())
            {
                Console.WriteLine("IAgent " + player.Agent.GetType().Name + " moved robber illegally");
                throw new AgentActionException("Agent " + player.Agent.GetType().Name + " moved robber illegally", true);
            }
            board = board.MoveRobber(robberPosition);

            Log(new MoveRobberLogEvent(player.Id, robberPosition));
            //Draw a card from an opponent
            var opponents = new List<int>();
            foreach (var piece in board.GetPieces(robberPosition))
            {
                if (piece.Player == player.Id) continue;
                if (opponents.Contains(piece.Player)) continue;
                opponents.Add(piece.Player);
            }
            if (opponents.Count == 0) return; //No opponents to draw from
            int choice = player.Agent.ChoosePlayerToDrawFrom(CurrentGamestate(), opponents.ToArray());

            if (!opponents.Contains(choice))
            {
                Console.WriteLine("IAgent " + player.Agent.GetType().Name + " chose an illegal player to draw from");
                return;
            }

            if (players[choice].Resources.Count == 0) return; //Nothing to take

            Log(new StealCardLogEvent(player.Id, choice));

            //Move a card from one player to another
            var position = shuffleRandom.Next(players[choice].Resources.Count);
            var toMove = players[choice].Resources[position];
            players[choice].Resources.RemoveAt(position);
            player.Resources.Add(toMove);
        }
Ejemplo n.º 7
0
 /// <summary>
 /// Let a given player pay an amount of a resource to the bank
 /// </summary>
 /// <param name="player">The player that must pay</param>
 /// <param name="resource">The type of resource to pay</param>
 /// <param name="quantity">The quantity of the resource to pay (default 1)</param>
 private void PayResource(Player player, Resource resource, int quantity = 1)
 {
     for (int i = 0; i < quantity; i++)
     {
         if (!player.Resources.Contains(resource)) throw new InsufficientResourcesException("Player out of " + resource);
         player.Resources.Remove(resource);
         resourceBank[(int)resource]++;
     }
 }
Ejemplo n.º 8
0
 /// <summary>
 /// Give a player an amount of some resource
 /// If there are no more cards in the pile an NoMoreCardsException is thrown
 /// </summary>
 /// <param name="player">The player to give resources to</param>
 /// <param name="resource">The type of resource he receives</param>
 /// <param name="quantity">The amount of the resource he receives (default 1)</param>
 private void GetResource(Player player, Resource resource, int quantity = 1)
 {
     for (int i = 0; i < quantity; i++)
     {
         if (resourceBank[(int)resource] == 0) throw new NoMoreCardsException("Resource bank is out of " + resource.ToString());
         player.Resources.Add(resource);
         resourceBank[(int)resource]--;
     }
 }
Ejemplo n.º 9
0
 /// <summary>
 /// Find out if a given player has won (if his number of victory points is over or equal to 10)
 /// </summary>
 /// <param name="player">The player to test</param>
 /// <returns>True if the player has 10 or more victory points</returns>
 private Boolean HasWon(Player player)
 {
     return (GetPoints(player) >= 10);
 }
Ejemplo n.º 10
0
 public StartActions(Player player, GameController controller)
 {
     this.player = player;
     this.controller = controller;
 }
Ejemplo n.º 11
0
        /// <summary>
        /// Let a player play a knight development card
        /// If the player doesn't have a knight on his hand a InsufficientResourcesException is thrown
        /// A knight is removed from the players hand
        /// The largest army special card is relocated if playing this knight causes it to be
        /// </summary>
        /// <param name="player">The player playing a knight</param>
        public GameState PlayKnight(Player player)
        {
            var playable = GetPlayableDevelopmentCards(player);
            if (!playable.Contains(DevelopmentCard.Knight))
                throw new InsufficientResourcesException("No knight found in hand");

            player.DevelopmentCards.Remove(DevelopmentCard.Knight);
            player.PlayedKnights++;
            if (player.PlayedKnights > largestArmySize)
            {
                largestArmySize = player.PlayedKnights;
                largestArmyId = player.Id;
            }

            MoveRobber(player, CurrentGamestate());

            Log(new PlayKnightLogEvent(player.Id));

            return CurrentGamestate();
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Trade resources with the bank
        /// If no harbor is owned trading is 4 : 1
        /// If a general harbor is owned trading is 3 : 1
        /// Special harbors trade a specific resource 2 : 1
        /// </summary>
        /// <param name="player">The player wanting to trade</param>
        /// <param name="giving">The resource that the player want to give</param>
        /// <param name="receiving">The resource that the player want to receive</param>
        /// <returns>The updated gamestate after trading</returns>
        public GameState TradeBank(Player player, Resource giving, Resource receiving)
        {
            if (resourceBank[(int)receiving] == 0)
                throw new NoMoreCardsException("Resource bank has no more resources of type " + receiving);

            var harbors = board.GetPlayersHarbors(player.Id);
            var hasSpecific = harbors.Contains((HarborType) giving);
            var hasGeneral = harbors.Contains(HarborType.ThreeForOne);

            var amountToGive = (hasSpecific) ? 2 : ((hasGeneral) ? 3 : 4);

            if (player.Resources.Count(r => r == giving) < amountToGive)
                throw new InsufficientResourcesException("Player hasn't got enough resources to trade");

            PayResource(player,giving,amountToGive);
            GetResource(player,receiving);

            Log(new TradeBankLogEvent(player.Id,giving,amountToGive,receiving));

            return CurrentGamestate();
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Let a player build a road
        /// If the player doesn't have enough resources to build a road an InsufficientResourcesException is thrown
        /// If the player tries to build at a position not connected to another road, settlement or city an IllegalBuildPositionException is thrown
        /// If the player doesn't have any more road pieces left to place an IllegalActionException is thrown
        /// </summary>
        /// <param name="player">The player building a road</param>
        /// <param name="edge">The to build a road on</param>
        /// <returns></returns>
        public GameState BuildRoad(Player player, Edge edge)
        {
            var r = player.Resources;
            if (!(r.Contains(Resource.Brick) && r.Contains(Resource.Lumber)))
                throw new InsufficientResourcesException("Not enough resources to buy a road");
            if (player.RoadsLeft == 0)
                throw new IllegalActionException("No more road pieces left of your color");
            if (board.GetRoad(edge) != -1)
                throw new IllegalBuildPositionException("The chosen position is occupied by another road");
            if (!RoadConnected(board, edge, player.Id))
                throw new IllegalBuildPositionException("The chosen position is not connected to any of your pieces");
            if (!board.CanBuildRoad(edge))
                throw new IllegalBuildPositionException("The chosen position is not valid");

            PayResource(player, Resource.Brick);
            PayResource(player, Resource.Lumber);

            Log(new BuildRoadLogEvent(player.Id, edge));

            player.RoadsLeft--;
            board = board.PlaceRoad(edge, player.Id);
            UpdateLongestRoad();
            return CurrentGamestate();
        }
Ejemplo n.º 14
0
        public Dictionary<int, ITrade> ProposeTrade(Player player, List<List<Resource>> give, List<List<Resource>> take)
        {
            var trade = new Trade(give, take);

            var dict = new Dictionary<int, Trade>(); //Reversed trades
            var replyDict = new Dictionary<int, ITrade>();

            Log(new ProposeTradeLogEvent(player.Id, trade.Give, trade.Take));

            var state = CurrentGamestate();

            foreach (var other in players)
            {
                if (other.Id == player.Id) continue; //No need to propose a trade with yourself
                dict[other.Id] = (Trade)other.Agent.HandleTrade(state, trade.Reverse(), player.Id);
                if (dict[other.Id].Status == TradeStatus.Countered)
                {
                    replyDict[other.Id] = dict[other.Id].Reverse();
                    //Note, take and give are swapped since dict[other.Id] is as seen from the opponent
                    var giveLog = dict[other.Id].Take.Where(c => c.Count > 0).Select(r => r[0]).ToList();
                    var takeLog = dict[other.Id].Give.Where(c => c.Count > 0).Select(r => r[0]).ToList();
                    Log(new CounterTradeLogEvent(other.Id, giveLog, takeLog));
                    break;
                }
            }
            proposedTrades[player.Id] = dict;

            return replyDict;
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Start the game. This method will run for the length of the game and returns the id of the winner
        /// </summary>
        /// <param name="agents">The competing agents (The order in which they are submitted is irrelevant)</param>
        /// <param name="boardSeed">The seed for the board generator, used to shuffle development cards, and for drawing a random card after moving the robber</param>
        /// <param name="diceSeed">The seed for the dice</param>
        /// <param name="visual">True if the game should be displayed visually</param>
        /// <param name="visual">True if the game should save the game log to a file</param>
        /// <returns>The id of the winner of the game (-1 in case of error)</returns>
        public int StartGame(IAgent[] agents, int boardSeed, int diceSeed, bool visual, bool logToFile)
        {
            this.visual = visual;
            this.logToFile = logToFile;

            //Initialize random number generators
            diceRandom = new Random(diceSeed);
            shuffleRandom = new Random(boardSeed); //The card deck is based on the seed of the board

            //Build player list
            players = new Player[agents.Length];
            for (int i = 0; i < agents.Length; i++)
            {
                players[i] = new Player(agents[i], i);
            }

            //Set up board
            board = new Board(boardSeed);
            PopulateDevelopmentCardStack();
            resourceBank = new int[] { 19, 19, 19, 19, 19 };

            //Start the game!
            turn = 0;

            //StartGUI();
            if (visual)
            {
                Thread guiThread = new Thread(StartGUI);
                guiThread.Start();
                Thread.Sleep(5000);
            }

            PlaceStarts();
            int result = GameLoop();
            if (logToFile) System.IO.File.WriteAllLines(DateTime.Now.ToString("s").Replace(":","").Replace("-","")+" GameLog.txt", log.Select(l => l.ToString()));

            return result;
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Let a player play a year of plenty development card
        /// If the player doesn't have a YearOfPlenty card on his hand a InsufficientResourcesException is thrown
        /// If the resource bank doesn't have enough cards to fulfill the request a NoMoreCardsException is thrown
        /// </summary>
        /// <param name="player">The player playing the year of plenty development card</param>
        /// <param name="resource1">The type of resource for the first card</param>
        /// <param name="resource2">The type of resource for the second card</param>
        public GameState PlayYearOfPlenty(Player player, Resource resource1, Resource resource2)
        {
            var playable = GetPlayableDevelopmentCards(player);
            if (resourceBank[(int)resource1] == 0) throw new NoMoreCardsException("Resource bank is out of " + resource1);
            if (resourceBank[(int)resource2] == 0) throw new NoMoreCardsException("Resource bank is out of " + resource2);
            if (!playable.Contains(DevelopmentCard.YearOfPlenty)) throw new InsufficientResourcesException("No Year of Plenty found in hand");

            player.DevelopmentCards.Remove(DevelopmentCard.YearOfPlenty);
            GetResource(player, resource1);
            GetResource(player, resource2);

            Log(new PlayYearOfPlentyLogEvent(player.Id, resource1, resource2));

            return CurrentGamestate();
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Let a player play a road building development card
        /// If the player doesn't have a RoadBuilding card on his hand a InsufficientResourcesException is thrown
        /// If the player doesn't have any road pieces left a IllegalActionException is thrown
        /// If the player tries to place a road at a position where a road is already present a IllegalBuildPositionException is thrown
        /// If the player only has one road piece left, the position to place it must be passed as road1Tile1, road1Tile2 (the others are ignored)
        /// </summary>
        /// <param name="player">The player that plays the RoadBuilding development card</param>
        /// <param name="firstRoad">The first edge to build a road on</param>
        /// <param name="secondRoad">The second edge to build a road on</param>
        public GameState PlayRoadBuilding(Player player, Edge firstRoad, Edge secondRoad)
        {
            var playable = GetPlayableDevelopmentCards(player);
            if (!playable.Contains(DevelopmentCard.RoadBuilding)) throw new InsufficientResourcesException("No Road building found in hand");
            if (player.RoadsLeft == 0) throw new IllegalActionException("No more road pieces left of your color");

            //Must always check road1
            if (!board.CanBuildRoad(firstRoad))
                throw new IllegalBuildPositionException("The chosen position is illegal or occupied");
            if (board.GetRoad(firstRoad) != -1)
                throw new IllegalBuildPositionException("There is already a road on the selected position");

            if (player.RoadsLeft == 1)
            {
                if (!RoadConnected(board, firstRoad, player.Id))
                    throw new IllegalBuildPositionException("The chosen position is not connected to any of your pieces");

                player.RoadsLeft--;
                board = board.PlaceRoad(firstRoad, player.Id);
                Log(new PlayRoadBuildingLogEvent(player.Id, firstRoad));
            }
            else
            {
                //Check road 2
                if (!board.CanBuildRoad(secondRoad))
                    throw new IllegalBuildPositionException("The chosen position is illegal or occupied");
                if (board.GetRoad(secondRoad) != -1)
                    throw new IllegalBuildPositionException("There is already a road on the selected position");

                //Can't build the same road twice
                if ((firstRoad.FirstTile == secondRoad.FirstTile && firstRoad.SecondTile == secondRoad.SecondTile) || (firstRoad.FirstTile == secondRoad.SecondTile && firstRoad.SecondTile == secondRoad.FirstTile))
                    throw new IllegalBuildPositionException("Can't build the same road twice (roadbuilding dev. card)");

                //Place the connected road first (to be able to check that both are connected in the end
                if (RoadConnected(board, firstRoad, player.Id))
                {
                    var temp = board.PlaceRoad(firstRoad, player.Id);
                    if (RoadConnected(temp, secondRoad, player.Id))
                    {
                        board = temp.PlaceRoad(secondRoad, player.Id);
                        player.RoadsLeft -= 2;
                    }
                }
                else if (RoadConnected(board, secondRoad, player.Id))
                {
                    var temp = board.PlaceRoad(secondRoad, player.Id);
                    if (RoadConnected(temp, firstRoad, player.Id))
                    {
                        board = temp.PlaceRoad(firstRoad, player.Id);
                        player.RoadsLeft -= 2;
                    }
                }
                else
                {
                    throw new IllegalBuildPositionException("The chosen positions are not connected to any of your buildings or roads");
                }
                Log(new PlayRoadBuildingLogEvent(player.Id, firstRoad, secondRoad));
            }

            player.DevelopmentCards.Remove(DevelopmentCard.RoadBuilding);
            UpdateLongestRoad();
            return CurrentGamestate();
        }
Ejemplo n.º 18
0
        /// <summary>
        /// Let a player play a Monopoly development card
        /// If the player doesn't have a Monopoly card on his hand a InsufficientResourcesException is thrown
        /// All resources of the given type is removed from players hands and all given to the playing player
        /// </summary>
        /// <param name="player">The player playing the monopoly development card</param>
        /// <param name="resource">The resource to get monopoly on</param>
        /// <returns></returns>
        public GameState PlayMonopoly(Player player, Resource resource)
        {
            var playable = GetPlayableDevelopmentCards(player);
            if (!playable.Contains(DevelopmentCard.Monopoly)) throw new InsufficientResourcesException("No Monopoly in hand");
            player.DevelopmentCards.Remove(DevelopmentCard.Monopoly);
            //Take all resources of the given type out of all hands
            int count = players.Sum(t => t.Resources.RemoveAll(c => c == resource));
            //And place them in the playing players hand
            for (int i = 0; i < count; i++)
            {
                player.Resources.Add(resource);
            }

            Log(new PlayMonopolyLogEvent(player.Id, resource, count));

            return CurrentGamestate();
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Executes all parts of a players turn
        ///     1. Allow the play of a development card before the dice are rolled
        ///     2. Roll the dice, hand out resources to all players, and move the robber if roll is 7
        ///     3. Allow all actions according to the rules
        /// </summary>
        /// <param name="player">The player whose turn it is</param>
        private void TakeTurn(Player player)
        {
            var actions = new MainActions(player, this);
            player.Agent.BeforeDiceRoll(CurrentGamestate(), actions);

            int roll = RollDice();
            actions.DieRoll();
            Log(new RollLogEvent(player.Id,roll));

            if (roll == 7)
            {
                //Discard if over 7 cards
                foreach (var p in players)
                {
                    if (p.Resources.Count > 7)
                    {
                        var cards = p.Agent.DiscardCards(CurrentGamestate(p.Id), p.Resources.Count / 2);
                        if (cards.Length != p.Resources.Count / 2)
                        {
                            //Clone, shuffle, take, convert
                            cards = p.Resources.ToList().OrderBy(e => Guid.NewGuid()).Take(p.Resources.Count / 2).ToArray();
                        }
                        foreach (var c in cards)
                        {
                            PayResource(p, c);
                        }
                        Log(new DiscardCardsLogEvent(p.Id,cards.ToList()));
                    }
                }
                MoveRobber(player, CurrentGamestate());
            }
            else
            {
                HandOutResources(roll);
            }
            var afterResourcesState = CurrentGamestate();
            player.Agent.PerformTurn(afterResourcesState, actions);

            player.NewDevelopmentCards.Clear(); //Reset new development cards
        }
Ejemplo n.º 20
0
 /// <summary>
 /// Get a list of playable development cards for a given player
 /// Newly bought development cards cannot be played in the same round
 /// </summary>
 /// <param name="player">The player for whom to get the list of playable development cards</param>
 /// <returns>The list of playable development cards</returns>
 private List<DevelopmentCard> GetPlayableDevelopmentCards(Player player)
 {
     var playable = new List<DevelopmentCard>();
     foreach (var card in player.DevelopmentCards)
     {
         if (player.NewDevelopmentCards.Contains(card))
         {
             player.NewDevelopmentCards.Remove(card);
         }
         else
         {
             playable.Add(card);
         }
     }
     return playable;
 }
Ejemplo n.º 21
0
        /// <summary>
        /// Let a player build a settlement
        /// If the player doesn't have enough resources to build a settlement a InsufficientResourcesException is thrown
        /// If the player tries to build too close to another building, or not connected to a road a IllegalBuildPosition is thrown
        /// If the player doesn't have any more settlement pieces left to place a IllegalActionException is thrown
        /// The required resources are taken from the player and placed back at the resource bank
        /// If the settlement is placed at a harbor, the harbor can be used immediately (rules p. 7 - footnote 12)
        /// </summary>
        /// <param name="player">The player building a settlement</param>
        /// <param name="inter">The intersection to build a settlement on</param>
        /// <returns></returns>
        public GameState BuildSettlement(Player player, Intersection inter)
        {
            var r = player.Resources;
            if (!(r.Contains(Resource.Grain) && r.Contains(Resource.Wool) && r.Contains(Resource.Brick) && r.Contains(Resource.Lumber)))
                throw new InsufficientResourcesException("Not enough resources to buy a settlement");
            if (player.SettlementsLeft == 0)
                throw new IllegalActionException("No more settlement pieces left of your color");
            if (board.GetPiece(inter) != null)
                throw new IllegalBuildPositionException("The chosen position is occupied by another building");
            if (!board.HasNoNeighbors(inter))
                throw new IllegalBuildPositionException("The chosen position violates the distance rule");
            if (board.GetRoad(new Edge(inter.FirstTile,inter.SecondTile)) != player.Id
                && board.GetRoad(new Edge(inter.FirstTile,inter.ThirdTile)) != player.Id
                && board.GetRoad(new Edge(inter.SecondTile, inter.ThirdTile)) != player.Id)
                throw new IllegalBuildPositionException("The chosen position has no road leading to it");

            if (!board.CanBuildPiece(inter))
                throw new IllegalBuildPositionException("The chosen position is not valid");

            PayResource(player, Resource.Grain);
            PayResource(player, Resource.Wool);
            PayResource(player, Resource.Brick);
            PayResource(player, Resource.Lumber);

            Log(new BuildPieceLogEvent(player.Id, Token.Settlement, inter));

            player.SettlementsLeft--;
            board = board.PlacePiece(inter, new Piece(Token.Settlement, player.Id));
            UpdateLongestRoad();
            return CurrentGamestate();
        }
Ejemplo n.º 22
0
        /// <summary>
        /// Find out how many victory points a given player has
        /// Points are counted as:
        ///     Settlements give 1 point each
        ///     Cities give 2 points each
        ///     Victory point development cards give 1 point each
        ///     Having the largest army or the longest road give 2 points each.
        /// </summary>
        /// <param name="player">The player to test</param>
        /// <returns>How many victory points the player has</returns>
        private int GetPoints(Player player)
        {
            int points = 0;
            points += (5 - player.SettlementsLeft) * 1;
            points += (4 - player.CitiesLeft) * 2;

            points += player.DevelopmentCards.Count(c => c == DevelopmentCard.VictoryPoint) * 1;

            if (player.Id == largestArmyId) points += 2;
            if (player.Id == longestRoadId) points += 2;

            return points;
        }
Ejemplo n.º 23
0
        /// <summary>
        /// Let a player build a settlement without a requirement for connectivity and free of charge
        /// The settlement still has to follow the distance rule and cannot be placed on top of another building
        /// </summary>
        /// <param name="player">The player placing the settlement</param>
        /// <param name="intersection">The intersection to build a settlement on</param>
        public GameState BuildFirstSettlement(Player player, Intersection intersection)
        {
            if (board.GetPiece(intersection) != null)
                throw new IllegalBuildPositionException("The chosen position is occupied by another building");
            if (!board.HasNoNeighbors(intersection))
                throw new IllegalBuildPositionException("The chosen position violates the distance rule");
            if (!board.CanBuildPiece(intersection))
                throw new IllegalBuildPositionException("The chosen position is not valid");

            player.SettlementsLeft--;
            board = board.PlacePiece(intersection, new Piece(Token.Settlement, player.Id));
            return CurrentGamestate();
        }
Ejemplo n.º 24
0
        /*
         * ACTIONS
         */
        /// <summary>
        /// Let a player draw a development card
        /// If the player doesn't have enough resources a InsufficientResourcesException is thrown
        /// If the development card stack is empty a NoMoreCardsException is thrown
        /// Resources to pay for the card are removed from the player hand and returned to the resource bank
        /// </summary>
        /// <param name="player">The player drawing a development card</param>
        /// <returns>The drawn development card</returns>
        public GameState DrawDevelopmentCard(Player player)
        {
            var r = player.Resources;
            if (!(r.Contains(Resource.Grain) && r.Contains(Resource.Wool) && r.Contains(Resource.Ore)))
                throw new InsufficientResourcesException("Not enough resources to buy a development card");

            if (developmentCardStack.Count == 0)
                throw new NoMoreCardsException("Development card stack is empty");

            PayResource(player, Resource.Grain);
            PayResource(player, Resource.Wool);
            PayResource(player, Resource.Ore);

            var last = developmentCardStack.Last();
            developmentCardStack.RemoveAt(developmentCardStack.Count-1);

            Log(new BuyDevLogEvent(player.Id));

            player.DevelopmentCards.Add(last);
            player.NewDevelopmentCards.Add(last);
            return CurrentGamestate();
        }