diff --git a/connect4.c b/connect4.c index 056ee25..9ed5cf1 100644 --- a/connect4.c +++ b/connect4.c @@ -21,13 +21,14 @@ #include #include #include +#include #include "macros.h" #include "config.h" #include "logic.h" #include "types.h" #include "ui.h" -#define VERSION 0.1.2 +#define VERSION 0.2.0 #ifndef GITHASH #define FULLVERSION VERSION @@ -50,6 +51,8 @@ int main( int argc, char *argv[] ){ .rows = BOARD_HEIGHT, .columns = BOARD_WIDTH }; + FILE *outputfile = NULL; + char *filename = NULL; // Parse options for(;;){ // Allowed options @@ -59,12 +62,15 @@ int main( int argc, char *argv[] ){ { "version", no_argument, NULL, '\0' }, { "columns", required_argument, NULL, 'c' }, { "rows", required_argument, NULL, 'r' }, + { "output", required_argument, NULL, 'o' }, { 0 } }; // Index of current option int option_index = 0; // Get next option - char c = getopt_long( argc, argv, "hlc:r:", long_options, &option_index ); + char c = getopt_long( argc, argv, "hlc:r:o:", + long_options, &option_index + ); if( c == -1 ) break; // Handle option switch( c ){ @@ -86,12 +92,14 @@ int main( int argc, char *argv[] ){ case 'h': // --help printf( "Usage: %s [OPTIONS]\n\n", argv[0] ); printf( -" -h --help Print this help text\n" -" -l --license Print the LICENSE file\n" -" --version Print the version string\n" +" -h --help Print this help text\n" +" -l --license Print the LICENSE file\n" +" --version Print the version string\n" "\n" " -c n --columns n Set the amount of columns\n" " -r n --rows n Set the amount of rows\n" +"\n" +" -o file --output file Ouput moves taken in game to file\n" ); return 0; case 'l': // --license @@ -109,6 +117,10 @@ int main( int argc, char *argv[] ){ case 'r': // --rows playboard.rows = atoi(optarg); break; + case 'o': + filename = strdup(optarg); + outputfile = fopen( filename, "w" ); + break; } } // Check for unhandled options @@ -163,10 +175,32 @@ int main( int argc, char *argv[] ){ wins.same.diagonalDown4 = calloc( playboard.columns, sizeof(column_t) ); initBoard( playboard ); // Begin loopin + if( outputfile != NULL ){ + fprintf( + outputfile, + "# File generated by " VERSIONSTRING + "# First define the config\n" + "--rows %d\n" + "--columns %d\n" + "# Now follows the moves taken, zero indexed\n" + , + playboard.rows, + playboard.columns + ); + } for(;; playboard.player = !playboard.player ){ columnsint_t column = askColumn( playboard ); + if( column == QUITCOLUMN ) break; playMove( &playboard, column ); calcWins( &wins, playboard, column ); updateBoard( wins, playboard, column ); + if( outputfile != NULL ){ + fprintf( outputfile, "%d\n", column ); + } } + if( outputfile != NULL ){ + fclose( outputfile ); + printf( "Output is written to %s\n", filename ); + } + exit_ui(); } diff --git a/types.h b/types.h index 7ec4fa5..f5b3688 100644 --- a/types.h +++ b/types.h @@ -2,22 +2,27 @@ #pragma once #include +#include #include "config.h" +// Only use big ints on architectures where it doesn't impact speed #if INT_FAST16_MAX == INT_FAST64_MAX typedef int rowsint_t; -typedef int columnsint_t; +typedef unsigned columnsint_t; +#define QUITCOLUMN UINT_MAX typedef unsigned winint_t; typedef uintmax_t column_t; #else typedef int_fast8_t rowsint_t; -typedef int_fast8_t columnsint_t; +typedef uint_fast8_t columnsint_t; +#define QUITCOLUMN UINT_FAST8_MAX typedef uint_fast8_t winint_t; typedef uint_fast8_t column_t; #endif #define WININT_FORMAT "%3d" + typedef struct { bool player; rowsint_t *height; diff --git a/ui.h b/ui.h index 6ab5588..fbff018 100644 --- a/ui.h +++ b/ui.h @@ -14,6 +14,8 @@ extern void updateBoard( const columnsint_t column ); -extern int askColumn( +extern columnsint_t askColumn( const board_t board ); + +extern void exit_ui(void); diff --git a/ui_ncurses.c b/ui_ncurses.c index b86f255..00bf47c 100644 --- a/ui_ncurses.c +++ b/ui_ncurses.c @@ -207,7 +207,7 @@ void updateBoard( ); } -int askColumn( +columnsint_t askColumn( const board_t board ){ columnsint_t column = 0; @@ -228,7 +228,8 @@ int askColumn( column += ( column < board.columns - 1 ); break; case KEY_LEFT: - column -= ( column > 0 ); + if( column == 0 ) return QUITCOLUMN; + column --; break; case KEY_DOWN: return column; @@ -239,7 +240,7 @@ int askColumn( else column++; break; case KEY_LEFT: - if( column == 0 ) ch = KEY_RIGHT; + if( column == 0 ) return QUITCOLUMN; else column--; break; } @@ -272,6 +273,10 @@ int askColumn( #endif /* ! ARROWS */ } +void exit_ui(void){ + endwin(); +} + #undef INPUT_X #undef INPUT_Y #undef SCOREBOARD_X diff --git a/ui_vt100.c b/ui_vt100.c index c38131d..cbf68b4 100644 --- a/ui_vt100.c +++ b/ui_vt100.c @@ -94,7 +94,7 @@ void updateBoard( printf( "\033[2K\n" ); } -int askColumn( +columnsint_t askColumn( const board_t board ){ columnsint_t column; @@ -102,21 +102,16 @@ int askColumn( printf( "Wher player %d put? ", board.player ); printf( "\033[K" ); // clear everything after cursor fflush( stdout ); - column = -1; + column = 0; for( char ch = '0'; ch != '\n'; read( STDIN_FILENO, &ch, 1 ) ){ if( ch >= '0' && ch <= '9' ){ - if( column == -1 ) - column = 0; - else - column *= 10; - if( column >= 0 ) - column += (columnsint_t)( ch - '0' ); - } else { - column = -2; - } + column *= 10; + column += (columnsint_t)( ch - '0' ); + } else return QUITCOLUMN; } + if( column < FIRST_NUMBER ) return QUITCOLUMN; column -= FIRST_NUMBER; - if( column >= 0 && column < board.columns ) + if( column < board.columns ) if( board.height [ column ] < board.rows ) return column; else printf( "\033[2Apls enter a column that ain't full" ); @@ -126,6 +121,10 @@ int askColumn( } } +void exit_ui(void){ + printf( "\n" ); +} + #undef BOARD_WIDTH_CHARS #undef SCOREBOARD_OFFSET #undef SCOREBOARD_WIDTH