4 in a row
unknown
plain_text
17 days ago
25 kB
1
Indexable
Never
#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; }