4 in a row
unknown
plain_text
2 years ago
25 kB
5
Indexable
#include <stdio.h>
#include <stdbool.h>
#define BOARD_MAX_SIDE 9
#define SQUARE_BOARD_MAX_SIDE 81
#define MIN_TOKENS 3
#define RED_SLOT_SYMBOL ('R')
#define YELLOW_SLOT_SYMBOL ('Y')
#define EMPTY_SLOT_SYMBOL (' ')
//----------------------- Returned Identifiers --------------------------//
#define END_THE_GAME 0
#define LEGAL_INPUTS 1
#define LEGAL_BUT_UNRELEVANT -1
#define Filled_NEW_SYMBOL 2
//----------------------- Message Identifiers --------------------------//
#define MSG_GET_BOARD_ROWS 0
#define MSG_GET_BOARD_COLS 1
#define MSG_GET_NUMBER_TOKENS 2
//--------------------------- Board Edges ------------------------------//
#define BOARD_VERT_SEP '|'
#define BOARD_LEFT_ANG '\\'
#define BOARD_RIGHT_ANG '/'
#define BOARD_BOTTOM '-'
#define BOARD_BOTTOM_SEP '-'
//----------------------------------------------------------------------//
void print_welcome_message();
void print_read_game_params_message(int param);
void print_chose_color_message();
void print_chose_move_message(int player);
void print_enter_column_message();
void print_full_column_message();
void print_unavailable_undo_redo_message();
/*
* Outputs game board.
*
* board - contains spaces for empty cells, 'Y' or 'R' for
* respective player cells.
* board_side - contains board dimensions {rows, cols}
*/
void print_board(char board[][BOARD_MAX_SIDE], int board_side[]);
/*
* Outputs winner or tie message.
*
* player_id - the id to be output. Pass <0 for tie.
*/
void print_winner(int player_id);
//----------------------------------------------- My Functions -------------------------------------------------//
int fill_with_empty_slots(char board[][BOARD_MAX_SIDE]);
int min(int a, int b);
char input_symbol();
int input_N();
int input_M(int N);
bool input_rows_and_cols(int board_side[2]);
int input_T(int n, int m);
void match_symbol_to_player(char players_symbols[2]);
int receive_params(char players_symbols[2], int board_side[2], int* tptr, char board[][BOARD_MAX_SIDE]);
bool is_there_moves_to_undo(int history[SQUARE_BOARD_MAX_SIDE + 1]);
bool is_there_moves_to_redo(int undo_history[SQUARE_BOARD_MAX_SIDE - 1]);
bool is_column_not_full(char board[][BOARD_MAX_SIDE], int choosen_col);
int deal_with_undo(int history[SQUARE_BOARD_MAX_SIDE + 1], int undo_history[SQUARE_BOARD_MAX_SIDE - 1],
char board[][BOARD_MAX_SIDE], int board_side[2]);
int deal_with_redo(int history[SQUARE_BOARD_MAX_SIDE + 1], int undo_history[SQUARE_BOARD_MAX_SIDE - 1], int board_side[2],
char board[][BOARD_MAX_SIDE], char symbol);
int deal_with_num(int history[SQUARE_BOARD_MAX_SIDE + 1], int undo_history[SQUARE_BOARD_MAX_SIDE - 1], int board_side[2],
char board[][BOARD_MAX_SIDE], char symbol, int new_element[2], int choosen_col);
int input_until_legal_col(int history[SQUARE_BOARD_MAX_SIDE + 1], int undo_history[SQUARE_BOARD_MAX_SIDE - 1], char board[][BOARD_MAX_SIDE],
int board_side[2], int new_element[2], int player_num, char players_symbols[2]);
int count_right_elements(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2]);
int count_left_elements(char board[][BOARD_MAX_SIDE], int new_element[2]);
bool symbols_in_a_row(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2], int tokens);
int count_upper_elements(char board[][BOARD_MAX_SIDE], int new_element[2]);
int count_lower_elements(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2]);
bool symbols_in_a_column(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2], int tokens);
int count_upper_right_corner(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2]);
int count_lower_left_corner(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2]);
bool symbols_in_a_side_slant(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2], int tokens);
int count_upper_left_corner(char board[][BOARD_MAX_SIDE], int new_element[2]);
int count_lower_right_corner(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2]);
bool symbols_in_a_main_slant(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2], int tokens);
int check_winner(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2], int tokens, int player_num);
int check_tie(char board[][BOARD_MAX_SIDE], int board_side[2]);
int win_or_tie(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2], int tokens, int player_num);
int check_flag(char board[][BOARD_MAX_SIDE], int board_side[2], int flag, int new_element[2], int tokens, int player_num);
int inputed_col_is_legal(int choosen_col, int history[SQUARE_BOARD_MAX_SIDE + 1], int undo_history[SQUARE_BOARD_MAX_SIDE - 1],
char board[][BOARD_MAX_SIDE], int board_side[2], char players_symbols[2], int player_num, int new_element[2]);
//--------------------------- Main Program -----------------------------//
// 13 lines
int main()
{
char board[BOARD_MAX_SIDE][BOARD_MAX_SIDE], players_symbols[2] ;
fill_with_empty_slots(board);
int history[SQUARE_BOARD_MAX_SIDE + 1] = { 0 }, undo_history[SQUARE_BOARD_MAX_SIDE - 1] = { 0 }, board_side[2] = { 0 }, new_element[2] = { 0 };
int T, player_num = 1, flag = receive_params(players_symbols,board_side, &T,board);
while (flag == LEGAL_INPUTS)
{
print_chose_move_message(player_num);
do
{
flag = input_until_legal_col(history, undo_history, board, board_side, new_element,player_num,players_symbols);
}while (flag == LEGAL_BUT_UNRELEVANT);
if (flag == END_THE_GAME)
return 0;
flag = check_flag(board, board_side, flag, new_element, T, player_num);
player_num = 3 - player_num;
}
return 0;
}
// message number 0 = "Welcome to 4-in-a-row game! \n"
void print_welcome_message()
{
printf("Welcome to 4-in-a-row game! \n");
}
// message number 1 = "Please enter number of rows:"
// message number 2 = "Please enter number of columns:"
// message number 3 = "Please enter number of tokens:"
void print_read_game_params_message(int param)
{
char const* const possible_params[] = { "rows", "columns", "tokens" };
printf("Please enter number of %s: ", possible_params[param]);
}
// message number 4 = "Please choose starting color (Y)ellow or (R)ed: "
void print_chose_color_message()
{
printf("Please choose starting color (Y)ellow or (R)ed: ");
}
// message number 5 = "Your move, player <player>. "
void print_chose_move_message(int player)
{
printf("Your move, player %d. ", player);
}
// message number 6
void print_enter_column_message()
{
printf("Please enter column: ");
}
void print_full_column_message()
{
printf("Column full. ");
}
void print_unavailable_undo_redo_message()
{
printf("No moves to undo/redo. ");
}
void print_board(char board[][BOARD_MAX_SIDE], int board_side[])
{
//assert(IS_IN_RANGEI(board_side[0], 0, BOARD_MAX_SIDE)
// && IS_IN_RANGEI(board_side[1], 0, BOARD_MAX_SIDE));
for (int row = 0; row < board_side[0]; ++row)
{
printf("\n%c", BOARD_VERT_SEP);
for (int col = 0; col < board_side[1]; ++col)
printf("%c%c", board[row][col], BOARD_VERT_SEP);
}
printf("\n%c", BOARD_LEFT_ANG);
for (int ii = 0; ii < board_side[1] - 1; ++ii)
printf("%c%c", BOARD_BOTTOM, BOARD_BOTTOM_SEP);
printf("%c%c\n", BOARD_BOTTOM, BOARD_RIGHT_ANG);
}
void print_winner(int player_id)
{
if (player_id >= 0)
printf("Player %d won! \n", player_id);
else
printf("That's a tie. \n");
}
//-------------------------------------------- My Functions ----------------------------------------------//
// fills all the boxes in the board with spaces
// 4 line
int fill_with_empty_slots(char board[][BOARD_MAX_SIDE])
{
for (int i = 0; i < BOARD_MAX_SIDE; i++)
for (int j = 0; j < BOARD_MAX_SIDE; j++)
board[i][j] = EMPTY_SLOT_SYMBOL;
return 0;
}
// returns the minimum between a and b
// 3 lines
int min(int a, int b)
{
if (a > b)
return b;
return a;
}
// receives and returns first player's symbol
// 6 lines
char input_symbol()
{
char first_player;
do
{
print_chose_color_message();
if (!(scanf(" %c", &first_player)))
return '0';
} while ((first_player != RED_SLOT_SYMBOL) && (first_player != YELLOW_SLOT_SYMBOL));
return first_player;
}
// receives and returns rows number
// 6 lines
int input_N()
{
int rows;
do
{
print_read_game_params_message(MSG_GET_BOARD_ROWS);
if (!(scanf(" %d", &rows)))
return END_THE_GAME;
} while ((rows < 3) || (rows > 9));
return rows;
}
// receives and returns columns number
// 6 lines
int input_M(int N)
{
int cols;
do
{
print_read_game_params_message(MSG_GET_BOARD_COLS);
if (!(scanf(" %d", &cols)))
return END_THE_GAME;
} while ((cols < 3) || (cols > 9) || (cols < N));
return cols;
}
// receives tokens number
// 6 lines
int input_T(int n, int m)
{
int toks;
do
{
print_read_game_params_message(MSG_GET_NUMBER_TOKENS);
if (!(scanf(" %d", &toks)))
return END_THE_GAME;
} while ((toks < MIN_TOKENS) || (toks > min(n, m)));
return toks;
}
// matches the unchoosen symbol color to the secound player
// 3 lines
void match_symbol_to_player(char players_symbols[2])
{
if (players_symbols[0] == RED_SLOT_SYMBOL)
players_symbols[1] = YELLOW_SLOT_SYMBOL;
else
players_symbols[1] = RED_SLOT_SYMBOL;
}
// receives params, stores their values, returns 0 in case the input is unlegal
// 11 lines
int receive_params(char players_symbols[2], int board_side[2], int* tptr,char board[][BOARD_MAX_SIDE])
{
print_welcome_message();
players_symbols[0] = input_symbol();
if (players_symbols[0] == '0')
return END_THE_GAME;
else
match_symbol_to_player(players_symbols);
if (input_rows_and_cols(board_side))
return END_THE_GAME;
*tptr = input_T(board_side[0], board_side[1]);
if (*tptr == END_THE_GAME)
return END_THE_GAME;
print_board(board, board_side);
return LEGAL_INPUTS;
}
// 7 lines
bool input_rows_and_cols(int board_side[2])
{
board_side[0] = input_N();
if (board_side[0] == END_THE_GAME)
return true;
board_side[1] = input_M(board_side[0]);
if (board_side[1] == END_THE_GAME)
return true;
else return false;
}
// returns true if there are moves to undo, otherwise returns false
// 4 lines
bool is_there_moves_to_undo(int history[SQUARE_BOARD_MAX_SIDE + 1])
{
if (history[1] == 0)
{
print_unavailable_undo_redo_message();
return false;
}
return true;
}
// returns true if there are moves to redo, otherwise returns false
// 4 lines
bool is_there_moves_to_redo(int undo_history[SQUARE_BOARD_MAX_SIDE-1])
{
if (undo_history[0] == 0)
{
print_unavailable_undo_redo_message();
return false;
}
return true;
}
// returns false if the choosen column is full, otherwise returns true
bool is_column_not_full(char board[][BOARD_MAX_SIDE], int choosen_col)
{
if (board[0][choosen_col - 1] == EMPTY_SLOT_SYMBOL)
return true;
print_full_column_message();
return false;
}
// performs undo on the last added symbol and updates informations in arrays
// 12 lines
int deal_with_undo(int history[SQUARE_BOARD_MAX_SIDE + 1], int undo_history[SQUARE_BOARD_MAX_SIDE - 1], char board[][BOARD_MAX_SIDE],
int board_side[2])
{
int col_to_update = history[history[0]] - 1; // the statment history[history[0]] gives the value of the last choosen column on real board
for (int row = 0; row < board_side[0]; row++)
if (board[row][col_to_update] != EMPTY_SLOT_SYMBOL)
{
board[row][col_to_update] = EMPTY_SLOT_SYMBOL;
break;
}
for (int i = 0; i < SQUARE_BOARD_MAX_SIDE - 1; i++)
{
if (undo_history[i] == 0)
{
undo_history[i] = history[history[0]];
break;
}
}
history[history[0]] = 0;
history[0]--;
return LEGAL_INPUTS;
}
// performs redo and updates informations in arrays
// 13 lines
int deal_with_redo(int history[SQUARE_BOARD_MAX_SIDE + 1], int undo_history[SQUARE_BOARD_MAX_SIDE - 1], int board_side[2],
char board[][BOARD_MAX_SIDE], char symbol)
{
int column = 0;
for (int i = SQUARE_BOARD_MAX_SIDE - 2; i >= 0; i--)
{
if (undo_history[i] != 0)
{
column = undo_history[i];
undo_history[i] = 0;
break;
}
}
for (int row = board_side[0] - 1 ; row >= 0; row--)
{
if (board[row][column-1] == EMPTY_SLOT_SYMBOL)
{
board[row][column-1] = symbol;
break;
}
}
history[0]++;
history[history[0]] = column;
return LEGAL_INPUTS;
}
// adds the symbol to a matching line and updates informations in arrays
// 11 lines
int deal_with_num(int history[SQUARE_BOARD_MAX_SIDE + 1], int undo_history[SQUARE_BOARD_MAX_SIDE - 1], int board_side[2],
char board[][BOARD_MAX_SIDE], char symbol, int new_element[2], int choosen_col)
{
for (int i = (board_side[0] - 1); i >= 0; i--)
{
if (board[i][choosen_col - 1] == EMPTY_SLOT_SYMBOL)
{
board[i][choosen_col - 1] = symbol;
new_element[0] = i+1;
new_element[1] = choosen_col;
break;
}
}
for (int j = 0; j < SQUARE_BOARD_MAX_SIDE - 1; j++)
undo_history[j] = 0;
history[0]++;
history[history[0]] = choosen_col;
return Filled_NEW_SYMBOL;
}
/*
*
returns 0 if the input is not legal
return -1 if the input is legal but is not in the wanted domain (not relevant)
otherwise, when the input is legal and relevant
the function returns the returned value of "inputed_col_is_legal"
*
*/
// 7 lines
int input_until_legal_col(int history[SQUARE_BOARD_MAX_SIDE + 1], int undo_history[SQUARE_BOARD_MAX_SIDE - 1],
char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2], int player_num, char players_symbols[2])
{
print_enter_column_message();
int choosen_col = 0;
if (!(scanf(" %d", &choosen_col)))
return END_THE_GAME;
else if (choosen_col<-2 || choosen_col>board_side[1] || choosen_col == 0)
return LEGAL_BUT_UNRELEVANT;
else
return inputed_col_is_legal(choosen_col, history, undo_history, board, board_side, players_symbols, player_num, new_element);
}
/*
* inputs a legal and relevant (in the wanted domain) column number
* returns 1 if the choosen colmun still relevant
* otherwise if the column is full/no moves to redo/undo the functions returns -1
*/
// 9 lines
int inputed_col_is_legal(int choosen_col, int history[SQUARE_BOARD_MAX_SIDE +1], int undo_history[SQUARE_BOARD_MAX_SIDE-1],
char board[][BOARD_MAX_SIDE],int board_side[2], char players_symbols[2], int player_num, int new_element[2])
{
if (choosen_col == -1)
{
if (is_there_moves_to_undo(history))
{
return (deal_with_undo(history, undo_history, board, board_side));
}
}
else if (choosen_col == -2)
{
if (is_there_moves_to_redo(undo_history))
{
return (deal_with_redo(history, undo_history, board_side, board, players_symbols[player_num - 1]));
}
}
else
{
if (is_column_not_full(board, choosen_col))
{
return (deal_with_num(history, undo_history, board_side, board, players_symbols[player_num - 1], new_element, choosen_col));
}
}
return LEGAL_BUT_UNRELEVANT;
}
/*inputs the location of the last entered symbol
new_elemnt {row,col}
*returns the number of the same symbols existed in a row on right side of new element
*/
// 11 lines
int count_right_elements(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2])
{
int count = 0, current_col=new_element[1]-1;
bool done = false;
char current_element = board[new_element[0] - 1][new_element[1] - 1];
while (!done)
{
if (current_col + 1 == board_side[1])
break;
current_col++;
if (board[new_element[0] - 1][current_col] == current_element)
count++;
else
break;
}
return count;
}
// returns the number of the same symbols existed in a row on left side of new element
// 10 lines
int count_left_elements(char board[][BOARD_MAX_SIDE], int new_element[2])
{
int count = 0, current_col = new_element[1] - 1,row = new_element[0] - 1;
char current_element = board[row][current_col];
while (1)
{
if (current_col == 0)
break;
current_col--;
if (board[row][current_col] == current_element)
count++;
else
break;
}
return count;
}
//returns true if there was in a line T symbols in a row from the same color
// 3 lines
bool symbols_in_a_row(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2], int tokens)
{
int right = count_right_elements(board, board_side, new_element);
int left = count_left_elements(board, new_element);
return ((right + left + 1) >= tokens);
}
//returns the number of the same symbols existed in a row above the new element
// 10 lines
int count_upper_elements(char board[][BOARD_MAX_SIDE], int new_element[2])
{
int count = 0, current_row = new_element[0] - 1, col= new_element[1] - 1;
char current_symbol = board[current_row][col];
while (1)
{
if (current_row == 0)
break;
current_row--;
if (board[current_row][col] == current_symbol)
count++;
else
break;
}
return count;
}
// returns the number of the same symbols existed in a row down the new element
//10 lines
int count_lower_elements(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2])
{
int count = 0, current_row = new_element[0] - 1;
char current_symbol = board[current_row][new_element[1] - 1];
while (1)
{
if (current_row + 1 == board_side[1])
break;
current_row++;
if (board[current_row][new_element[1] - 1] == current_symbol)
count++;
else
break;
}
return count;
}
// returns true if there was in a column T symbols in a row from the same color
// 3 lines
bool symbols_in_a_column(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2], int tokens)
{
int up = count_upper_elements(board , new_element);
int down = count_lower_elements(board, board_side, new_element);
return ((up + down + 1) == tokens);
}
// returns the number of the same symbols existed in a row on the right upper side of new_element
// 11 lines
int count_upper_right_corner(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2])
{
int row = new_element[0] - 1, column = new_element[1] - 1, count = 0;
char current_element = board[row][column];
while (1)
{
if (row == 0 || column == (board_side[1]-1))
break;
row--;
column++;
if (board[row][column] == current_element)
count++;
else
break;
}
return count;
}
// returns the number of the same symbols existed in a row on the lower left side of new_element
// 11 lines
int count_lower_left_corner(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2])
{
int count = 0, row = new_element[0] - 1, column = new_element[1] - 1;
char current_element = board[row][column];
while (1)
{
if (row == board_side[0] - 1 || column == 0)
break;
row++;
column--;
if (board[row][column] == current_element)
count++;
else
break;
}
return count;
}
// returns true if there was T symbols from the same color existed in a row on the side slant (lower left to upper right)
// 4 lines
bool symbols_in_a_side_slant(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2], int tokens)
{
int upper_right = count_upper_right_corner(board, board_side, new_element);
int lower_left = count_lower_left_corner(board, board_side, new_element);
int sum = upper_right + lower_left + 1;
return (sum >= tokens);
}
// returns the number of the same symbols existed in a row on the upper left side of new_element
// 11 lines
int count_upper_left_corner(char board[][BOARD_MAX_SIDE], int new_element[2])
{
int row = new_element[0] - 1, column = new_element[1] - 1, count = 0;
char current_element = board[row][column];
while (1)
{
if (row == 0 || column == 0)
break;
row--;
column--;
if (board[row][column] == current_element)
count++;
else
break;
}
return count;
}
// returns the number of the same symbols existed in a row on the lower right side of new_element
// 11 lines
int count_lower_right_corner(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2])
{
int row = new_element[0] - 1, column = new_element[1] - 1, count = 0;
char current_element = board[row][column];
while (1)
{
if(row==(board_side[0]-1)||column==(board_side[1]-1))
break;
row++;
column++;
if (board[row][column] == current_element)
count++;
else
break;
}
return count;
}
// returns true if there was T symbols from the same color existed in a row on the main slant (upper left to lower right)
// 4 lines
bool symbols_in_a_main_slant(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2], int tokens)
{
int upper_left = count_upper_left_corner(board, new_element);
int lower_right = count_lower_right_corner(board, board_side, new_element);
int sum = upper_left + lower_right + 1;
return (sum >= tokens);
}
// returns 0 if there was a winner
// 8 lines
int check_winner(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2], int tokens, int player_num)
{
bool line = symbols_in_a_row(board, board_side, new_element, tokens);
bool column = symbols_in_a_column(board, board_side, new_element, tokens);
bool side_slant = symbols_in_a_side_slant(board, board_side, new_element, tokens);
bool main_slant = symbols_in_a_main_slant(board, board_side, new_element, tokens);
if (line || column || side_slant || main_slant)
{
print_winner(player_num);
return END_THE_GAME;
}
return 1;
}
// returns 0 if there was s tie
// 8 lines
int check_tie(char board[][BOARD_MAX_SIDE], int board_side[2])
{
int full_columns = 0, columns_num = board_side[1];
for (int i = 0; i < columns_num; i++)
if (board[0][i] != EMPTY_SLOT_SYMBOL)
full_columns++;
if (full_columns == columns_num)
{
print_winner(-1);
return END_THE_GAME;
}
return 1;
}
//returns 0 if there was a tie or winner
// 5 lines
int win_or_tie(char board[][BOARD_MAX_SIDE], int board_side[2], int new_element[2], int tokens, int player_num)
{
int win = check_winner(board, board_side, new_element, tokens, player_num);
int tie = check_tie(board, board_side);
if ((win == END_THE_GAME) || (tie == END_THE_GAME))
return END_THE_GAME;
return LEGAL_INPUTS;
}
/*
inputs flag
flag value equals to 2 or 1
*/
// 4 lines
int check_flag(char board[][BOARD_MAX_SIDE], int board_side[2], int flag, int new_element[2], int tokens, int player_num)
{
print_board(board, board_side);
if (flag == Filled_NEW_SYMBOL)
flag = win_or_tie(board, board_side, new_element, tokens, player_num);
return flag;
}
Editor is loading...