Add Generation encapsulation

This commit is contained in:
Andrew Cooper
2022-09-13 07:21:53 +10:00
parent 3b208a1b92
commit db186bb86e
4 changed files with 116 additions and 79 deletions

View File

@@ -1,21 +1,28 @@
using System.Text;
namespace LifeforTwo; namespace LifeforTwo;
internal class Board internal class Board
{ {
private readonly Piece[,] _cells = new Piece[7,7]; private readonly Piece[,] _cells = new Piece[7, 7];
private readonly Dictionary<int, int> _cellCounts =
private readonly Dictionary<int, int> _cellCounts = new(); new() { [Piece.None] = 0, [Piece.Player1] = 0, [Piece.Player2] = 0 };
public Piece this[Coordinates coordinates] public Piece this[Coordinates coordinates]
{ {
get => _cells[coordinates.X, coordinates.Y]; get => this[coordinates.X, coordinates.Y];
set => _cells[coordinates.X, coordinates.Y] = value; set => this[coordinates.X, coordinates.Y] = value;
} }
public Piece this[int x, int y] public Piece this[int x, int y]
{ {
get => _cells[x, y]; get => _cells[x, y];
set => _cells[x, y] = value; set
{
if (!_cells[x, y].IsEmpty) { _cellCounts[_cells[x, y]] -= 1; }
_cells[x, y] = value;
_cellCounts[value] += 1;
}
} }
public int Player1Count => _cellCounts[Piece.Player1]; public int Player1Count => _cellCounts[Piece.Player1];
@@ -23,69 +30,27 @@ internal class Board
internal bool IsEmptyAt(Coordinates coordinates) => this[coordinates].IsEmpty; internal bool IsEmptyAt(Coordinates coordinates) => this[coordinates].IsEmpty;
public string? Result => internal void ClearCell(Coordinates coordinates) => this[coordinates] = Piece.NewNone();
(Player1Count, Player2Count) switch
{
(0, 0) => Strings.Draw,
(_, 0) => string.Format(Formats.Winner, 1),
(0, _) => string.Format(Formats.Winner, 2),
_ => null
};
internal void ClearCell(Coordinates coordinates) => this[coordinates] = Piece.NewEmpty();
internal void AddPlayer1Piece(Coordinates coordinates) => this[coordinates] = Piece.NewPlayer1(); internal void AddPlayer1Piece(Coordinates coordinates) => this[coordinates] = Piece.NewPlayer1();
internal void AddPlayer2Piece(Coordinates coordinates) => this[coordinates] = Piece.NewPlayer2(); internal void AddPlayer2Piece(Coordinates coordinates) => this[coordinates] = Piece.NewPlayer2();
public void CalculateNextGeneration() public override string ToString()
{ {
_cellCounts[Piece.None] = _cellCounts[Piece.Player1] = _cellCounts[Piece.Player2] = 0; var builder = new StringBuilder();
for (var x = 1; x <= 5; x++)
{
for (var y = 1; y <= 5; y++)
{
this[x, y] = this[x, y].GetNext();
_cellCounts[this[x, y].Value]++;
}
}
CountNeighbours();
}
public void CountNeighbours()
{
for (var x = 1; x <= 5; x++)
{
for (var y = 1; y <= 5; y++)
{
var coordinates = new Coordinates(x, y);
var piece = this[coordinates];
if (!piece.IsEmpty)
{
foreach (var neighbour in coordinates.GetNeighbors())
{
this[neighbour] = this[neighbour].AddNeighbour(piece);
}
}
}
}
}
public void Display(IReadWrite io)
{
for (var y = 0; y <= 6; y++) for (var y = 0; y <= 6; y++)
{ {
io.WriteLine(); builder.AppendLine();
for (var x = 0; x <= 6; x++) for (var x = 0; x <= 6; x++)
{ {
io.Write(GetDisplay(x, y)); builder.Append(GetCellDisplay(x, y));
} }
} }
return builder.ToString();
} }
private string GetDisplay(int x, int y) => private string GetCellDisplay(int x, int y) =>
(x, y) switch (x, y) switch
{ {
(0 or 6, _) => $" {y % 6} ", (0 or 6, _) => $" {y % 6} ",

View File

@@ -1,54 +1,44 @@
internal class Game internal class Game
{ {
private readonly IReadWrite _io; private readonly IReadWrite _io;
private readonly Board _board;
public Game(IReadWrite io) public Game(IReadWrite io)
{ {
_io = io; _io = io;
_board = new Board();
} }
public void Play() public void Play()
{ {
_io.Write(Streams.Title); _io.Write(Streams.Title);
for (var player = 1; player <= 2; player++) var generation = Generation.Create(_io);
{
_io.WriteLine(Formats.InitialPieces, player);
for (var i = 1; i <= 3; i++)
{
_board[_io.ReadCoordinates(_board)] = player == 1 ? Piece.NewPlayer1() : Piece.NewPlayer2();
}
}
_board.CountNeighbours(); _io.Write(generation);
_board.Display(_io);
while(true) while(true)
{ {
_board.CalculateNextGeneration(); generation = generation.CalculateNextGeneration();
_io.WriteLine(); _io.WriteLine();
_board.Display(_io); _io.Write(generation);
if (_board.Result is not null) { break; } if (generation.Result is not null) { break; }
var player1Coordinate = _io.ReadCoordinates(1, _board); var player1Coordinate = _io.ReadCoordinates(1, generation.Board);
var player2Coordinate = _io.ReadCoordinates(2, _board); var player2Coordinate = _io.ReadCoordinates(2, generation.Board);
if (player1Coordinate == player2Coordinate) if (player1Coordinate == player2Coordinate)
{ {
_io.Write(Streams.SameCoords); _io.Write(Streams.SameCoords);
// This is a bug existing in the original code. The line should be _board[_coordinates[_player]] = 0; // This is a bug existing in the original code. The line should be _board[_coordinates[_player]] = 0;
_board.ClearCell(player1Coordinate + 1); generation.Board.ClearCell(player1Coordinate + 1);
} }
else else
{ {
_board.AddPlayer1Piece(player1Coordinate); generation.Board.AddPlayer1Piece(player1Coordinate);
_board.AddPlayer2Piece(player2Coordinate); generation.Board.AddPlayer2Piece(player2Coordinate);
} }
} }
_io.WriteLine(_board.Result); _io.WriteLine(generation.Result);
} }
} }

View File

@@ -0,0 +1,78 @@
internal class Generation
{
private readonly Board _board;
public Generation(Board board)
{
_board = board;
CountNeighbours();
}
public Board Board => _board;
public int Player1Count => _board.Player1Count;
public int Player2Count => _board.Player2Count;
public string? Result =>
(Player1Count, Player2Count) switch
{
(0, 0) => Strings.Draw,
(_, 0) => string.Format(Formats.Winner, 1),
(0, _) => string.Format(Formats.Winner, 2),
_ => null
};
public static Generation Create(IReadWrite io)
{
var board = new Board();
SetInitialPieces(1, coord => board.AddPlayer1Piece(coord));
SetInitialPieces(2, coord => board.AddPlayer2Piece(coord));
return new Generation(board);
void SetInitialPieces(int player, Action<Coordinates> setPiece)
{
io.WriteLine(Formats.InitialPieces, player);
for (var i = 1; i <= 3; i++)
{
setPiece(io.ReadCoordinates(board));
}
}
}
public Generation CalculateNextGeneration()
{
var board = new Board();
for (var x = 1; x <= 5; x++)
{
for (var y = 1; y <= 5; y++)
{
board[x, y] = _board[x, y].GetNext();
}
}
return new(board);
}
private void CountNeighbours()
{
for (var x = 1; x <= 5; x++)
{
for (var y = 1; y <= 5; y++)
{
var coordinates = new Coordinates(x, y);
var piece = _board[coordinates];
if (piece.IsEmpty) { continue; }
foreach (var neighbour in coordinates.GetNeighbors())
{
_board[neighbour] = _board[neighbour].AddNeighbour(piece);
}
}
}
}
public override string ToString() => _board.ToString();
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
namespace LifeforTwo; namespace LifeforTwo;
@@ -19,10 +20,10 @@ public struct Piece
private Piece(int value) => _value = value; private Piece(int value) => _value = value;
public int Value => _value; public int Value => _value & PieceMask;
public bool IsEmpty => (_value & PieceMask) == None; public bool IsEmpty => (_value & PieceMask) == None;
public static Piece NewEmpty() => new(None); public static Piece NewNone() => new(None);
public static Piece NewPlayer1() => new(Player1); public static Piece NewPlayer1() => new(Player1);
public static Piece NewPlayer2() => new(Player2); public static Piece NewPlayer2() => new(Player2);
@@ -47,4 +48,7 @@ public struct Piece
Player2 => "#", Player2 => "#",
_ => " " _ => " "
}; };
public static implicit operator Piece(int value) => new(value);
public static implicit operator int(Piece piece) => piece.Value;
} }