-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.c
269 lines (225 loc) · 8.51 KB
/
main.c
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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "board.h"
#include "engine.h"
#define MAX_CELLS 128 // Defines the max number of cells that can exist in the board
/* Program Functions' Declaration */
void showMenu();
int getSafeCellsFromConfigFile(char *fileName, int *safeCells);
void freeBoardCells(list* boardCells);
int main(int argc, char const *argv[])
{
/* Program variables */
// Default values for 'Board Presentation Mode', 'Number of Lines' and 'Number of Columns'
unsigned int boardPresentationMode = 0, linesNum = 3, columnsNum = 7;
unsigned long int argConversionResult; // Variable used to get convert cli args to int
char *tempArg; // Variable used to get convert cli args to int
int safeCells[MAX_CELLS] = {0}; // Stores the safe cells read from the config file
unsigned int totalCells; // Number of total cells
list boardCells; // List struct to store all board cells data
char inputOption; // Stores user input option
bool player1; // Holds the player for the current play
unsigned int dicesValue; // Holds dices value for each move
int gameOver; // Holds the return of the 'checkGameWin' function
bool rollDices = true; // Whether dices should be rolled again or not
bool printBoard = true; // Whether board should be printed or not
// Initializes random seed
srand(1);
// Gets program args and checks if they're valid
for (int i = 1; i < argc; i++) {
// Checks if 'Board Presentation Mode' argument is set and valid
if (i == 1) {
argConversionResult = argv[i][0] == '0' || argv[i][0] == '1' ? argv[i][0] - '0' : -1;
if (argConversionResult == 0 || argConversionResult == 1) {
boardPresentationMode = argConversionResult;
} else {
puts(INVAL_PARAMS);
return 0;
}
}
// Checks if the 'Number of lines' is set and valid
if (i == 2) {
argConversionResult = strtoul(argv[i], &tempArg, 10);
if (argConversionResult >= MIN_ROWS && argConversionResult % 2 != 0) {
linesNum = argConversionResult;
} else {
puts(INVAL_PARAMS);
return 0;
}
}
// Checks if the 'Number of Columns' is set and valid
if (i == 3) {
argConversionResult = strtoul(argv[i], &tempArg, 10);
if (argConversionResult > MIN_COLS) {
columnsNum = argConversionResult;
} else {
puts(INVAL_PARAMS);
return 0;
}
}
// Checks if the 'Configuration File' is present and reads its content
if (i == 4) {
// Reads safe cells from config file and stores them in an array
int getSafeCells = getSafeCellsFromConfigFile((char*)argv[i], safeCells);
// Exits program if it fails to get safe cells from the config file
if (getSafeCells == 1) {
return 0;
}
}
}
// Updates the number of total cells based on given arguments
totalCells = linesNum * 2 + (columnsNum - 2) * 2;
// Initializes the board cells list
initializeCellsList(&boardCells);
// Adds cells to board (Board Setup)
boardSetup(&boardCells, safeCells, totalCells);
// Prints game info for the first time
boardPrint(linesNum, columnsNum, boardCells, boardPresentationMode); // Prints board
showMenu(); // Prints menu
player1 = true; // Sets player 1 as the starting player
// Game Loop
do {
/*
Checks if game is over (i.e. if a player won)
It it is, prints the winner and exits program
*/
gameOver = checkGameWin(&boardCells, totalCells);
// Checks if P1 won
if (gameOver == 1) {
// Frees all mem allocs related to board
freeBoardCells(&boardCells);
puts(PL1_WINS);
puts(EXIT_MSG);
return 0;
}
// Checks if P2 won
if (gameOver == 2) {
// Frees all mem allocs related to board
freeBoardCells(&boardCells);
puts(PL2_WINS);
puts(EXIT_MSG);
return 0;
}
// Prints current player move
if (player1) {
puts(PL1_MOVE);
} else {
puts(PL2_MOVE);
}
// Rolls dices for current player move and prints the value
if (rollDices) {
dicesValue = rolldice(2);
rollDices = true;
}
printf("%s %d\n", PL_DICE, dicesValue);
printf(">"); // Input cursor
scanf(" %c", &inputOption); // Reads user input
switch (inputOption) {
case 'h':
showMenu();
rollDices = false;
printBoard = false;
break;
case 's':
// Prints end game message and exits
puts(EXIT_MSG);
// Do not print board before exiting game
printBoard = false;
// Frees all mem allocs related to board
freeBoardCells(&boardCells);
// Skips to the end
break;
default:
// Checks if the inserted pawn is valid
if (validPawn(inputOption, player1) && isPawnMovable(inputOption, &boardCells, player1)) {
makePlay(&boardCells, inputOption, dicesValue);
// Changes player move after previous play is finished
player1 = !player1;
} else {
// Invalid option ERROR message
puts(INVAL_MOVE);
rollDices = false;
printBoard = false;
}
break;
}
// Prints the board again after the play or not
if (printBoard) {
boardPrint(linesNum, columnsNum, boardCells, boardPresentationMode); // Prints board
}
printBoard = true;
} while (inputOption != 's');
return 0;
}
/* Program Functions */
/**
* @brief Prints the game menu.
*
*/
void showMenu() {
puts("+------------------------------------+");
puts("| Nao Te Constipes |");
puts("+------------------------------------+");
puts("| <id do peao> (abcd, xyzw) |");
puts("| s - sair |");
puts("| h - imprimir menu |");
puts("+------------------------------------+");
}
/**
* @brief Gets the board safe cells from the config file given as a program argument
* @param fileName The name of the config file
* @param safeCells An array which stores all the safe cells read from the config file
* @return Returns 0 on 'SUCCESS' and 1 on 'FAILURE'
*/
int getSafeCellsFromConfigFile(char *fileName, int *safeCells) {
FILE *fp;
int numberRead;
// Prints message before opening the file to be read
printf("fich %s\n", fileName);
// Opens config file in 'read' mode
fp = fopen(fileName, "r");
// Checks for file read errors
if (fp == NULL) {
fputs(FILE_ERR1, stdout);
fputs(INVAL_PARAMS, stdout);
return 1;
}
// Reads all numbers from config file and stores them in 'safeCells'
while (!feof(fp)) {
if (fscanf(fp, "%d", &numberRead) == 0) {
// Prints ERROR message and breaks the loop in case the read value is not valid
printf("%s", FILE_ERR2);
puts(INVAL_PARAMS);
return 1;
}
if (numberRead < MAX_CELLS) {
safeCells[numberRead] = 1;
} else {
// Prints ERROR message in case the number read is greater the the max number of cells
printf("%s", FILE_ERR2);
puts(INVAL_PARAMS);
return 1;
}
}
// Closes file stream
fclose(fp);
return 0;
}
/**
* @brief Frees all memory allocations related to the board nodes.
* @param boardCells Linked list with board cells
*/
void freeBoardCells(list* boardCells) {
node *currentNode = boardCells->head; // Stores current node
node *nextNode = currentNode->next; // Stores next node
for (int cell = 0; cell < boardCells->length; cell++) {
free(currentNode);
if (cell != boardCells->length - 1) {
// Updates 'currentNode' and 'nextNode'
currentNode = nextNode;
nextNode = currentNode->next;
}
}
}