public override List<Cell> GetCellNeighbours(int i, int j, Board board) { List<Cell> neighbours = base.GetCellNeighbours(i,j,board); //Add radius 1 neighbours int startIndex, endIndex; int size = board.Size; //Add radius 2 neighbours //Add top & bottom cells startIndex = j > 1 ? j - 2 : 0; endIndex = j < size - 2 ? j + 2 : size - 1; if (i > 1) { for (int x = startIndex; x <= endIndex; x++) { neighbours.Add(board[i - 2,x]); } } if (i < size - 2) { for (int x = startIndex; x <= endIndex; x++) { neighbours.Add(board[i + 2, x]); } } //Add side neighbours startIndex = i > 0 ? i - 1 : 0; endIndex = i < size - 1 ? i + 1 : size - 1; if (j > 1) { for (int x = startIndex; x <= endIndex; x++) { neighbours.Add(board[x, j-2]); } } if (j < size - 2) { for (int x = startIndex; x <= endIndex; x++) { neighbours.Add(board[x , j + 2]); } } return neighbours; }
/// <summary> /// Handles the Click event of the btnGenerateBoard control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param> private void btnGenerateBoard_Click(object sender, EventArgs e) { int boardSize = int.Parse(txtBoardSize.Text); int numOfMen = int.Parse(txtNumOfMen.Text); int numOfWomen = int.Parse(txtNumOfWomen.Text); m_numOfGenerations = int.Parse(cmbNumOfGenerations.Text); var board = new Board(boardSize); BoardStrategyParameters parameters = GetStrategyParameters(); IBoardStrategy strategy = BoardStrategyFactory.CreateStrategy(parameters); m_boardManager = new BoardManager(board, strategy); m_boardManager.PopulateBoard(numOfMen, numOfWomen); m_boardPanels = new Panel[boardSize, boardSize]; InitializeBoardGraphics(m_boardManager.Board); btnRunAutomata.Enabled = true; }
/// <summary> /// Redraws the board graphics. /// </summary> /// <param name="board">The board.</param> private void RedrawBoardGraphics(Board board) { for (int i = 0; i < board.Size; i++) { for (int j = 0; j < board.Size; j++) { m_boardPanels[i, j].BackgroundImage = GetCellImage(board[i, j]); m_boardPanels[i, j].BackColor = GelCellBackColor(board[i, j]); } } splitContainer1.Panel2.Refresh(); }
/// <summary> /// Draws the board. /// </summary> /// <param name="board">The board.</param> /// <exception cref="System.NotImplementedException"></exception> private void InitializeBoardGraphics(Board board) { int cellSize = BoardWidthInPixel/board.Size; splitContainer1.Panel2.Controls.Clear(); for (int i = 0; i < board.Size; i++) { for (int j = 0; j < board.Size; j++) { var panel = new Panel { Size = new Size(cellSize, cellSize), Location = new Point(BoardXOffset + (cellSize * i) , BoardYOffset + (cellSize * j)), BackgroundImage = GetCellImage(board[i, j]), BackgroundImageLayout = ImageLayout.Stretch, BackColor = GelCellBackColor(board[i,j]), BorderStyle = BorderStyle.FixedSingle, }; splitContainer1.Panel2.Controls.Add(panel); m_boardPanels[i, j] = panel; } } lblAverageHappiness.Text = "0"; lblCurrHappiness.Text = "0"; lblGenerationNum.Text = "0"; }
public void CalculateNextBoardState() { m_board = m_startegy.CalculateNextBoardState(m_board); m_totalGenerationsCalculated++; m_totalGenerationsHappiness += GetCurrentHappinessScore(); }
public BoardManager(Board board, IBoardStrategy strategy) { m_board = board; m_startegy = strategy; m_rand = new Random(DateTime.Now.Millisecond); }
/// <summary> /// Calculates the state of the next board. /// </summary> /// <param name="board">The board.</param> /// <returns></returns> public Board CalculateNextBoardState(Board board) { var nextGenerationBoard = new Board(board.Size); for (int i = 0; i < board.Size; i++) { for (int j = 0; j < board.Size; j++) { Cell currGenerationCell = board[i, j]; Cell nextGenerationCell = nextGenerationBoard[i, j]; if (nextGenerationCell.State != CellState.Empty /*Already calculated*/ || currGenerationCell.State == CellState.Empty) continue; if (currGenerationCell.State != CellState.Couple) //A single cell, try to find spouses { Cell spouseCell = FindSpouseForSingleHumanCell(i, j, board, nextGenerationBoard); if (spouseCell != null) // Found a spouse, create a couple { Human spouse = spouseCell.GetOppositeSexHuman(currGenerationCell.Humans[0].Sex); Human human = currGenerationCell.Humans[0].Clone(); if (m_enableMemory) //If memory is enable, save spouses memory { human.BestCharacterDiffMemory = Math.Abs(spouse.Character - human.Character); } nextGenerationCell.Humans.Add(human); nextGenerationCell.Humans.Add(spouse.Clone()); Tuple<int, int> spouseIndexes = board.FindCellIndexes(spouseCell); if (spouseCell.State == CellState.Couple) //Create the single human cell in the next state board { spouseCell.Humans.Remove(spouse); nextGenerationBoard[spouseIndexes.Item1, spouseIndexes.Item2].Humans.Add(spouseCell.Humans[0].Clone()); } board[spouseIndexes.Item1, spouseIndexes.Item2] = new Cell(); board[i, j] = new Cell(); } else //Didn't find a spouse, try to move the human { MoveCell(board, nextGenerationBoard, i, j); } } else //The cell has a couple { Cell spouse = FindBetterSpouseForCoupleCell(i, j, board); if (spouse != null) //Found a better spouse, generate the new couple and new single { Tuple<int, int> spouseIndexes = board.FindCellIndexes(spouse); if (spouse.State == CellState.Man) { //The new couple nextGenerationBoard[spouseIndexes.Item1, spouseIndexes.Item2].Humans.Add(spouse.Male.Clone()); nextGenerationBoard[spouseIndexes.Item1, spouseIndexes.Item2].Humans.Add(board[i, j].Female.Clone()); //The new single nextGenerationBoard[i, j].Humans.Add(board[i, j].Male.Clone()); } else //Woman { //The new couple nextGenerationBoard[spouseIndexes.Item1, spouseIndexes.Item2].Humans.Add(spouse.Female.Clone()); nextGenerationBoard[spouseIndexes.Item1, spouseIndexes.Item2].Humans.Add(board[i, j].Male.Clone()); //The new single nextGenerationBoard[i, j].Humans.Add(board[i, j].Female.Clone()); } //Clear the couple and the new spouse cells from the original board board[i, j] = new Cell(); board[spouseIndexes.Item1, spouseIndexes.Item2] = new Cell(); } else //Didn't find a better spouse, try to move the couple { MoveCell(board, nextGenerationBoard, i, j); } } } } return nextGenerationBoard; }
/// <summary> /// Randomly Moves a cell on the board5. /// </summary> /// <param name="board">The board.</param> /// <param name="nextGenBoard">The next state board.</param> /// <param name="i">The i.</param> /// <param name="j">The j.</param> private void MoveCell(Board board, Board nextGenBoard, int i, int j) { Tuple<int, int> coordinates = GenerateRandomMoveCoordinates(i, j, board, nextGenBoard); if (coordinates != null) { nextGenBoard[coordinates.Item1, coordinates.Item2] = board[i, j].Clone(); } else { nextGenBoard[i, j] = board[i, j].Clone(); ; } board[i, j] = new Cell(); }
/// <summary> /// Finds the spouse for single human cell. /// </summary> /// <param name="i">The i.</param> /// <param name="j">The j.</param> /// <param name="board">The board.</param> /// <returns></returns> private Cell FindSpouseForSingleHumanCell(int i, int j, Board board, Board nextGenerationBoard) { Human human = board[i, j].Humans[0]; List<Cell> neighbours = GetCellNeighbours(i, j, board); //Filter only optional spouses neighbours = neighbours.Where(n => n.State != CellState.Empty && n.GetOppositeSexHuman(human.Sex) != null).ToList(); //Choose the best spouse var spouses = from neighbour in neighbours let charDiff = Math.Abs(neighbour.GetOppositeSexHuman(human.Sex).Character - human.Character) where (!m_enableMemory || charDiff < human.BestCharacterDiffMemory) && (m_maxCharacterDiffForCoupling == null || (charDiff <= m_maxCharacterDiffForCoupling && charDiff < neighbour.CharacterDiff)) orderby charDiff ascending select neighbour; //Filter couple spouse where the couple cell was already calculated in the next generation board, to avoid override spouses = from spouse in spouses let spouseIndexes = board.FindCellIndexes(spouse) where spouse.State != CellState.Couple || nextGenerationBoard[spouseIndexes.Item1, spouseIndexes.Item2].State == CellState.Empty select spouse; return spouses.FirstOrDefault(); //The best spouse }
/// <summary> /// Finds the better spouse for couple cell. /// </summary> /// <param name="i">The i.</param> /// <param name="j">The j.</param> /// <param name="board">The board.</param> /// <returns></returns> private Cell FindBetterSpouseForCoupleCell(int i, int j, Board board) { Cell cell = board[i, j]; List<Cell> neighbours = GetCellNeighbours(i, j, board); //Consider only non-empty cells neighbours = neighbours.Where(n => n.State != CellState.Empty).ToList(); int coupleCharDiff = Math.Abs(cell.Humans[0].Character - cell.Humans[1].Character); var betterSpouses = from neighbour in neighbours let charDiff = neighbour.Humans[0].Sex == Sex.Female ? Math.Abs(cell.Male.Character - neighbour.Humans[0].Character) : Math.Abs(cell.Female.Character - neighbour.Humans[0].Character) where (neighbour.State == CellState.Man || neighbour.State == CellState.Woman) && charDiff < coupleCharDiff select neighbour; return betterSpouses.FirstOrDefault(); }
/// <summary> /// Gets the cell neighbours. /// </summary> /// <param name="i">The i.</param> /// <param name="j">The j.</param> /// <param name="board">The board.</param> /// <returns></returns> /// <exception cref="System.ArgumentException">Indexes must be a positive integer</exception> public virtual List<Cell> GetCellNeighbours(int i, int j, Board board) { int size = board.Size; if (i < 0 || j < 0) { throw new ArgumentException("Indexes must be a positive integer"); } if (i >= size || j >= size) { throw new ArgumentException("Indexes must be less than board size:" + size); } var neighbours = new List<Cell>(); if (i > 0) //Add top neighbours { neighbours.Add(board[i - 1, j]); if (j < size - 1) { neighbours.Add(board[i - 1, j + 1]); } if (j > 0) { neighbours.Add(board[i - 1, j - 1]); } } if (i < size - 1) //Add bottom neighbours { neighbours.Add(board[i + 1, j]); if (j < size - 1) { neighbours.Add(board[i + 1, j + 1]); } if (j > 0) { neighbours.Add(board[i + 1, j - 1]); } } //Add side neighbours if (i > 0) { neighbours.Add(board[i - 1, j]); } if (i < size - 1) { neighbours.Add(board[i + 1, j]); } return neighbours; }
/// <summary> /// Generates the random move coordinates. /// </summary> /// <param name="i">The i.</param> /// <param name="j">The j.</param> /// <param name="board">The board.</param> /// <returns>Returns the new random coordinates or null if couldn't find any</returns> public Tuple<int, int> GenerateRandomMoveCoordinates(int i, int j, Board board, Board nextGenBoard) { int iRnd, jRnd; int tries = 0; do { iRnd = GenerateRandomMoveCoordinate(i, board.Size); jRnd = GenerateRandomMoveCoordinate(j, board.Size); tries++; } while ((board[iRnd, jRnd].State != CellState.Empty || nextGenBoard[iRnd, jRnd].State != CellState.Empty) && tries < MaxRandomMoveTries); if (tries == MaxRandomMoveTries) //Couldn't find an empty cell, so stay at the same cell. { return null; } else { return new Tuple<int, int>(iRnd, jRnd); } }