243 lines
6.6 KiB
C++
243 lines
6.6 KiB
C++
#include "game.h"
|
|
|
|
#include <assert.h>
|
|
|
|
#include <iostream>
|
|
|
|
// Checks whether or not the game is finished.
|
|
// A game is considered finished when all lines have been drawn.
|
|
bool game_is_finished(const Grid &grid) {
|
|
for (unsigned int j = 0; j < grid.num_rows(); ++j) {
|
|
for (unsigned int i = 0; i < grid.num_cols(); ++i) {
|
|
if (grid.field(i, j) == ' ')
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Draw a line in the grid starting at point (row, col) going towards the given
|
|
// direction
|
|
void draw_line(Grid &grid, unsigned int row, unsigned int col, char direction) {
|
|
switch (direction) {
|
|
case 'r':
|
|
grid.horizontal(row, col) = true;
|
|
break;
|
|
case 'l':
|
|
grid.horizontal(row, col - 1) = true;
|
|
break;
|
|
case 'd':
|
|
grid.vertical(row, col) = true;
|
|
break;
|
|
case 'u':
|
|
grid.vertical(row - 1, col) = true;
|
|
break;
|
|
default:
|
|
// We should never reach this point.
|
|
std::cout << "Invalid line direction.";
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
// Checks whether or not a box (or field) is newly completed.
|
|
// A box is newly completed if all four sides are drawn but the box is not
|
|
// claimed yet.
|
|
bool is_newly_completed_box(const Grid &grid, unsigned int row,
|
|
unsigned int col) {
|
|
bool state;
|
|
if (grid.vertical(row, col) == true && grid.horizontal(row, col) == true &&
|
|
grid.vertical(row, col + 1) && grid.horizontal(row + 1, col) == true)
|
|
state = true;
|
|
else
|
|
state = false;
|
|
|
|
return state;
|
|
}
|
|
|
|
// Play the players move.
|
|
// This function returns true if the player completed a box with their move.
|
|
// Otherwise it returns false.
|
|
bool play_move(Grid &grid, char player, unsigned int row, unsigned int col,
|
|
char direction) {
|
|
// Note: we assume the move is valid
|
|
|
|
// draw the new line
|
|
draw_line(grid, row, col, direction);
|
|
|
|
// check if the current players move completed a new box
|
|
bool completed_new_box = false;
|
|
switch (direction) {
|
|
case 'r':
|
|
// we drew a horizontal line
|
|
|
|
// check if box above the horizontal line is newly completed
|
|
// Note: box above only exists if the line is not at the top edge of
|
|
// the grid!
|
|
if (row > 0 && is_newly_completed_box(grid, row - 1, col)) {
|
|
completed_new_box = true;
|
|
grid.field(row - 1, col) = player;
|
|
}
|
|
if (row >= 0 && row < grid.num_rows() &&
|
|
is_newly_completed_box(grid, row, col)) {
|
|
completed_new_box = true;
|
|
grid.field(row, col) = player;
|
|
}
|
|
break;
|
|
case 'l':
|
|
if (row > 0 && is_newly_completed_box(grid, row - 1, col - 1)) {
|
|
completed_new_box = true;
|
|
grid.field(row - 1, col - 1) = player;
|
|
}
|
|
if (row >= 0 && row < grid.num_rows() &&
|
|
is_newly_completed_box(grid, row, col - 1)) {
|
|
completed_new_box = true;
|
|
grid.field(row, col - 1) = player;
|
|
}
|
|
break;
|
|
case 'u':
|
|
if (col > 0 && is_newly_completed_box(grid, row - 1, col - 1)) {
|
|
completed_new_box = true;
|
|
grid.field(row - 1, col - 1) = player;
|
|
}
|
|
if (col >= 0 && col < grid.num_cols() &&
|
|
is_newly_completed_box(grid, row - 1, col)) {
|
|
completed_new_box = true;
|
|
grid.field(row - 1, col) = player;
|
|
}
|
|
break;
|
|
case 'd':
|
|
if (col > 0 && is_newly_completed_box(grid, row, col - 1)) {
|
|
completed_new_box = true;
|
|
grid.field(row, col - 1) = player;
|
|
}
|
|
if (col >= 0 && col < grid.num_cols() &&
|
|
is_newly_completed_box(grid, row, col)) {
|
|
completed_new_box = true;
|
|
grid.field(row, col) = player;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return completed_new_box;
|
|
}
|
|
|
|
// Computes a players score.
|
|
// A Players score is the number of fields claimed by the player.
|
|
unsigned int compute_player_score(const Grid &grid, char player) {
|
|
int score = 0;
|
|
for (unsigned int j = 0; j < grid.num_rows(); j++) {
|
|
for (unsigned int i = 0; i < grid.num_rows(); i++) {
|
|
if (grid.field(i, j) == player)
|
|
++score;
|
|
}
|
|
}
|
|
return score;
|
|
}
|
|
|
|
// Checks if the move is within the bounds of the grid,
|
|
// and the line is not already drawn
|
|
bool is_valid_move(const Grid &grid, unsigned int row, unsigned int col,
|
|
char direction) {
|
|
bool state = false;
|
|
switch (direction) {
|
|
case 'l':
|
|
if (col > 0 && row <= grid.num_rows() &&
|
|
grid.horizontal(row, col - 1) == false)
|
|
state = true;
|
|
break;
|
|
case 'r':
|
|
if (col < grid.num_cols() && row <= grid.num_rows() &&
|
|
grid.horizontal(row, col) == false)
|
|
state = true;
|
|
break;
|
|
case 'u':
|
|
if (row > 0 && col <= grid.num_cols() &&
|
|
grid.vertical(row - 1, col) == false)
|
|
state = true;
|
|
break;
|
|
case 'd':
|
|
if (row < grid.num_rows() && col <= grid.num_cols() &&
|
|
grid.vertical(row, col) == false)
|
|
state = true;
|
|
break;
|
|
default:
|
|
state = false;
|
|
break;
|
|
}
|
|
return state;
|
|
}
|
|
|
|
// Main game loop
|
|
void play_game(Grid &grid) {
|
|
// initialize player and step
|
|
char current_player = 'A';
|
|
unsigned int current_move = 1;
|
|
|
|
// print initial grid
|
|
grid.print_grid();
|
|
|
|
// initialize user input
|
|
unsigned int row, col;
|
|
char direction;
|
|
|
|
// loop while game is not finished
|
|
while (!game_is_finished(grid)) {
|
|
std::cout << "Move # " << current_move << std::endl;
|
|
|
|
// get a valid move
|
|
std::cout << "Player " << current_player << "'s move: " << std::endl;
|
|
std::cin >> row >> col >> direction;
|
|
while (!is_valid_move(grid, row, col, direction)) {
|
|
std::cout << "Invalid move!" << std::endl;
|
|
std::cin >> row >> col >> direction;
|
|
}
|
|
|
|
// play the move
|
|
bool move_completed_box =
|
|
play_move(grid, current_player, row, col, direction);
|
|
current_move += 1;
|
|
|
|
// print grid
|
|
grid.print_grid();
|
|
|
|
// change current player
|
|
switch (current_player) {
|
|
case 'A':
|
|
if (move_completed_box == true)
|
|
current_player = 'A';
|
|
else
|
|
current_player = 'B';
|
|
break;
|
|
case 'B':
|
|
if (move_completed_box == true)
|
|
current_player = 'B';
|
|
else
|
|
current_player = 'A';
|
|
break;
|
|
default:
|
|
// We should never reach this point.
|
|
std::cout << "Unknown Player";
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
// Game loop exited. The game must be finished
|
|
std::cout << "Game finished" << std::endl;
|
|
|
|
// Compute and display player scores
|
|
unsigned int score_a = compute_player_score(grid, 'A');
|
|
unsigned int score_b = compute_player_score(grid, 'B');
|
|
std::cout << "Player A: " << score_a << std::endl;
|
|
std::cout << "Player B: " << score_b << std::endl;
|
|
if (score_a == score_b) {
|
|
std::cout << "It's a draw!" << std::endl;
|
|
} else {
|
|
char winner;
|
|
if (score_a > score_b)
|
|
winner = 'A';
|
|
else
|
|
winner = 'B';
|
|
std::cout << "Player " << winner << " wins!" << std::endl;
|
|
}
|
|
}
|