Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
checkers
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
CC = g++
CFLAGS = -g -Wall -Wextra -Werror -std=c++11
CFLAGS = -g -O0 -Wall -Wextra -Werror -std=c++11
CHECKERS_SOURCES = checker.cpp \
game.cpp \
board.cpp \
Expand Down
66 changes: 37 additions & 29 deletions board.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ Board::Board() {
}
}

int Board::y_for_player(int player) const {
return player ? -1 : 1;
}

Checker* Board::get_checker_at(const int x, const int y) const {
for(Checker* checker : checkers) {
if(checker->get_x() == x and checker->get_y() == y) {
Expand All @@ -36,6 +40,7 @@ void Board::print_board() const {
player_symbols[checker->get_player()];
}

printf("========\n");
printf(" ");
for(size_t i = 0; i < NUM_COLS; i++) {
printf("%zu ", i);
Expand All @@ -52,6 +57,7 @@ void Board::print_board() const {
}
printf("\n");
}
printf("========\n");
}

int Board::player_checker_count(const int playernum) const {
Expand All @@ -67,12 +73,13 @@ int Board::player_checker_count(const int playernum) const {
int Board::get_capture_vector(const Checker& checker) const {
int x = checker.get_x();
int y = checker.get_y();
for(size_t i = 0; i < 2; i++) {
int x_offset = vectors[checker.get_player()][i][0];
int y_offset = vectors[checker.get_player()][i][1];
int y_offset = y_for_player(checker.get_player());

for(int i = 0; i < 2; i++) {
int x_offset = 1 - i * 2;

Checker* victim = get_checker_at(x + x_offset,
y + y_offset);
y + y_offset);

if(not victim or victim->get_player() == checker.get_player()) {
continue;
Expand All @@ -82,7 +89,7 @@ int Board::get_capture_vector(const Checker& checker) const {
victim->get_y() + y_offset);

if(not space) { //Empty space
return i;
return i;
}
}
return -1;
Expand Down Expand Up @@ -116,9 +123,9 @@ bool Board::can_player_move(const int playernum) const {
if(checker->get_player() != playernum) {
continue;
}
int new_y = checker->get_y() + y_for_player(playernum);
for(size_t i = 0; i < 2; i++) {
int new_x = checker->get_x() + vectors[playernum][i][0];
int new_y = checker->get_y() + vectors[playernum][i][1];
int new_x = checker->get_x() + 1 - i * 2;
if(not is_position_legal(new_x, new_y)) {
continue;
}
Expand All @@ -135,10 +142,13 @@ bool Board::is_position_legal(const int x, const int y) const {
}

bool Board::is_move_legal(const Checker& piece, const int vector, const int player) const {
int y_dir = y_for_player(player);
int x_dir = vector ? 1 : -1;

return is_move_legal(piece.get_x(), piece.get_y(),
piece.get_x() + vectors[player][vector][0],
piece.get_y() + vectors[player][vector][1],
player);
piece.get_x() + x_dir,
piece.get_y() + y_dir,
player);
}

bool Board::is_move_legal(const int x_start, const int y_start,
Expand Down Expand Up @@ -184,28 +194,25 @@ bool Board::can_player_move_piece(const Checker& checker, const int player) cons
}

bool Board::can_player_move_piece(const int x, const int y, const int player) const {
if(not is_position_legal(x, y)) {
return false;
}
Checker* checker = get_checker_at(x, y);
if(not checker) {
return false;
}

if(checker->get_player() != player) {
if (!checker || (checker->get_player() != player)) {
return false;
}

int y_dir = y_for_player(player);

for(size_t i = 0; i < 2; i++) {
if(not get_checker_at(x + vectors[player][i][0],
y + vectors[player][i][1])) {
int x_dir = 1 - i * 2;

if(is_position_legal(x + x_dir, y + y_dir) &&
not get_checker_at(x + x_dir, y + y_dir)) {
return true;
} else if(is_position_legal(x + vectors[player][i][0] * 2,
y + vectors[player][i][1] * 2)) {
Checker* space = get_checker_at(x + vectors[player][i][0] * 2,
y + vectors[player][i][1] * 2);
Checker* victim = get_checker_at(x + vectors[player][i][0],
y + vectors[player][i][1]);
}
if(is_position_legal(x + x_dir * 2, y + y_dir * 2)) {
Checker* space = get_checker_at(x + x_dir * 2,
y + y_dir * 2);
Checker* victim = get_checker_at(x + x_dir, y + y_dir);
if(victim and victim->get_player() != player and not space) {
return true;
}
Expand All @@ -220,8 +227,9 @@ bool Board::can_player_move_piece(const int x, const int y, const int player) co
void Board::make_capture(Checker& piece, const int vector) {
int start_x = piece.get_x();
int start_y = piece.get_y();
int offset_x = vectors[piece.get_player()][vector][0];
int offset_y = vectors[piece.get_player()][vector][1];
int player = piece.get_player();
int offset_x = vector ? 1 : -1;
int offset_y = y_for_player(player);
kill_checker_at(start_x + offset_x, start_y + offset_y);
piece.set_x(start_x + offset_x * 2);
piece.set_y(start_y + offset_y * 2);
Expand Down Expand Up @@ -259,7 +267,7 @@ void Board::make_random_move(const int player) {
if(!is_move_legal(*piece, direction, player)) {
direction = (direction + 1) % 2;
}
piece->set_x(piece->get_x() + vectors[player][direction][0]);
piece->set_y(piece->get_y() + vectors[player][direction][1]);
piece->set_x(piece->get_x() + (direction ? 1 : -1));
piece->set_y(piece->get_y() + y_for_player(player));
}
}
14 changes: 2 additions & 12 deletions board.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,11 @@ const int player1_start_y[NUM_CHECKERS] = {7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5};

const int player_symbols[NUM_PLAYERS] = {'X', 'O'};

const int vectors[2][2][2] = {
{
{-1, 1}, //only for player 0
{1, 1}, //only for player 0
},
{
{-1, -1}, //only for player 1
{1, -1}, //only for player1
},
};


class Board {
private:
unordered_set<Checker*> checkers;
int y_for_player(int player) const;

public:
Board();
Checker* get_checker_at(const int x, const int y) const;
Expand Down
Binary file removed checkers
Binary file not shown.
159 changes: 159 additions & 0 deletions checkers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#!/usr/bin/python

import sys

class Checkboard(object):
def __init__(self):
self.whites = set() # All white pieces, tuples of coordinates
self.blacks = set() # All black pieces, tuples of coordinates
self.checkers = {} # The entire board, only taken spots, dictionary of dictionaries [row][col]

# Populate the board
for row in range(8):
self.checkers[row] = {}
for col in range(8):
if row < 3:
piece = 'w'
s = self.whites
elif row > 4:
piece = 'b'
s = self.blacks
else:
continue
if not ((col ^ row) & 1): # Only every other cell gets a piece
self.checkers[row][col] = piece
s.add((row, col))

def __str__(self):
separator = ' ' + '+-' * 8 + '+\n'
board = separator
for row in range(7, -1, -1):
board += str(row)
for col in range(8):
if (row ^ col) & 1:
check = ' '
else:
check = '.'
board += '|' + self.checkers[row].get(col, check)
board += '|\n' + separator
board += ' '
for col in range(8):
board += ' ' + str(col)
return board

# Return true if the piece in [row][col] was able to capture an opponent piece
def captured(self, row, col, rowdir, coldir, mycolor):
nnc = col + 2 * coldir
nnr = row + 2 * rowdir
if nnc < 0 or nnc > 7 or nnr < 0 or nnr > 7:
return False # this piece can not capture

nc = col + coldir
nr = row + rowdir

if nnc in self.checkers[nnr] or not nc in self.checkers[nr] or self.checkers[nr][nc] == mycolor:
return False # there is nothing to capture

# Determine the this and other sets
if mycolor == 'w':
os = self.blacks
s = self.whites
else:
os = self.whites
s = self.blacks

# remove the captured piece
del self.checkers[nr][nc]
os.remove((nr, nc))

# move our piece
self.checkers[nnr][nnc] = mycolor
del self.checkers[row][col]
s.remove((row, col))
s.add((nnr, nnc))
return True

# return true if piece in [row][col] was able to move
def moved(self, row, col, rowdir, coldir, mycolor):
nr = row + rowdir
nc = col + coldir

if nr < 0 or nr > 7 or nc < 0 or nc > 7:
return False # no chance to move

if nc not in self.checkers[nr]:
del self.checkers[row][col]
self.checkers[nr][nc] = mycolor
if mycolor == 'w':
s = self.whites
else:
s = self.blacks
s.remove((row, col))
s.add((nr, nc))
return True
return False


def try_capture(self, row, col, rowdir, color):
for coldir in (1, -1):
if self.captured(row, col, rowdir, coldir, color):
return True
return False

def try_move(self, row, col, rowdir, color):
for coldir in (1, -1):
if self.moved(row, col, rowdir, coldir, color):
return True
return False

def move(self, color):
# create a copy set, so that we can iterate over it and modify the original set
if color == 'w':
cs = set(self.whites)
rowdir = 1
else:
cs = set(self.blacks)
rowdir = -1

# Captures when possible must proceed, try them first
for row, col in cs:
if self.try_capture(row, col, rowdir, color):
return True
for row, col in cs:
if self.try_move(row, col, rowdir, color):
return True
return False


def get_coord(cb):
while True:
sys.stdout.write('Your move: ')
sys.stdout.flush()
try:
line = sys.stdin.readline().strip()
except KeyboardInterrupt:
print
sys.exit(1)
if len(line) == 3:
row, col, dir = (int(x) for x in line)
if cb.checkers[row].get(col, '') == 'b' and dir < 2:
return row, col, dir * 2 - 1
sys.stdout.write('Invalid input, try again\n')

cb = Checkboard()
keepgoing = True
while keepgoing:
if True: # Computer vs human
if not cb.move('w'):
break
print cb
row, col, dir = get_coord(cb)
if cb.captured(row, col, -1, dir, 'b') or cb.moved(row, col, -1, dir, 'b'):
continue
break
for color in ('w', 'b'):
print '\nbefore %s move :' % color
print cb
if not cb.move(color):
keepgoing = False
break
Loading