module pegp.board; class Board { private int m_size; private int m_peg_count; private bool[] m_pegs; enum Direction { NW, FIRST = NW, NE, W, E, SW, SE, COUNT, } struct Position { int row; int col; this(int row, int col) { this.row = row; this.col = col; } Position move(Direction d, int dist = 1) { int new_row = row + dist * ((d / 2) - 1); int new_col = col + dist * (((d % 3) + 1) & 1) * (d / 3 * 2 - 1); return Position(new_row, new_col); } string toString() { string s = [ cast(char)('1' + row), cast(char)('A' + col), ]; return s; } } this(int size) { assert(size >= 3); m_size = size; const int n_pegs = (size * (size + 1)) / 2; m_pegs = new bool[n_pegs]; m_pegs[] = true; m_pegs[0] = false; m_peg_count = n_pegs - 1; } this(Board b) { m_size = b.m_size; m_pegs = b.m_pegs.dup; m_peg_count = b.m_peg_count; } @property int peg_count() { return m_peg_count; } private int peg_index(int row, int col) { return (row * (row + 1)) / 2 + col; } bool position_valid(int row, int col) { return (row >= 0) && (row < m_size) && (col >= 0) && (col <= row); } bool position_valid(Position p) { return position_valid(p.row, p.col); } bool peg_present(int row, int col) { return m_pegs[peg_index(row, col)]; } bool peg_present(Position p) { return peg_present(p.row, p.col); } void remove_peg(Position p) { m_pegs[peg_index(p.row, p.col)] = false; m_peg_count--; } void add_peg(Position p) { m_pegs[peg_index(p.row, p.col)] = true; m_peg_count++; } Board move(Position p, Direction d) { Position p1 = p.move(d, 1); Position p2 = p.move(d, 2); if (peg_present(p) && position_valid(p2) && peg_present(p1) && !peg_present(p2)) { Board b2 = new Board(this); b2.remove_peg(p); b2.remove_peg(p1); b2.add_peg(p2); return b2; } return null; } unittest { Board b = new Board(5); assert(b.peg_count == 14); assert(b.position_valid(Position(0, 0))); assert(b.position_valid(4, 0)); assert(b.position_valid(4, 4)); assert(b.position_valid(2, 2)); assert(b.position_valid(3, 1)); assert(!b.position_valid(0, 1)); assert(!b.position_valid(0, -1)); assert(!b.position_valid(5, 0)); assert(!b.position_valid(5, 4)); assert(!b.position_valid(4, 5)); assert(!b.position_valid(2, 3)); assert(!b.position_valid(0, 4)); assert(b.peg_present(1, 0)); assert(b.peg_present(Position(1, 1))); assert(b.peg_present(4, 4)); assert(!b.peg_present(0, 0)); Position s = Position(2, 1); assert(s.move(Direction.NW) == Position(1, 0)); assert(s.move(Direction.NE) == Position(1, 1)); assert(s.move(Direction.W) == Position(2, 0)); assert(s.move(Direction.E) == Position(2, 2)); assert(s.move(Direction.SW) == Position(3, 1)); assert(s.move(Direction.SE) == Position(3, 2)); assert(s.move(Direction.NW, 2) == Position(0, -1)); assert(s.move(Direction.NE, 2) == Position(0, 1)); assert(s.move(Direction.W, 2) == Position(2, -1)); assert(s.move(Direction.E, 2) == Position(2, 3)); assert(s.move(Direction.SW, 2) == Position(4, 1)); assert(s.move(Direction.SE, 2) == Position(4, 3)); assert(b.position_valid(s.move(Direction.NW))); assert(b.position_valid(s.move(Direction.NE))); assert(b.position_valid(s.move(Direction.W))); assert(b.position_valid(s.move(Direction.E))); assert(b.position_valid(s.move(Direction.SW))); assert(b.position_valid(s.move(Direction.SE))); assert(!b.position_valid(s.move(Direction.NW, 2))); assert(!b.position_valid(s.move(Direction.NE, 2))); assert(!b.position_valid(s.move(Direction.W, 2))); assert(!b.position_valid(s.move(Direction.E, 2))); assert(b.position_valid(s.move(Direction.SW, 2))); assert(b.position_valid(s.move(Direction.SE, 2))); Board b2; b2 = b.move(Position(0, 0), Direction.SW); assert(b2 is null); b2 = b.move(Position(2, 0), Direction.NE); assert(b2 !is null); assert(!b2.peg_present(2, 0)); assert(!b2.peg_present(1, 0)); assert(b2.peg_present(0, 0)); assert(b2.peg_count == 13); } }