diff --git a/README.md b/README.md index 6abf6df..ba3fd52 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,4 @@ AnnaConnect is a silly little text-based connect 4 game c: -Supports vt100 escape codes and ncurses for drawing the UI - -Stuff still be changing so fast that the code is the documentation, -but at least it's got good enough comments methinks +Supports vt100 escape codes and ncurses for drawing the UI \ No newline at end of file diff --git a/config.h b/config.h index a134cab..f1e8451 100644 --- a/config.h +++ b/config.h @@ -5,3 +5,5 @@ #define BOARD_HEIGHT 6 #define FIRST_NUMBER 1 + +#define ARROWS diff --git a/logic.c b/logic.c index aa36dff..43e192e 100644 --- a/logic.c +++ b/logic.c @@ -17,33 +17,40 @@ * along with this program. If not, see . */ #include "logic.h" -#include "macros.h" -static column_t heightMask( const rowsint_t a ){ +static inline int top( const int a, const int b ){ + return a < b ? b : a; +} + +static inline int bottom( const int a, const int b ){ + return a < b ? a : b; +} + +static inline int heightMask( const int a ){ return ( 1 << a ) - 1; } -static column_t safeHeightMask( const rowsint_t a ){ +static inline int safeHeightMask( const int a ){ return a > 0 ? heightMask( a ) : 0; } -static column_t bottomHeightMask( const rowsint_t a, const rowsint_t b ){ +static inline int bottomHeightMask( const int a, const int b ){ return safeHeightMask( bottom( a, b ) ); } -void playMove( +inline void playMove( board_t *boardptr, - const columnsint_t column + const int column ){ boardptr->column [ column ] |= boardptr->player << boardptr->height [ column ]; boardptr->height [ column ]++; } -void calcWins( +inline void calcWins( wins_t *wins, const board_t board, - const columnsint_t column + const int column ){ // First the simplest win, the humble tower // Check for lil towers @@ -72,7 +79,7 @@ void calcWins( // Now the rest of the wins // First connect 2 for( - columnsint_t i = clipped_subtract( column, 1 ); + int i = top( column - 1, 0 ); i < bottom( column + 1, board.columns - 1 ); i++ ){ @@ -101,7 +108,7 @@ void calcWins( } // Then stitch the twos together and count for( - columnsint_t i = clipped_subtract( column, 3 ); + int i = top( column - 3, 0 ); i < bottom( column + 1, board.columns - 3 ); i++ ){ diff --git a/logic.h b/logic.h index 488894c..4123f8a 100644 --- a/logic.h +++ b/logic.h @@ -6,11 +6,11 @@ extern void playMove( board_t *boardptr, - const columnsint_t column + const int column ); extern void calcWins( wins_t *wins, const board_t board, - const columnsint_t column + const int column ); diff --git a/macros.h b/macros.h index 20b6cf4..a364109 100644 --- a/macros.h +++ b/macros.h @@ -1,9 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #pragma once -#define top( a, b ) ( a < b ? b : a ) -#define bottom( a, b ) ( a < b ? a : b ) -#define clipped_subtract( a, b ) ( a < b ? 0 : a - b ) - #define XSTR(s) STR(s) #define STR(s) #s diff --git a/makefile b/makefile index 5d10e86..f08e653 100644 --- a/makefile +++ b/makefile @@ -1,46 +1,27 @@ #!/usr/bin/make -f - -# Target architecture for compilation -ARCH = native - -# Optimization level -O = 3 - -# Flags for the compiler FLAGS = -std=c23 -FLAGS += -O$(O) -FLAGS += -march=$(ARCH) -# Only override gcc default tuning if specified in make command line -ifneq (, $(TUNE)) - FLAGS += -mtune=$(TUNE) -endif +FLAGS += -O3 +FLAGS += -march=native FLAGS += -pedantic FLAGS += -Wall FLAGS += -Wextra FLAGS += -Werror -# This flag is because of the compiler otherwise giving too much warning -#FLAGS += -Wformat-truncation=0 +FLAGS += -Wformat-truncation=0 -# Compile flag for defining GITHASH to put at the end of the version string GITFLAG = -D'GITHASH=$(shell git rev-parse --short=1 HEAD)' -# Directories where .o files and excecutables will be placed OBJDIR = obj OUTDIR = out -# The UI to compile for by default using make run #UI_TARGET = vt100 UI_TARGET = ncurses -# The URL of the plaintext version of the lisence, for the --license option LICENSEURL = https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt -# C compiler CC = cc .NOTINTERMEDIATE: -# Messages to print during different steps in making MSG_FETCHING = FETCHING: MSG_LINKING = Linking: MSG_COMPILING = Compiling C: @@ -48,57 +29,44 @@ MSG_CLEANING = Cleaning: MSG_CLEANING_OBJ = Cleaning $(OBJDIR): MSG_CLEANING_OUT = Cleaning $(OUTDIR): -# Compile for all UI targets all: $(addprefix $(OUTDIR)/connect4_,ncurses.elf vt100.elf) -# Compile and run the default UI target run: $(OUTDIR)/connect4_$(UI_TARGET).elf ./$< -# Compile and run with a specific UI target run_%: $(OUTDIR)/connect4_%.elf ./$< -# Compile specifically the ncurses version -# This one's special because it needs -lncursesw $(OUTDIR)/connect4_ncurses.elf: $(addprefix $(OBJDIR)/,ui_ncurses.o logic.o connect4.o LICENSE.o) @echo $(MSG_LINKING) $@ @mkdir -p $(@D) $(CC) $(FLAGS) -lncursesw -o $@ $^ -# Compile the final excecutable for a given UI target $(OUTDIR)/connect4_%.elf: $(addprefix $(OBJDIR)/,ui_%.o logic.o connect4.o LICENSE.o) @echo $(MSG_LINKING) $@ @mkdir -p $(@D) $(CC) $(FLAGS) -o $@ $^ -# Make an object file for the license so it does not all need to be in the code $(OBJDIR)/LICENSE.o: $(OBJDIR)/LICENSE @echo $(MSG_LINKING) $@ @mkdir -p $(@D) cd $(@D); ld -r -b binary -o $(@F) $(^F) -# Compile the object file of the main code. -# This one's special because it includes the git hash $(OBJDIR)/connect4.o: connect4.c @echo $(MSG_COMPILING) $^ @mkdir -p $(@D) $(CC) -c $(FLAGS) $(GITFLAG) -o $@ $^ -# Generic object file compile $(OBJDIR)/%.o: %.c @echo $(MSG_COMPILING) $^ @mkdir -p $(@D) $(CC) -c $(FLAGS) -o $@ $^ -# Download the license file in non-markdown form. -# This is not cleaned as that would be too silly $(OBJDIR)/LICENSE: @echo $(MSG_FETCHING) $@ curl $(LICENSEURL) \ | sed -n '/END OF TERMS AND CONDITIONS/q;p' > $(OBJDIR)/LICENSE -# Remove all compilation output and intermediate files clean: @echo $(MSG_CLEANING) @echo $(MSG_CLEANING_OBJ) diff --git a/types.h b/types.h index df3c0a4..f5b3688 100644 --- a/types.h +++ b/types.h @@ -5,7 +5,7 @@ #include #include "config.h" -// Use fastest available ints unless it's 64 bits because that uses more memory +// Only use big ints on architectures where it doesn't impact speed #if INT_FAST16_MAX == INT_FAST64_MAX typedef int rowsint_t; typedef unsigned columnsint_t; diff --git a/ui_ncurses.c b/ui_ncurses.c index 8da8914..00bf47c 100644 --- a/ui_ncurses.c +++ b/ui_ncurses.c @@ -71,7 +71,6 @@ void initBoard( const board_t board ){ keypad(stdscr, TRUE); nonl(); echo(); - __attribute__((assume(board.columns < 999))); for( columnsint_t column = 0; column < board.columns; column++ ){ char colnum[4]; snprintf( @@ -97,10 +96,8 @@ void initBoard( const board_t board ){ } for( rowsint_t row = 0; row < board.rows; row++ ){ char rownum[4]; - const int intToPrint = board.rows - row + FIRST_NUMBER - 1; - __attribute__((assume(intToPrint <= 256))); snprintf( - rownum, sizeof(rownum), "%2d", intToPrint + rownum, sizeof(rownum), "%2d", board.rows - row + FIRST_NUMBER - 1 ); mvaddstr( BOARD_Y + BOARD_DY * ( row + 1 ), @@ -214,17 +211,13 @@ columnsint_t askColumn( const board_t board ){ columnsint_t column = 0; +#ifdef ARROWS move( BOARD_Y, BOARD_X ); if( board.player ) addstr( "p1" ); else addstr( "p0" ); refresh(); - for(; board.height[ column ] >= board.rows; ){ - column++; - if( column == board.columns ){ - getch(); - return QUITCOLUMN; - } - } + for(; board.height[ column ] >= board.rows; ) + column += ( column < board.columns - 1 ); for(;;){ int ch = mvgetch( BOARD_Y + BOARD_DY * ( board.rows - board.height[ column ] ), @@ -252,6 +245,32 @@ columnsint_t askColumn( break; } } +#else /* !ARROWS */ + for(;;){ + mvaddstr( + INPUT_Y, + INPUT_X, + "Where does player " + ); + if( board.player ) addstr( "1" ); + else addstr( "0" ); + addstr( " put the piece? " ); + clrtoeol(); + refresh(); + scanw( " %d", &column ); + column -= FIRST_NUMBER; + move( + INPUT_Y + 1, + INPUT_X + ); + clrtoeol(); + if( column >= 0 && column < board.columns ) + if( board.height [ column ] < board.columns ) + return column; + else addstr( "Pls enter a column that ain't full" ); + else addstr( "Pls enter a column that exists" ); + } +#endif /* ! ARROWS */ } void exit_ui(void){ diff --git a/ui_vt100.c b/ui_vt100.c index 03b0a8d..cbf68b4 100644 --- a/ui_vt100.c +++ b/ui_vt100.c @@ -65,13 +65,14 @@ void initBoard( const board_t board ){ } void updateBoard( + const wins_t wins, const board_t board, const columnsint_t column ){ rowsint_t height = board.height [ column ]; printf( "\033[%dA\033[%dC%c\033[%dB", - height + 2, + height + 3, column * 3 + 4, '0' + !!( board.player ), height + 1 @@ -84,11 +85,11 @@ void updateBoard( "" WININT_FORMAT " │" WININT_FORMAT "\033[2B\033[8D" "" WININT_FORMAT " │" WININT_FORMAT "\033[2B" ,( 3 * board.columns + 6 ) + SCOREBOARD_WIDTH - 8 - ,board.count0.vertical, board.count1.vertical - ,board.count0.horizontal, board.count1.horizontal - ,board.count0.diagonalUp, board.count1.diagonalUp - ,board.count0.diagonalDown, board.count1.diagonalDown - ,board.count0.total, board.count1.total + ,wins.count0.vertical, wins.count1.vertical + ,wins.count0.horizontal, wins.count1.horizontal + ,wins.count0.diagonalUp, wins.count1.diagonalUp + ,wins.count0.diagonalDown, wins.count1.diagonalDown + ,wins.count0.total, wins.count1.total ); printf( "\033[2K\n" ); } @@ -111,10 +112,9 @@ columnsint_t askColumn( if( column < FIRST_NUMBER ) return QUITCOLUMN; column -= FIRST_NUMBER; if( column < board.columns ) - if( board.height [ column ] < board.rows ){ - printf( "\033[A" ); + if( board.height [ column ] < board.rows ) return column; - } else printf( "\033[2Apls enter a column that ain't full" ); + else printf( "\033[2Apls enter a column that ain't full" ); else printf( "\033[2Apls enter valid column" ); printf( "\033[K\n" );