This commit is contained in:
Sandipsinh Rathod 2024-12-06 17:06:18 -05:00
commit c1c4586abd
No known key found for this signature in database
13 changed files with 901 additions and 0 deletions

12
CMakeLists.txt Normal file

@ -0,0 +1,12 @@
cmake_minimum_required(VERSION 3.29)
project(cmpsc330hw5)
set(CMAKE_CXX_STANDARD 20)
add_executable(cmpsc330hw5
main.cxx
board.cxx
dotsboxesgm.cxx
strategic_player.h
strategic_player.cxx
)

74
board.cxx Normal file

@ -0,0 +1,74 @@
#include <iostream>
#include <assert.h>
#include "common.h"
#include "board.h"
using namespace std;
void Board::AllocateBoard(int dots_in_rows, int dots_in_cols, int& blanklinecount)
{
assert(board == nullptr);
rows = dots_in_rows * 2 - 1;
cols = dots_in_cols * 2 - 1;
board = new char* [rows];
for(int r = 0; r < rows; r++)
board[r] = new char[cols];
blanklinecount = 0;
for(int r = 0; r < rows; r ++)
for(int c = 0; c < cols; c ++)
{
board[r][c] = ' ';
if(Loc(r, c).IsLineLocation())
blanklinecount++;
}
for(int r = 0; r < rows; r += 2)
for(int c = 0; c < cols; c += 2)
board[r][c] = '.';
}
void Board::FreeBoard()
{
if(board != nullptr)
{
for(int r = 0; r < rows; r++)
delete[] board[r];
delete[] board;
board = nullptr;
}
}
ostream& operator << (ostream& os, const Board& board)
{
cout << " ";
for(int i=0; i<board.cols; i++)
{
if(i % 10 == 0) cout << (i/10);
else cout << ' ';
}
cout << endl;
cout << " ";
for(int i=0; i<board.cols; i++)
cout << (i%10);
cout << endl;
for(int r=0; r<board.GetRows(); r++)
{
if(r%10 == 0) cout << (r/10) << (r%10) << ' ';
else cout << ' ' << (r%10) << ' ';
for(int c=0; c<board.GetCols(); c++)
{
Loc loc(r,c);
char b_rc = board(r,c);
if(b_rc == ' ') cout << b_rc;
else if(loc.IsLineVerticalLocation () && b_rc != ' ') cout << "|";
else if(loc.IsLineHorizontalLocation() && b_rc != ' ') cout << "-";
else cout << b_rc;
}
cout << endl;
}
return os;
}

48
board.h Normal file

@ -0,0 +1,48 @@
#ifndef __BOARD__
#define __BOARD__
class IBoard
{
public:
virtual int GetRows() const = 0;
virtual int GetCols() const = 0;
virtual char operator()(int row, int col) const = 0;
virtual char operator()(const Loc& loc ) const = 0;
virtual char& operator()(int row, int col) = 0;
virtual char& operator()(const Loc& loc ) = 0;
};
class Board : public IBoard
{
char** board;
int rows, cols;
public:
Board()
{
rows = cols = -1;
board = nullptr;
}
//Board(int dots_in_rows, int dots_in_cols)
//{
// AllocateBoard(dots_in_rows, dots_in_cols);
//}
~Board()
{
FreeBoard();
}
void AllocateBoard(int dots_in_rows, int dots_in_cols, int& blanklinecount);
void FreeBoard();
void AllocateBoard(int dots_in_rows, int dots_in_cols) { int blanklinecount; AllocateBoard(dots_in_rows, dots_in_cols, blanklinecount); }
int GetRows() const { return rows; }
int GetCols() const { return cols; }
char& operator()(int row, int col) { return board[ row][ col]; }
char operator()(int row, int col) const { return board[ row][ col]; }
char& operator()(const Loc& loc ) { return board[loc.row][loc.col]; }
char operator()(const Loc& loc ) const { return board[loc.row][loc.col]; }
friend ostream& operator << (ostream& os, const Board& board);
};
#endif

22
common.h Normal file

@ -0,0 +1,22 @@
#ifndef __COMMON__
#define __COMMON__
#include <iostream>
#include <string>
using namespace std;
class Loc
{
public:
int row, col;
Loc() { row = -1; col = -1; }
Loc(const Loc& loc) { row = loc.row; col = loc.col; }
Loc(int nr, int nc) { row = nr; col = nc; }
bool IsDotLocation() const { return ((row % 2 == 0) && (col % 2 == 0)); }
bool IsBoxLocation() const { return ((row % 2 == 1) && (col % 2 == 1)); }
bool IsLineHorizontalLocation() const { return ((row % 2 == 0) && (col % 2 == 1)); }
bool IsLineVerticalLocation() const { return ((row % 2 == 1) && (col % 2 == 0)); }
bool IsLineLocation() const { return IsLineHorizontalLocation() || IsLineVerticalLocation(); }
};
#endif

306
dotsboxesgm.cxx Normal file

@ -0,0 +1,306 @@
#include <iostream>
#include <time.h>
#include <chrono>
#include <assert.h>
#include <vector>
#include "common.h"
#include "board.h"
#include "player.h"
void ClearConsole();
void SleepInSec(double sleep_sec);
extern void* a_player_libhandle;
extern void* b_player_libhandle;
string LoadPlayer(IPlayer*& ab_player, string libpath, int board_rows, int board_cols, char box_type, char line_type);
void CloseLibs();
struct PlayerInfo
{
public:
IPlayer* iplayer;
int score;
char box;
char line;
double timespent;
PlayerInfo* next; // play-list (linked list)
PlayerInfo* prev; // play-list (linked list)
PlayerInfo(IPlayer* p, char b, char l)
{
iplayer = p;
score = 0;
box = b;
line = l;
timespent = 0;
}
};
void PrintBoard(int iter, const Board& board, const vector<PlayerInfo>& players)
{
// print board
cout << board;
cout << endl;
// print iteration number
cout << "iter : " << iter << endl;
// find winning scores and winner numbers
int maxscore = 0;
int maxscore_cnt = 0;
for(int i=0; i<players.size(); i++)
{
if(maxscore < players[i].score)
{
maxscore = players[i].score;
maxscore_cnt = 0;
}
if(maxscore == players[i].score)
maxscore_cnt ++;
}
// print player status (boxes, win/tie)
for(int i=0; i<players.size(); i++)
{
cout << "Player " << players[i].box << " (" << players[i].iplayer->PlayerInfo() << ") has ";
if(players[i].score >= 2) cout << players[i].score << " boxes";
else cout << players[i].score << " box";
cout << " and spent " << players[i].timespent*100 << " msec";
if(maxscore == players[i].score)
{
if(maxscore_cnt == 1) cout << " (win)." << endl;
else cout << " (tie)." << endl;
}
else
{
cout << "." << endl;
}
}
cout << endl;
}
// send add-line event to players
void EventAddLine(const vector<PlayerInfo>& players, char line, const Loc& loc)
{
for(int j = 0; j < players.size(); j++)
{
if(players[j].next == nullptr)
continue;
players[j].iplayer->EventAddLine(line, loc);
}
}
// send add-box event to players
void EventAddBox(const vector<PlayerInfo>& players, char box, const Loc& loc)
{
for(int j = 0; j < players.size(); j++)
{
if(players[j].next == nullptr)
continue;
players[j].iplayer->EventAddBox(box, loc);
}
}
// update box with player box info, and return true (for gaining box) or false (for not gaining box)
bool AddBox(Board& board, int row, int col, char box, const vector<PlayerInfo>& players)
{
assert(Loc(row,col).IsBoxLocation());
if(board(row,col) == ' '
&& board(row+1,col) != ' '
&& board(row-1,col) != ' '
&& board(row,col+1) != ' '
&& board(row,col-1) != ' ')
{
board(row,col) = box;
EventAddBox(players, box, Loc(row,col));
return true;
}
return false;
}
string GameMaster(const vector<string>& libpaths, vector<int>& scores, vector<double>& timespents, double sleep_sec)
{
///////////////////////////////////////////////////
// create board
int board_rows, board_cols, board_blanklinecount;
cin >> board_rows >> board_cols;
cout << endl;
Board board;
board.AllocateBoard(board_rows, board_cols, board_blanklinecount);
///////////////////////////////////////////////////
// load players
vector<PlayerInfo> players;
int ibox = 0;
for(int i=0; i<libpaths.size(); i++)
{
string libpath = libpaths[i];
IPlayer* player = nullptr;
char box_type = 'A' + ibox;
char line_type = 'a' + ibox;
ibox++;
if(box_type == 'E' || box_type == 'X')
{
box_type = 'A' + ibox;
line_type = 'a' + ibox;
ibox++;
}
string message = "";
try
{
message = LoadPlayer(player, libpath, board_rows, board_cols, box_type, line_type);
if(message != "")
{
cout << message << endl;
cout << "Library error while loading a player (" << libpath << ")." << endl;
if(player != nullptr)
player->Close();
continue;
}
players.push_back(PlayerInfo(player, box_type, line_type));
}
catch(...)
{
cout << "Exception while loading a player (" << libpath << ")." << endl;
if(player != nullptr)
player->Close();
continue;
}
}
///////////////////////////////////////////////////
// set player sequence and first player
int iter = 0;
for(int i=0; i<players.size(); i++)
{
int next_idx = (i+1) % players.size();
int prev_idx = (i-1) % players.size();
players[i].next = &(players[next_idx]);
players[i].prev = &(players[prev_idx]);
}
PlayerInfo* player = &(players[0]);
///////////////////////////////////////////////////
// play game
while(true)
{
iter++;
////////////////////////////////////////////////////////////
// stop if there is no player to play
if(player == nullptr)
break;
// stop if the board is full
if(board_blanklinecount == 0)
break;
// print play-log
if(sleep_sec == 0)
cout << "Player " << player->box;
////////////////////////////////////////////////////////////
// determine player's line location
// if the player put a line into a invalid location, then makr the player lose
Loc loc;
double timespent = 0;
try
{
auto begin = chrono::high_resolution_clock::now();
loc = player->iplayer->SelectLineLocation();
auto end = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin);
player->timespent += (elapsed.count() * 1e-9);
if(loc.IsBoxLocation()) throw "lose";
if(loc.IsDotLocation()) throw "lose";
if(board(loc) != ' ' ) throw "lose";
}
catch(...)
{
// if the player put line into a wrong location or throw exception,
// make the player have -1 score (invalid move) and
// remove the player from play-list (linked-list)
player->score = -1;
if(player->next == player)
{
// if player is the last player, make the linked-list empty
player = nullptr;
}
else
{
// if the player is not the last player, remove the player in the linked-list, and select the next player
PlayerInfo* next_player = player->next;
player->next->prev = player->prev;
player->prev->next = player->next;
player->next = nullptr;
player->prev = nullptr;
player = next_player;
}
// print play-log
if(sleep_sec == 0)
cout << " made an invalid move." << endl;
continue;
}
////////////////////////////////////////////////////////////
// add the line into the board
assert(loc.IsLineLocation());
assert(board(loc) == ' ' );
board(loc) = player->line;
board_blanklinecount --;
EventAddLine(players, player->line, loc);
////////////////////////////////////////////////////////////
// if the player gain a box, then
// mark the box owner and
// make gainbox true
int gainbox = 0;
if(loc.IsLineHorizontalLocation())
{
if(loc.row-1 >= 0 ) if(AddBox(board, loc.row-1, loc.col, player->box, players)) { player->score++; gainbox++; }
if(loc.row+1 < board.GetRows()) if(AddBox(board, loc.row+1, loc.col, player->box, players)) { player->score++; gainbox++; }
}
if(loc.IsLineVerticalLocation())
{
if(loc.col-1 >= 0 ) if(AddBox(board, loc.row, loc.col-1, player->box, players)) { player->score++; gainbox++; }
if(loc.col+1 < board.GetCols()) if(AddBox(board, loc.row, loc.col+1, player->box, players)) { player->score++; gainbox++; }
}
////////////////////////////////////////////////////////////
// print board or play-log
if(sleep_sec == 0)
{
cout << " add a line at (" << loc.row << "," << loc.col << ")";
if(gainbox == 1)
cout << " and gain " << gainbox << " box." << endl;
else if(gainbox >= 2)
cout << " and gain " << gainbox << " boxes." << endl;
else
cout << "." << endl;
}
else
{
ClearConsole();
PrintBoard(iter, board, players);
SleepInSec(sleep_sec);
}
////////////////////////////////////////////////////////////
// if the player does not gain a box
// move to the next player
if(gainbox == 0)
player = player->next;
}
////////////////////////////////////////////////////////////
// print board
if(sleep_sec != 0) ClearConsole();
else cout << endl;
PrintBoard(iter, board, players);
for(int i = 0; i < players.size(); i++)
{
scores [i] = players[i].score;
timespents[i] = players[i].timespent;
}
return "";
}

3
input1.txt Normal file

@ -0,0 +1,3 @@
3 8
A Strategic
B Random

78
main.cxx Normal file

@ -0,0 +1,78 @@
#include <cassert>
#include <vector>
#include "player.h"
using namespace std;
#include <unistd.h> // usleep()
#include <dlfcn.h>
string GameMaster(const vector<string> &libpaths, vector<int> &scores, vector<double> &timespents, double sleep_sec);
void CloseLibs();
int main(int argc, char *argv[]) {
// argv[0] : program name
// argv[1] : 1st player library path
// argv[2] : 2nd player library path
// argv[3] : 3rd player library path
if (argc <= 2)
return 0;
vector<string> libpaths;
vector<int> scores;
vector<double> timespents;
for (int i = 1; i < argc; i++) {
libpaths.push_back(argv[i]);
scores.push_back(0);
timespents.push_back(0);
}
double sleep_sec = 0.00;
string result = GameMaster(libpaths, scores, timespents, sleep_sec);
CloseLibs();
}
void ClearConsole() {
system("clear");
}
void SleepInSec(double sleep_sec) {
int sleep_microsecond = sleep_sec * 1000000;
usleep(sleep_microsecond);
}
vector<void *> lst_player_libhandle;
typedef IPlayer *(*CreatePlayerType)();
string LoadPlayer
(IPlayer *&iplayer, string libpath, int board_rows // the size of board (including dots, lines, and boxes)
, int board_cols // the size of board (including dots, lines, and boxes)
, char box_type // the character for the player's boxes
, char line_type // the character for the player's lines
) {
void *player_libhandle = dlopen(libpath.c_str(), RTLD_LAZY);
if (player_libhandle == nullptr) {
return "cannot load " + libpath;
}
lst_player_libhandle.push_back(player_libhandle);
void *pfunc = dlsym(player_libhandle, "PlayerFactory");
if (pfunc == nullptr) {
return "cannot find PlayerFactory() function defined as extern C";
}
CreatePlayerType CreatePlayer = (CreatePlayerType) pfunc;
iplayer = CreatePlayer();
iplayer->Init(board_rows, board_cols, box_type, line_type);
if (iplayer == nullptr) {
return "cannot create player using PlayerFactory() function";
}
return "";
}
void CloseLibs() {
for (void *player_libhandle: lst_player_libhandle)
dlclose(player_libhandle);
lst_player_libhandle.clear();
}

35
player.h Normal file

@ -0,0 +1,35 @@
#ifndef __PLAYER__
#define __PLAYER__
#include <iostream>
#include "common.h"
#include "board.h"
using namespace std;
class IPlayer
{
public:
// return the player information that includes full name and email address,
// such that "Micky Mouse (mm123@psu.edu)"
virtual string PlayerInfo() = 0;
// Init(const int,const int) will be called before playing the game
// You can create your own data-structure
virtual void Init
( int board_rows // the size of board (including dots, lines, and boxes)
, int board_cols // the size of board (including dots, lines, and boxes)
, char box_type // the character for the player's boxes
, char line_type // the character for the player's lines
) = 0;
// Close() will be called after finishing playing the game
// You can remove all dynamically allocated memories
virtual void Close() = 0;
// EventAddLine() and EventAddBox() will be called
// when a player adds a line or when a system assign a box's owner
virtual void EventAddLine(char bar, const Loc& loc) = 0;
virtual void EventAddBox (char box, const Loc& loc) = 0;
// Loc SelectLineLocation() will be called
// when the game system ask where your player want to add a line
virtual Loc SelectLineLocation() = 0;
};
#endif

79
random_player.cxx Normal file

@ -0,0 +1,79 @@
#include <iostream>
#include <assert.h>
#include <cstdlib> // for srand and rand
#include <ctime> // for time
#include "common.h"
#include "player.h"
#include "random_player.h"
using namespace std;
extern "C" IPlayer* PlayerFactory()
{
return new RandomPlayer();
}
RandomPlayer::RandomPlayer()
{
srand(time(0));
}
RandomPlayer::~RandomPlayer()
{
}
void RandomPlayer::Init(int _dots_in_rows, int _dots_in_cols, char _player_box, char _player_line)
{
board.AllocateBoard(_dots_in_rows, _dots_in_cols);
player_box = _player_box ;
player_line = _player_line;
emptylines = new Loc[board.GetRows() * board.GetCols()];
}
void RandomPlayer::Close()
{
board.FreeBoard();
int emptylines_cnt = board.GetRows() * board.GetCols();
delete[] emptylines;
}
void RandomPlayer::EventAddLine(const char bar, const Loc& loc)
{
assert(loc.IsLineLocation());
assert(board(loc) == ' ');
board(loc) = bar;
}
void RandomPlayer::EventAddBox(const char box, const Loc& loc)
{
assert(loc.IsBoxLocation());
assert(board(loc) == ' ');
board(loc) = box;
}
Loc RandomPlayer::SelectLineLocation()
{
ListEmptyLines();
int randloc = rand() % emptylines_cnt;
return emptylines[randloc];
}
void RandomPlayer::ListEmptyLines()
{
emptylines_cnt = 0;
for(int row=0; row<board.GetRows(); row++)
{
for(int col=0; col<board.GetCols(); col++)
{
if((row % 2 == 0) && (col % 2 == 0)) continue; // dot
if((row % 2 == 1) && (col % 2 == 1)) continue; // box
if(board(row, col) == ' ')
{
emptylines[emptylines_cnt].row = row;
emptylines[emptylines_cnt].col = col;
emptylines_cnt ++;
}
}
}
}

32
random_player.h Normal file

@ -0,0 +1,32 @@
#ifndef __RANDOM_PLAYER__
#define __RANDOM_PLAYER__
#include <iostream>
#include "common.h"
#include "player.h"
#include "board.h"
using namespace std;
class RandomPlayer : public IPlayer
{
private:
Board board;
char player_box;
char player_line;
Loc* emptylines;
int emptylines_cnt;
public:
RandomPlayer();
~RandomPlayer();
string PlayerInfo() { return "random player"; }
void Init(int dots_in_rows, int dots_in_cols, char player_box, char player_line);
// Close() will be called after finishing playing the game
// You can remove all dynamically allocated memories
void Close();
void EventAddLine(char bar, const Loc& loc);
void EventAddBox(char box, const Loc& loc);
Loc SelectLineLocation();
void ListEmptyLines();
};
#endif

10
readme.txt Normal file

@ -0,0 +1,10 @@
Build mazerunner program and player_randommove.so library
g++ -ansi -pedantic -std=c++14 board.cxx dotsboxesgm.cxx main.cxx -o dotsboxes
g++ -shared -fPIC -ansi -pedantic -std=c++14 random_player.cxx board.cxx -o random_player.so
playing the dots and boxes games with multiple players
./dotsboxes ./strategic_player.so ./random_player.so ./strategic_player.so ./random_player.so

164
strategic_player.cxx Normal file

@ -0,0 +1,164 @@
#include "strategic_player.h"
#include "common.h"
extern "C" IPlayer* PlayerFactory()
{
return new StrategicPlayer();
}
string StrategicPlayer::PlayerInfo() {
return "Sapan Shah (scs6041@psu.edu), Sandipsinh Rathod (sdr5549@psu.edu)";
}
void StrategicPlayer::Init(int board_rows, int board_cols, char box_type, char line_type) {
this->name = box_type;
this->box_name = line_type;
this->board.AllocateBoard(board_rows, board_cols);
}
StrategicPlayer::~StrategicPlayer() {
board.FreeBoard();
}
void StrategicPlayer::Close() {
board.FreeBoard();
}
int normalize(int x) {
return (x + 1) >> 1;
}
char getPoint(Board &board, const int row, const int col) {
return board(row, col);
}
bool isLineValid(Board &board, const int row, const int col) {
return (row > -1 && row < board.GetRows() && col > -1 && col < board.GetCols()) &&
((row & 1) != (col & 1)) && (getPoint(board, row, col) == ' ');
}
void set(Board &board, int r, int c, char ch) {
board(r, c) = ch;
}
/// TODO: check if we needs checks :)
void StrategicPlayer::EventAddLine(char bar, const Loc &loc) {
set(board, loc.row, loc.col, bar);
}
void StrategicPlayer::EventAddBox(char box, const Loc &loc) {
set(board, loc.row, loc.col, box);
}
void selectLine(Board &board, int &row, int &col, int rows, int cols, char name) {
// Step 1: Try to complete a box
for (int r = 1; r < 2 * rows - 2; r += 2) {
// Iterate over box centers (odd rows)
for (int c = 1; c < 2 * cols - 2; c += 2) {
// Iterate over box centers (odd cols)
// Check adjacent lines for an opportunity to complete a box
if (isLineValid(board, r - 1, c) && // Top line
getPoint(board, r + 1, c) != ' ' && // Bottom line
getPoint(board, r, c - 1) != ' ' && // Left line
getPoint(board, r, c + 1) != ' ') {
// Right line
row = r - 1;
col = c;
return;
}
if (isLineValid(board, r + 1, c) && // Bottom line
getPoint(board, r - 1, c) != ' ' && // Top line
getPoint(board, r, c - 1) != ' ' && // Left line
getPoint(board, r, c + 1) != ' ') {
// Right line
row = r + 1;
col = c;
return;
}
if (isLineValid(board, r, c - 1) && // Left line
getPoint(board, r - 1, c) != ' ' && // Top line
getPoint(board, r + 1, c) != ' ' && // Bottom line
getPoint(board, r, c + 1) != ' ') {
// Right line
row = r;
col = c - 1;
return;
}
if (isLineValid(board, r, c + 1) && // Right line
getPoint(board, r - 1, c) != ' ' && // Top line
getPoint(board, r + 1, c) != ' ' && // Bottom line
getPoint(board, r, c - 1) != ' ') {
// Left line
row = r;
col = c + 1;
return;
}
}
}
// Step 2: Avoid moves that leave a box with one line remaining
for (int r = 0; r < 2 * rows - 1; ++r) {
// Iterate over all valid rows
for (int c = 0; c < 2 * cols - 1; ++c) {
// Iterate over all valid cols
if (isLineValid(board, r, c)) {
// Simulate placing the line
set(board, r, c, name);
// Check if this move leaves a box with only one line remaining
bool createsOpportunity = false;
for (int nr = 1; nr < 2 * rows - 2; nr += 2) {
// Iterate over box centers
for (int nc = 1; nc < 2 * cols - 2; nc += 2) {
if (getPoint(board, nr, nc) == ' ') {
int adjacentLines = 0;
if (nr > 0 && getPoint(board, nr - 1, nc) != ' ') adjacentLines++; // Top line
if (nr < 2 * rows - 2 && getPoint(board, nr + 1, nc) != ' ') adjacentLines++; // Bottom line
if (nc > 0 && getPoint(board, nr, nc - 1) != ' ') adjacentLines++; // Left line
if (nc < 2 * cols - 2 && getPoint(board, nr, nc + 1) != ' ') adjacentLines++; // Right line
if (adjacentLines == 3) {
// Opponent can complete this box
createsOpportunity = true;
break;
}
}
}
if (createsOpportunity) break;
}
set(board, r, c, ' '); // Undo the simulated move
if (!createsOpportunity) {
row = r;
col = c;
return;
}
}
}
}
// Step 3: Fallback to the first valid move
for (int r = 0; r < 2 * rows - 1; ++r) {
for (int c = 0; c < 2 * cols - 1; ++c) {
if (isLineValid(board, r, c)) {
row = r;
col = c;
return;
}
}
}
}
Loc StrategicPlayer::SelectLineLocation() {
int rows = normalize(board.GetRows());
int cols = normalize(board.GetCols());
int row, col;
selectLine(board, row, col, rows, cols, name);
return Loc(row, col);
}

38
strategic_player.h Normal file

@ -0,0 +1,38 @@
#ifndef HW4_STRATEGIC_PLAYER_H
#define HW4_STRATEGIC_PLAYER_H
#include "common.h"
#include "board.h"
#include "player.h"
class StrategicPlayer: public IPlayer {
char name;
char box_name;
Board board;
public:
string PlayerInfo();
// Init(const int,const int) will be called before playing the game
// You can create your own data-structure
void Init
( int board_rows // the size of board (including dots, lines, and boxes)
, int board_cols // the size of board (including dots, lines, and boxes)
, char box_type // the character for the player's boxes
, char line_type // the character for the player's lines
);
// Close() will be called after finishing playing the game
// You can remove all dynamically allocated memories
void Close();
// EventAddLine() and EventAddBox() will be called
// when a player adds a line or when a system assign a box's owner
void EventAddLine(char bar, const Loc& loc);
void EventAddBox (char box, const Loc& loc);
// Loc SelectLineLocation() will be called
// when the game system ask where your player want to add a line
Loc SelectLineLocation();
~StrategicPlayer();
};
#endif //HW4_STRATEGIC_PLAYER_H