peg_puzzle/src/pegp/board.d
Josh Holtrop 6add626470 Flesh out Solver a bit more.
Something is definitely broken though...
2021-02-28 14:41:26 -05:00

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);
}
}