From fd728bae0e5bdf4dc051d2c7ee31303ba530bc8b Mon Sep 17 00:00:00 2001 From: Kharec Date: Fri, 14 Nov 2025 22:33:04 +0100 Subject: [PATCH] feat: add drop4.c --- drop4.c | 258 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 drop4.c diff --git a/drop4.c b/drop4.c new file mode 100644 index 0000000..341aa3a --- /dev/null +++ b/drop4.c @@ -0,0 +1,258 @@ +#include +#include +#include +#include +#include +#include + +#define ROWS 6 +#define COLS 7 +#define EMPTY 0 +#define P1 1 +#define P2 2 +#define WIN_LENGTH 4 + +#define DIR_HORIZONTAL 0 +#define DIR_VERTICAL 1 +#define DIR_DIAG_DOWN 2 +#define DIR_DIAG_UP 3 +#define NUM_DIRECTIONS 4 + +typedef struct { + int board[ROWS][COLS]; + int current_player; + int last_row; + int last_col; +} Game; + +void init_game(Game *game) { + for (int i = 0; i < ROWS; i++) { + for (int j = 0; j < COLS; j++) { + game->board[i][j] = EMPTY; + } + } + game->current_player = P1; + game->last_row = -1; + game->last_col = -1; +} + +void print_board(Game *game) { + printf("\n"); + for (int j = 0; j < COLS; j++) { + printf(" %d ", j); + } + printf("\n"); + for (int i = 0; i < ROWS; i++) { + for (int j = 0; j < COLS; j++) { + char symbol = game->board[i][j] == EMPTY ? '.' + : game->board[i][j] == P1 ? 'X' + : 'O'; + printf(" %c ", symbol); + } + printf("\n"); + } + printf("\n"); +} + +void switch_player(Game *game) { + game->current_player = game->current_player == P1 ? P2 : P1; +} + +int drop_piece(Game *game, int col) { + for (int i = ROWS - 1; i >= 0; i--) { + if (game->board[i][col] == EMPTY) { + game->board[i][col] = game->current_player; + game->last_row = i; + game->last_col = col; + return 1; + } + } + return 0; +} + +int is_valid_move(Game *game, int col) { + return col >= 0 && col < COLS && game->board[0][col] == EMPTY; +} + +int is_winning_move(Game *game) { + if (game->last_row < 0 || game->last_col < 0) { + return 0; + } + + int row = game->last_row; + int col = game->last_col; + int player = game->board[row][col]; + const int directions[NUM_DIRECTIONS][2] = {{0, 1}, {1, 0}, {1, 1}, {1, -1}}; + + for (int dir = 0; dir < NUM_DIRECTIONS; dir++) { + int count = 1; + for (int offset = 1; offset < WIN_LENGTH; offset++) { + int new_row = row + directions[dir][0] * offset; + int new_col = col + directions[dir][1] * offset; + if (new_row < 0 || new_row >= ROWS || new_col < 0 || new_col >= COLS) + break; + if (game->board[new_row][new_col] != player) + break; + count++; + } + for (int offset = 1; offset < WIN_LENGTH; offset++) { + int new_row = row - directions[dir][0] * offset; + int new_col = col - directions[dir][1] * offset; + if (new_row < 0 || new_row >= ROWS || new_col < 0 || new_col >= COLS) + break; + if (game->board[new_row][new_col] != player) + break; + count++; + if (count >= WIN_LENGTH) + return 1; + } + if (count >= WIN_LENGTH) + return 1; + } + return 0; +} + +int is_board_full(Game *game) { + for (int j = 0; j < COLS; j++) { + if (game->board[0][j] == EMPTY) + return 0; + } + return 1; +} + +static void trim_whitespace(char *str) { + size_t len = strlen(str); + while (len > 0 && isspace((unsigned char)str[len - 1])) { + str[len - 1] = '\0'; + len--; + } + size_t start = 0; + while (str[start] != '\0' && isspace((unsigned char)str[start])) { + start++; + } + if (start > 0) { + len = strlen(str + start); + memmove(str, str + start, len + 1); + } +} + +static int is_quit_command(const char *str) { + char temp[64]; + strncpy(temp, str, sizeof(temp) - 1); + temp[sizeof(temp) - 1] = '\0'; + trim_whitespace(temp); + size_t len = strlen(temp); + if (len == 0) + return 0; + + if (len == 1 && (temp[0] == 'q' || temp[0] == 'Q')) + return 1; + if (len == 4) { + if ((temp[0] == 'q' || temp[0] == 'Q') && + (temp[1] == 'u' || temp[1] == 'U') && + (temp[2] == 'i' || temp[2] == 'I') && + (temp[3] == 't' || temp[3] == 'T')) { + return 1; + } + } + return 0; +} + +int get_column_input(Game *game) { + int col; + char buffer[64]; + while (1) { + printf("Player %d, enter a column (0-%d) or 'q' to quit: ", + game->current_player, COLS - 1); + if (fgets(buffer, sizeof(buffer), stdin) == NULL) { + return -1; + } + + size_t len = strlen(buffer); + if (len > 0 && buffer[len - 1] != '\n') { + int c; + while ((c = getchar()) != '\n' && c != EOF) + ; + printf("Error: Input too long. Please enter a number between 0 and %d.\n", + COLS - 1); + continue; + } + + if (is_quit_command(buffer)) { + return -1; + } + + char *endptr; + errno = 0; + long col_long = strtol(buffer, &endptr, 10); + + if (errno == ERANGE || col_long < INT_MIN || col_long > INT_MAX) { + printf( + "Error: Number too large. Please enter a number between 0 and %d.\n", + COLS - 1); + continue; + } + + if (endptr == buffer) { + printf("Error: Invalid input. Please enter a number between 0 and %d, or " + "'q' to quit.\n", + COLS - 1); + continue; + } + + while (*endptr != '\0' && isspace((unsigned char)*endptr)) { + endptr++; + } + + if (*endptr != '\0') { + printf("Error: Invalid characters after number. Please enter only a " + "number between 0 and %d.\n", + COLS - 1); + continue; + } + + col = (int)col_long; + + if (col < 0 || col >= COLS) { + printf("Error: Column %d is out of range. Please enter a number between " + "0 and %d.\n", + col, COLS - 1); + continue; + } + + if (!is_valid_move(game, col)) { + printf("Error: Column %d is full. Please choose another column.\n", col); + continue; + } + + return col; + } +} + +int main() { + Game game; + init_game(&game); + print_board(&game); + + while (1) { + int col = get_column_input(&game); + if (col < 0) { + printf("\nGame interrupted.\n"); + break; + } + + drop_piece(&game, col); + print_board(&game); + if (is_winning_move(&game)) { + printf("Player %d wins!\n", game.current_player); + break; + } + if (is_board_full(&game)) { + printf("It's a draw! The board is full.\n"); + break; + } + switch_player(&game); + } + + return 0; +}