/// <summary> /// Set of client status information pushed at regular intervals /// </summary> /// <param name="g">The grid</param> /// <param name="p">The player</param> /// <param name="nei">Players neighborhood</param> /// <returns>A client status view</returns> public ClientView GetClientStatus(Grid g, Player p) { int blueCount; int yellowCount; if (p.PlayerType == 1) { blueCount = p.Neighborhood.OwnTypeCount; yellowCount = p.Neighborhood.OtherTypeCount; } else { blueCount = p.Neighborhood.OtherTypeCount; yellowCount = p.Neighborhood.OwnTypeCount; } var cv = new ClientView { Round = g.Round, OwnType = p.PlayerType, Move = p.RequestMove, TypeChange = p.RequestTypeChange, Timeout = p.HasTimeout, LastPayoff = p.LastPoints, TotalPayoff = p.GridPoints, BlueCount = blueCount, YellowCount = yellowCount, WhiteCount = p.Neighborhood.EmptyCount, OwnShare = p.Neighborhood.OwnShare.ToString("P1"), OtherShare = p.Neighborhood.OtherShare.ToString("P1"), CountDown = g.RoundTimer }; return cv; }
/// <summary> /// Adds a player on arrival /// </summary> /// <param name="accessCode">Access code of player</param> /// <param name="connectionId">Connection Id of player</param> /// <param name="connected">Connection status</param> /// <param name="isAdmin">True if admin connection, false if client</param> public void Add(string accessCode, string connectionId, bool connected, bool isAdmin, string ip, string browser, string transport) { var grid = db.Grids.FirstOrDefault(g => g.GridName.Equals("Lobby")); if (grid == null) throw new Exception("Lobby not found found"); var player = new Player { AccessCode = accessCode, ConnectionId = connectionId, Connected = connected, Ip = ip, Browser = browser, Transport = transport, IsAdmin = isAdmin, IsBot = false, IsZombie = false, PlayerNr = 0, PlayerType = 0, Round = 0, IsReady = false, HasTimeout = false, RequestMove = false, RequestTypeChange = false, Neighborhood = new Neighborhood(), LastPoints = 0, GridPoints = 0, TotalPoints = 0, GridWaitingTime = 0, TotalWaitingTime = 0, WaitingPayoff = 0, TotalPayoff = 0, StartTime = DateTime.Now, EndTime = DateTime.Now, StartLobby = DateTime.Now, LastUpdateTime = DateTime.Now, GridId = grid.GridId }; db.Add(player); }
/// <summary> /// Set of lobby or waiting room status information pushed at regular intervals /// </summary> /// <param name="g">The grid</param> /// <param name="player">The player</param> /// <param name="waitingPlayerCount">Number of players waiting</param> /// <param name="requiredPlayerCount">Number of players required for the next grid</param> /// <returns></returns> public LobbyView GetWaitingStatus(Grid g, Player player, int waitingPlayerCount, int requiredPlayerCount) { var now = DateTime.Now; var lobbyView = new LobbyView { ConnectionId = player.ConnectionId, AccessCode = player.AccessCode, ServerTime = now.ToString(), Workers = waitingPlayerCount, WorkersNeeded = requiredPlayerCount, WaitingTime = (now - player.StartLobby).ToString(@"mm\:ss"), HasBonus = g.HasWaitingBonus, WaitingBonus = db.Player.GetWaitingBonus(g, player.StartLobby) }; return lobbyView; }
/// <summary> /// Set of grid summary info displayed at the end of a grid /// </summary> /// <param name="g">The grid</param> /// <param name="p">The player</param> /// <returns>A grid summary view</returns> public GridSummaryView GetGridSummaryView(Grid g, Player p) { var gsv = new GridSummaryView { GridId = g.GridId, PlayerId = p.PlayerId, RoundCount = g.RoundCount, Moves = db.PlayerLogs.Count(pl => pl.GridId == g.GridId & pl.PlayerId == p.PlayerId & pl.RequestMove), TypeChanges = db.PlayerLogs.Count(pl => pl.GridId == g.GridId & pl.PlayerId == p.PlayerId & pl.RequestTypeChange), GridPoints = p.GridPoints, GridPayoff = Math.Round((double)p.GridPoints*g.ExchangeRate, 2), TotalPayoff = p.TotalPayoff, SummaryTimer = g.SummaryTimer }; return gsv; }
/// <summary> /// Remove a player from database /// </summary> public void Remove(Player player) { db.Players.Remove(player); db.SaveChanges(); }
/// <summary> /// Add a player to the database /// </summary> public void Add(Player player) { db.Players.Add(player); db.SaveChanges(); }
public void SwapPlayer(Player player) { var grid = db.Grids.FirstOrDefault(g => g.GridId == player.GridId); if (grid != null) { var bot = new Player { GridId = player.GridId, AccessCode = "Bot-" + grid.GridGuid + "-Replacement", Connected = true, Ip = "", Browser = "", IsAdmin = false, IsBot = true, IsZombie = true, PlayerNr = player.PlayerNr, PlayerType = player.PlayerType, Round = player.Round, IsReady = true, HasTimeout = false, RequestMove = false, RequestTypeChange = false, LastPoints = 0, TotalPoints = 0, TotalWaitingTime = 0, WaitingPayoff = 0, TotalPayoff = 0, StartTime = DateTime.Now, EndTime = DateTime.Now, StartLobby = DateTime.Now, LastUpdateTime = DateTime.Now }; db.Add(bot); db.Save(); var replacementBot = db.Players.FirstOrDefault(p => p.GridId == player.GridId & p.PlayerNr == player.PlayerNr & p.IsBot); if(replacementBot != null) { var cell = db.Cells.FirstOrDefault(c => c.PlayerId == player.PlayerId); if(cell != null) { cell.PlayerId = replacementBot.PlayerId; db.Save(); } } } }
/// <summary> /// Returns the neighborhood of a player /// </summary> /// <param name="grid">The Grid</param> /// <param name="player">The player</param> /// <param name="cells">List of all cells on the grid</param> /// <returns>A neighborhood</returns> private Neighborhood PlayerNeighborhood(Grid grid, Player player, List<Cell> cells) { var nei = new Neighborhood(); var sizeX = grid.SizeX; var sizeY = grid.SizeY; // Find my cell, type and coordinates var cell = cells.FirstOrDefault(c => c.PlayerId == player.PlayerId); if (cell != null) { var myCell = cell.CellNr; var myType = player.PlayerType; var myX = cell.X; var myY = cell.Y; // Find CellNr of neighbors List<int> neighborCells = new List<int>(); var nCell = (myY == 1) ? myCell + (sizeY - 1) * sizeX : myCell - sizeX; //N neighborCells.Add(nCell); var sCell = (myY == sizeY) ? myCell - (sizeY - 1) * sizeX : myCell + sizeX; neighborCells.Add(sCell); //S neighborCells.Add((myX == 1) ? myCell + (sizeX - 1) : myCell - 1); //W neighborCells.Add((myX == sizeX) ? myCell - (sizeX - 1) : myCell + 1); //E; neighborCells.Add((myX == 1) ? nCell + (sizeX - 1) : nCell - 1); //NW neighborCells.Add((myX == sizeX) ? nCell - (sizeX - 1) : nCell + 1); //NE neighborCells.Add((myX == 1) ? sCell + (sizeX - 1) : sCell - 1); //SW neighborCells.Add((myX == sizeX) ? sCell - (sizeX - 1) : sCell + 1); //SE // Iterate neighbors var ownTypeCount = 0; var otherTypeCount = 0; var empty = 0; foreach (var nr in neighborCells) { var neighbor = cells.FirstOrDefault(c => c.CellNr == nr); if (neighbor.Player != null) { if (neighbor.Player.PlayerType == myType) ownTypeCount++; if (neighbor.Player.PlayerType != myType) otherTypeCount++; } else { empty++; } } // Compute shares double ownShare = 0; double otherShare = 0; if ((ownTypeCount + otherTypeCount) > 0) { ownShare = (double)ownTypeCount / ((double)ownTypeCount + (double)otherTypeCount); otherShare = 1 - ownShare; } nei = new Neighborhood { PlayerId = player.PlayerId, OwnTypeCount = ownTypeCount, OtherTypeCount = otherTypeCount, EmptyCount = empty, OwnShare = ownShare, OtherShare = otherShare }; } return nei; }
/// <summary> /// Add artifical inteligence players /// </summary> /// <param name="gridId">Grid Id</param> public void AddBots(int gridId) { // Get the grid var grid = db.Grids.FirstOrDefault(g => g.GridId == gridId); if (grid != null) { // Get the total required number of players var totalPlayer = grid.TotalPlayerCount; // Get the number of bots to generate var targetBotCount = grid.BotCount; // Return instantly if bots are not allowed or required if (targetBotCount == 0) return; // Get the actual number of players var existingTotalPlayers = grid.Players.Count(x => x.Connected & !x.IsAdmin); var existingRealPlayers = grid.Players.Count(x => x.Connected & !x.IsBot & !x.IsAdmin); var existingBots = grid.Players.Count(x => x.Connected & x.IsBot & !x.IsAdmin); // Return if we have enough players if (existingTotalPlayers >= totalPlayer) return; // Generate the requested number of bots if (targetBotCount > 0) { // Return if we have already spawned the required number of bots if (targetBotCount == existingBots) { return; } } // Auto-generate the required number of bots else if (targetBotCount == -1) { targetBotCount = totalPlayer - existingRealPlayers - existingBots; } // Add bots to grid for (int i = 1 + existingBots; i <= targetBotCount + existingBots; i++) { var bot = new Player { GridId = gridId, AccessCode = "Bot-" + grid.GridGuid + "-" + i.ToString(), Connected = true, Ip = "", Browser = "", IsAdmin = false, IsBot = true, PlayerNr = 0, PlayerType = 0, Round = 0, IsReady = true, HasTimeout = false, RequestMove = false, RequestTypeChange = false, LastPoints = 0, TotalPoints = 0, TotalWaitingTime = 0, WaitingPayoff = 0, TotalPayoff = 0, StartTime = DateTime.Now, EndTime = DateTime.Now, StartLobby = DateTime.Now, LastUpdateTime = DateTime.Now }; db.Add(bot); } // Save numer of generated bots grid.BotCount = targetBotCount + existingBots; // Save db.Save(); // Test if bots have been saved var existingBots2 = grid.Players.Count(x => x.Connected & x.IsBot & !x.IsAdmin); if (grid.BotCount != existingBots2) throw new Exception("Bots not yet saved."); } }
/// <summary> /// Type change rule of bot /// </summary> /// <param name="grid">The Grid</param> /// <param name="player">The player and his neighborhood.</param> public void BotTypeChangeDecision(Grid grid, Player player) { // If neigborhood is not initialized, cannot decide if (player.Neighborhood.PlayerId == -1) return; bool typeChange = false; // Decision Rule switch (grid.TreatmentTypeId) { case 1: // Tolerance if (player.Neighborhood.OwnShare < grid.LowerThreshold) typeChange = true; break; case 2: // Preference for mixing if (player.Neighborhood.OwnShare < grid.LowerThreshold) { // 100% probability to move if very unhappy typeChange = true; } else if (player.Neighborhood.OwnShare > grid.UpperThreshold) { //50% probability to move if somewhat unhappy double moveProb = db.Random.NextDouble(); if (moveProb > 0.5) typeChange = true; } break; } // Noise if (grid.NoiseLevel > 0) { double noise = db.Random.NextDouble(); if (noise < grid.NoiseLevel) { if (typeChange) { typeChange = false; } else { typeChange = true; } } } // Zombie if (player.IsZombie) typeChange = false; if (typeChange) player.RequestTypeChange = true; player.LastUpdateTime = DateTime.Now; player.IsReady = true; }
/// <summary> /// Compute total payoff after a grid has completed. /// </summary> /// <param name="grid">The grid</param> /// <param name="player">The player</param> public void TransferPayoff(Grid grid, Player player) { switch(grid.GameTypeId) { case 1: player.PlayedMGames++; break; case 2: player.PlayedTGames++; break; case 3: player.PlayedMGames++; break; case 4: player.PlayedTGames++; break; } player.TotalPayoff += Math.Round((double)player.GridPoints * (double)grid.ExchangeRate, 2); }