Patolli in C++

Nathan Mack

This project was the final assignment for my C++ programming course at Old Dominion University, where we were asked to recreate a text-based version of Patolli, a strategic Mesoamerican board game. The program is built entirely in C++ using object-oriented design with custom ADTs for the player, board, and referee. It handles everything from input validation and turn management to movement rules and win conditions.

What I’m most proud of is how this project showcases my problem-solving skills — translating a physical board game into structured logic, managing complex game state, and designing interactions between multiple components without any visual interface. The full source code is included below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#include <iostream>
#include <string>
#include <stdlib.h>
#include <time.h>

using namespace std;

// used for spacing in board
const string space = " ";
const string bar = "-----";
const string midspace = "--------------";

class Player
{
string name;
int score;
string pieces;

public:
// constructor
Player(char t)
{
name = t;
score = 0;
pieces = (t == 'L') ? "ABCDEF" : "123456";
}
// getters and setters
void SetScore(int s) { score = s; }
int GetScore() { return score; }
string GetName() { return name; }
string GetPieces() { return pieces; }
};

class Board
{
// array of spaces on the board
char board[60];

public:
// constructor
Board()
{
for (int i = 0; i < 60; i++)
board[i] = ' ';
}
// getters and setters
void SetValue(int x, char v) { board[x] = v; }
char GetValue(int x) { return board[x]; }
// draws board with pieces
void DrawBoard()
{
cout << space << bar << endl;
cout << space << "|" << board[7] << "|" << board[8] << "|" << endl;
cout << space << bar << endl;
cout << space << "|" << board[6] << "|" << board[9] << "|" << endl;
cout << space << bar << endl;
cout << space << "|" << board[5] << "|" << board[10] << "|" << endl;
cout << space << bar << endl;
cout << space << "|" << board[4] << "|" << board[11] << "|" << endl;
cout << space << bar << endl;
cout << space << "|" << board[3] << "|" << board[12] << "|" << endl;
cout << space << bar << endl;
cout << space << "|" << board[2] << "|" << board[13] << "|" << endl;
cout << space << bar << endl;
cout << space << "|" << board[1] << "|" << board[14] << "|" << endl;
cout << midspace << bar << midspace << endl;
cout << "|" << board[53] << "|" << board[54] << "|" << board[55] << "|" << board[56]
<< "|" << board[57] << "|" << board[58] << "|" << board[59] << "|" << board[0]
<< "|" << board[15] << "|" << board[16] << "|" << board[17] << "|" << board[18]
<< "|" << board[19] << "|" << board[20] << "|" << board[21] << "|" << board[22] << "|" << endl;
cout << midspace << bar << midspace << endl;
cout << "|" << board[52] << "|" << board[51] << "|" << board[50] << "|" << board[49]
<< "|" << board[48] << "|" << board[47] << "|" << board[46] << "|" << board[45]
<< "|" << board[30] << "|" << board[29] << "|" << board[28] << "|" << board[27]
<< "|" << board[26] << "|" << board[25] << "|" << board[24] << "|" << board[23] << "|" << endl;
cout << midspace << bar << midspace << endl;
cout << space << "|" << board[44] << "|" << board[31] << "|" << endl;
cout << space << bar << endl;
cout << space << "|" << board[43] << "|" << board[32] << "|" << endl;
cout << space << bar << endl;
cout << space << "|" << board[42] << "|" << board[33] << "|" << endl;
cout << space << bar << endl;
cout << space << "|" << board[41] << "|" << board[34] << "|" << endl;
cout << space << bar << endl;
cout << space << "|" << board[40] << "|" << board[35] << "|" << endl;
cout << space << bar << endl;
cout << space << "|" << board[39] << "|" << board[36] << "|" << endl;
cout << space << bar << endl;
cout << space << "|" << board[38] << "|" << board[37] << "|" << endl;
cout << space << bar << endl;
}
};

class Referee
{
Player* playerL;
Player* playerN;
Board* board;
bool gameover;

public:
// constructor
Referee()
{
playerL = new Player('L');
playerN = new Player('N');
board = new Board();
gameover = false;
}
// main gameplay function
void Play()
{
int turn = 1;
int lastturn = 0;
int diceRoll = 0;
int spot = 0;
char input = ' ';

// loop until winner
while (!gameover)
{
// decide current player
Player* currentPlayer = (turn % 2 == 1) ? playerL : playerN;
srand(time(NULL));
system("CLS");
board->DrawBoard();
// figure out if last move ended or if it is prompting for re-input
if (lastturn != turn) {
diceRoll = rand() % 6;
lastturn = turn;
} else {
if (spot == 7 || spot == 8 || spot == 22 || spot == 23 || spot == 37 || spot == 38 || spot == 52 || spot == 53) {
cout << "You landed on the edge! Move again." << endl << endl;
diceRoll = rand() % 6;
} else {
cout << "Invalid Move! Try again." << endl << endl;
}
}
// instant pass
if (diceRoll == 0) {
cout << "You rolled a 0. You must pass your turn." << endl << endl;
}
cout << "Player L (Letters) Score: " << playerL->GetScore() << endl;
cout << "Player N (Numbers) Score: " << playerN->GetScore() << endl << endl;
cout << "Player " << currentPlayer->GetName() << "'s Turn (Turn " << turn << ")" << endl;
cout << "The roll is: " << diceRoll << endl;
cout << "Select a piece to move (" << currentPlayer->GetPieces() << " or P to Pass): ";

cin >> input;
input = toupper(input);
// pass turn
if (input == 'P' || diceRoll == 0) {
turn++;
continue;
}
// validate input
if (!(currentPlayer->GetPieces().find(input) < currentPlayer->GetPieces().length())) { continue; }
int position = -1;
// find if piece is on board
for (int i = 0; i < 60; i++) {
if (board->GetValue(i) == input) { position = i; }
}
spot = (position + diceRoll) % 60;
if (position >= 0) {
if (spot != 0 && spot != 15 && spot != 30 && spot != 45) {
if (board->GetValue(spot) != ' ') { continue; } // can't move to occupied space outside of middle
}
board->SetValue(spot, input);
board->SetValue(position, ' ');
if (spot == 7 || spot == 8 || spot == 22 || spot == 23 || spot == 37 || spot == 38 || spot == 52 || spot == 53) { continue; } // extra turn
// scoring
if (currentPlayer->GetName() == "L" && spot == 29) {
board->SetValue(29, ' ');
playerL->SetScore(playerL->GetScore() + 1);
}
if (currentPlayer->GetName() == "N" && spot == 59) {
board->SetValue(59, ' ');
playerN->SetScore(playerN->GetScore() + 1);
}
turn++;
} else {
// add new piece to board
if (currentPlayer->GetName() == "L") {
if (board->GetValue(31) == ' ') { board->SetValue(31, input); } else { continue; }
} else {
if (board->GetValue(1) == ' ') { board->SetValue(1, input); } else { continue; }
}
turn++;
}
// win conditions
if (playerL->GetScore() == 6) {
cout << endl << "PLAYER L WINS" << endl;
gameover = true;
} else if (playerN->GetScore() == 6) {
cout << endl << "PLAYER N WINS" << endl;
gameover = true;
}
}
}
};

int main()
{
Referee Game = Referee();
Game.Play();
return 0;
}

Here’s a screenshot of the game in action. It shows the initial setup phase and part of the turn cycle where players place pieces and roll the die. The visual layout of the board and player prompts were designed to be easy to follow, even in a simple text-based interface.

Initial Game State

State of Game after Move 50

  • Title: Patolli in C++
  • Author: Nathan Mack
  • Created at : April 20th, 2023 12:00 am
  • Updated at : July 26th, 2025 3:07 pm
  • Link: https://nemack.net/2023/04/20/Patolli-in-C/
  • License: This work is licensed under CC BY-NC-SA 4.0.
On this page
Patolli in C++