diff --git a/connect4.c b/connect4.c index 86e89a7..1e52873 100644 --- a/connect4.c +++ b/connect4.c @@ -17,6 +17,7 @@ * along with this program. If not, see . */ #include +#include #include #include #include "macros.h" @@ -25,7 +26,7 @@ #include "types.h" #include "ui.h" -#define VERSION 0.0.5 +#define VERSION 0.1.0 #define VERSIONSTRING \ "AnnaConnect version "XSTR(VERSION)", Copyright (C) Anna Snoeijs\n" @@ -36,19 +37,37 @@ extern char _binary_LICENSE_start[]; extern char _binary_LICENSE_end[]; int main( int argc, char *argv[] ){ + // Initialise variables + wins_t wins = { + .count0 = { + .total = 0, + .vertical = 0, + .horizontal = 0, + .diagonalUp = 0, + .diagonalDown = 0, + }, + }; + wins.count1 = wins.count0; + board_t playboard = { + .player = 0, + .rows = BOARD_HEIGHT, + .columns = BOARD_WIDTH + }; // Parse options for(;;){ // Allowed options static struct option long_options[] = { - { "help", no_argument, NULL, 'h' }, - { "license", no_argument, NULL, 'l' }, - { "version", no_argument, NULL, '\0' }, + { "help", no_argument, NULL, 'h' }, + { "license", no_argument, NULL, 'l' }, + { "version", no_argument, NULL, '\0' }, + { "columns", required_argument, NULL, 'c' }, + { "rows", required_argument, NULL, 'r' }, { 0 } }; // Index of current option int option_index = 0; // Get next option - char c = getopt_long( argc, argv, "hl", long_options, &option_index ); + char c = getopt_long( argc, argv, "hlc:r:", long_options, &option_index ); if( c == -1 ) break; // Handle option switch( c ){ @@ -86,6 +105,12 @@ int main( int argc, char *argv[] ){ putchar( *p ); } return 0; + case 'c': // --columns + playboard.columns = atoi(optarg); + break; + case 'r': // --rows + playboard.rows = atoi(optarg); + break; } } // Check for unhandled options @@ -95,6 +120,14 @@ int main( int argc, char *argv[] ){ printf( "%s ", argv[optind++] ); putchar( '\n' ); } + if( playboard.rows < 1 ){ + fprintf( stderr, "ERR: AMOUT OF ROWS MUST BE AT LEAST 1\n" ); + return -1; + } + if( playboard.rows >= 32 ){ + fprintf( stderr, "ERR: AMOUT OF ROWS MUST BE LESS THAN 32\n" ); + return -1; + } // Start the actual program printf( VERSIONSTRING @@ -103,30 +136,19 @@ int main( int argc, char *argv[] ){ "under certain condtions. See `%s --license`\n", argv[0] ); // board, innit? - initBoard(); - board_t playboard = { - .player = 0, - .column = {0}, - .height = {0}, - }; - wins_t wins = { - .count0 = { - .total = 0, - .vertical = 0, - .horizontal = 0, - .diagonalUp = 0, - .diagonalDown = 0, - }, - .count1 = { - .total = 0, - .vertical = 0, - .horizontal = 0, - .diagonalUp = 0, - .diagonalDown = 0, - }, - .win0 = {0}, - .win1 = {0}, - }; + playboard.height = calloc( playboard.columns, sizeof(int) ); + playboard.column = calloc( playboard.columns, sizeof(int) ); + wins.win0 = calloc( playboard.columns, sizeof(int) ); + wins.win1 = calloc( playboard.columns, sizeof(int) ); + wins.same.vertical2 = calloc( playboard.columns, sizeof(int) ); + wins.same.horizontal2 = calloc( playboard.columns, sizeof(int) ); + wins.same.diagonalUp2 = calloc( playboard.columns, sizeof(int) ); + wins.same.diagonalDown2 = calloc( playboard.columns, sizeof(int) ); + wins.same.vertical4 = calloc( playboard.columns, sizeof(int) ); + wins.same.horizontal4 = calloc( playboard.columns, sizeof(int) ); + wins.same.diagonalUp4 = calloc( playboard.columns, sizeof(int) ); + wins.same.diagonalDown4 = calloc( playboard.columns, sizeof(int) ); + initBoard( playboard ); // Begin loopin for(;; playboard.player = !playboard.player ){ move_t move = askMove(); diff --git a/logic.c b/logic.c index 969e9c2..21a251f 100644 --- a/logic.c +++ b/logic.c @@ -62,7 +62,7 @@ void calcWins( // First the simplest win, the humble tower wins->count0.vertical = 0; wins->count1.vertical = 0; - for( int i = 0; i < BOARD_WIDTH; i++ ){ + for( int i = 0; i < board.columns; i++ ){ // Check for lil towers wins->same.vertical2 [ i ] = ~( board.column [ i ] @@ -89,7 +89,7 @@ void calcWins( wins->count0.diagonalDown = 0; wins->count1.diagonalDown = 0; // First connect 2 - for( int i = 0; i < BOARD_WIDTH - 1; i++ ){ + for( int i = 0; i < board.columns - 1; i++ ){ wins->same.horizontal2 [ i ] = ~( board.column [ i ] ^ board.column [ i + 1 ] ) @@ -114,7 +114,7 @@ void calcWins( & ~1; // A diagonal line down ain't starts at the floor innit? } // Then stitch the twos together and count - for( int i = 0; i < BOARD_WIDTH - 3; i++ ){ + for( int i = 0; i < board.columns - 3; i++ ){ wins->same.horizontal4 [ i ] = wins->same.horizontal2 [ i ] & wins->same.horizontal2 [ i + 1 ] diff --git a/types.h b/types.h index 5ddc194..54d2d7b 100644 --- a/types.h +++ b/types.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #pragma once +#include #include "config.h" typedef enum { @@ -10,19 +11,21 @@ typedef enum { typedef struct { int player; - int height [ BOARD_WIDTH ]; - int column [ BOARD_WIDTH ]; + int *height; + int *column; + uint8_t rows; + uint8_t columns; } board_t; typedef struct { - int vertical2 [ BOARD_WIDTH ]; - int horizontal2 [ BOARD_WIDTH - 1 ]; - int diagonalUp2 [ BOARD_WIDTH - 1 ]; - int diagonalDown2 [ BOARD_WIDTH - 1 ]; - int vertical4 [ BOARD_WIDTH ]; - int horizontal4 [ BOARD_WIDTH - 3 ]; - int diagonalUp4 [ BOARD_WIDTH - 3 ]; - int diagonalDown4 [ BOARD_WIDTH - 3 ]; + int *vertical2; + int *horizontal2; + int *diagonalUp2; + int *diagonalDown2; + int *vertical4; + int *horizontal4; + int *diagonalUp4; + int *diagonalDown4; } directions_t; typedef struct { @@ -36,7 +39,7 @@ typedef struct { typedef struct { wincount_t count0; wincount_t count1; - int win0 [ BOARD_WIDTH ]; - int win1 [ BOARD_WIDTH ]; + int *win0; + int *win1; directions_t same; } wins_t; diff --git a/ui.h b/ui.h index 0fbbacd..18a1673 100644 --- a/ui.h +++ b/ui.h @@ -4,7 +4,9 @@ #include "types.h" #include "config.h" -extern void initBoard( void ); +extern void initBoard( + const board_t board +); extern void updateBoard( const wins_t wins, diff --git a/ui_ncurses.c b/ui_ncurses.c index 1d6459c..31d535f 100644 --- a/ui_ncurses.c +++ b/ui_ncurses.c @@ -65,13 +65,13 @@ #define SCOREBOARD_HEIGHT 10 #endif -void initBoard( void ){ +void initBoard( const board_t board ){ setlocale(LC_ALL, ""); initscr(); keypad(stdscr, TRUE); nonl(); echo(); - for( int column = 0; column < BOARD_WIDTH; column++ ){ + for( int column = 0; column < board.columns; column++ ){ char colnum[4]; sprintf( colnum, "%2d", column + FIRST_NUMBER ); mvaddstr( @@ -79,7 +79,7 @@ void initBoard( void ){ BOARD_X + BOARD_DX * ( column + 1 ), colnum ); - for(int row = 0; row < BOARD_HEIGHT; row++){ + for(int row = 0; row < board.rows; row++){ mvaddstr( BOARD_Y + BOARD_DY * ( row + 1 ), BOARD_X + BOARD_DX * ( column + 1 ), @@ -87,14 +87,14 @@ void initBoard( void ){ ); } mvaddstr( - BOARD_Y + BOARD_DY * ( BOARD_HEIGHT + 1 ), + BOARD_Y + BOARD_DY * ( board.rows + 1 ), BOARD_X + BOARD_DX * ( column + 1 ), colnum ); } - for(int row = 0; row < BOARD_HEIGHT; row++ ){ + for(int row = 0; row < board.rows; row++ ){ char rownum[4]; - sprintf( rownum, "%2d", row + FIRST_NUMBER ); + sprintf( rownum, "%2d", board.rows - row + FIRST_NUMBER - 1 ); mvaddstr( BOARD_Y + BOARD_DY * ( row + 1 ), BOARD_X, @@ -102,7 +102,7 @@ void initBoard( void ){ ); mvaddstr( BOARD_Y + BOARD_DY * ( row + 1 ), - BOARD_X + BOARD_DX * ( BOARD_WIDTH + 1 ), + BOARD_X + BOARD_DX * ( board.columns + 1 ), rownum ); } @@ -139,7 +139,7 @@ void updateBoard( switch( move ){ case PUT: mvaddstr( - BOARD_Y + BOARD_DY * ( BOARD_HEIGHT - height + 1 ), + BOARD_Y + BOARD_DY * ( board.rows - height + 1 ), BOARD_X + 1 + BOARD_DX * ( column + 1 ), board.column[ column ] & 1 << ( height - 1 ) ? "1" : "0" ); @@ -147,7 +147,7 @@ void updateBoard( default: for( int row = 0; row < height; row++ ){ mvaddstr( - BOARD_Y + BOARD_DY * ( BOARD_HEIGHT - row ), + BOARD_Y + BOARD_DY * ( board.rows - row ), BOARD_X + 1 + BOARD_DX * ( column + 1 ), board.column[ column ] & 1 << row ? "1" : "0" ); @@ -227,16 +227,16 @@ int askColumn( if( board.player ) addstr( "p1" ); else addstr( "p0" ); refresh(); - for(; board.height[ column ] >= BOARD_HEIGHT; ) - column += ( column < BOARD_WIDTH - 1 ); + for(; board.height[ column ] >= board.rows; ) + column += ( column < board.columns - 1 ); for(;;){ int ch = mvgetch( - BOARD_Y + BOARD_DY * ( BOARD_HEIGHT - board.height[ column ] ), + BOARD_Y + BOARD_DY * ( board.rows - board.height[ column ] ), BOARD_X + 1 + BOARD_DX * ( column + 1 ) ); switch( ch ){ case KEY_RIGHT: - column += ( column < BOARD_WIDTH - 1 ); + column += ( column < board.columns - 1 ); break; case KEY_LEFT: column -= ( column > 0 ); @@ -246,9 +246,9 @@ int askColumn( } switch( move ){ case PUT: - for(; board.height[ column ] >= BOARD_HEIGHT; ) switch( ch ){ + for(; board.height[ column ] >= board.rows; ) switch( ch ){ case KEY_RIGHT: - if( column >= BOARD_WIDTH ) ch = KEY_LEFT; + if( column >= board.columns ) ch = KEY_LEFT; else column++; break; case KEY_LEFT: @@ -260,7 +260,7 @@ int askColumn( case POP: for(; board.height[ column ] <= 0; ) switch( ch ){ case KEY_RIGHT: - if( column >= BOARD_WIDTH ) ch = KEY_LEFT; + if( column >= board.columns ) ch = KEY_LEFT; else column++; break; case KEY_LEFT: @@ -296,10 +296,10 @@ int askColumn( INPUT_X ); clrtoeol(); - if( column >= 0 && column < BOARD_WIDTH ) + if( column >= 0 && column < board.columns ) switch( move ){ case PUT: - if( board.height [ column ] < BOARD_HEIGHT ) + if( board.height [ column ] < board.columns ) return column; else addstr( "Pls enter a column that ain't full" ); break; diff --git a/ui_vt100.c b/ui_vt100.c index d817730..2a54a15 100644 --- a/ui_vt100.c +++ b/ui_vt100.c @@ -21,22 +21,22 @@ #include #include "macros.h" -#define BOARD_WIDTH_CHARS ( 3 * BOARD_WIDTH + 6 ) +#define BOARD_WIDTH_CHARS ( 3 * board.columns + 6 ) #define SCOREBOARD_OFFSET 5 #define SCOREBOARD_WIDTH 27 #define SCOREBOARD_HEIGHT 9 -void initBoard( void ){ - for( int i = SCOREBOARD_HEIGHT - ( BOARD_HEIGHT + 2 ); i > 0; i-- ) +void initBoard( const board_t board ){ + for( int i = SCOREBOARD_HEIGHT - ( board.rows + 2 ); i > 0; i-- ) putchar( '\n' ); printf( "\n " ); - for( int column = 0; column < BOARD_WIDTH; column++ ) + for( int column = 0; column < board.columns; column++ ) printf( "%2d ", column + FIRST_NUMBER ); putchar( '\n' ); - for( int row = BOARD_HEIGHT - 1; row > -1; row-- ){ + for( int row = board.rows - 1; row > -1; row-- ){ // begin row printf( "%2d " , row + FIRST_NUMBER ); - for( int column = 0; column < BOARD_WIDTH; column++ ) + for( int column = 0; column < board.columns; column++ ) printf( "[ ]" ); // end of row printf( "%2d" , row + FIRST_NUMBER ); @@ -46,7 +46,7 @@ void initBoard( void ){ } // end of board printf( " " ); - for( int column = 0; column < BOARD_WIDTH; column++ ) + for( int column = 0; column < board.columns; column++ ) printf( "%2d ", column + FIRST_NUMBER ); #define SCOREBOARD_LINE_END "\033[B\033["XSTR(SCOREBOARD_WIDTH)"D" printf("\033["XSTR(SCOREBOARD_OFFSET)"C\033["XSTR(SCOREBOARD_HEIGHT)"A" @@ -85,7 +85,7 @@ void updateBoard( break; default: // Print all the pieces in the column and the air above printf( "\033[%dA", height + 4 ); - if( height < BOARD_HEIGHT ) printf( "\033[%dC ", column * 3 + 4 ); + if( height < board.rows ) printf( "\033[%dC ", column * 3 + 4 ); else printf( "\033[%dC", column * 3 + 5 ); for( int row = height; row --> 0; ) printf( @@ -101,7 +101,7 @@ void updateBoard( "%3d │%3d\033[B\033[8D" "%3d │%3d\033[2B\033[8D" "%3d │%3d\033[2B" - ,BOARD_WIDTH_CHARS + SCOREBOARD_WIDTH - 8 + ,( 3 * board.columns + 6 ) + SCOREBOARD_WIDTH - 8 ,wins.count0.vertical, wins.count1.vertical ,wins.count0.horizontal, wins.count1.horizontal ,wins.count0.diagonalUp, wins.count1.diagonalUp @@ -138,10 +138,10 @@ int askColumn( } } column -= FIRST_NUMBER; - if( column >= 0 && column < BOARD_WIDTH ) + if( column >= 0 && column < board.columns ) switch( move ){ case PUT: - if( board.height [ column ] < BOARD_HEIGHT ) + if( board.height [ column ] < board.rows ) return column; else printf( "\033[2Apls enter a column that ain't full" ); break;