183 lines
4.8 KiB
D
183 lines
4.8 KiB
D
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);
|
|
}
|
|
}
|