From b50a6f34869a1a721419c9b08e2aa668120c148a Mon Sep 17 00:00:00 2001 From: AnnaSnoeijs Date: Sat, 14 Jun 2025 20:35:22 +0200 Subject: [PATCH 01/10] Made arrows the only input for ncurses because I never test the rest --- config.h | 2 -- ui_ncurses.c | 27 --------------------------- 2 files changed, 29 deletions(-) diff --git a/config.h b/config.h index f1e8451..a134cab 100644 --- a/config.h +++ b/config.h @@ -5,5 +5,3 @@ #define BOARD_HEIGHT 6 #define FIRST_NUMBER 1 - -#define ARROWS diff --git a/ui_ncurses.c b/ui_ncurses.c index 00bf47c..cdf0e7b 100644 --- a/ui_ncurses.c +++ b/ui_ncurses.c @@ -211,7 +211,6 @@ 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" ); @@ -245,32 +244,6 @@ 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){ From e4c5cc3a46f0f5b83df844fb91a7f2a30995b009 Mon Sep 17 00:00:00 2001 From: AnnaSnoeijs Date: Sat, 14 Jun 2025 22:12:57 +0200 Subject: [PATCH 02/10] Corrected comment --- types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types.h b/types.h index f5b3688..df3c0a4 100644 --- a/types.h +++ b/types.h @@ -5,7 +5,7 @@ #include #include "config.h" -// Only use big ints on architectures where it doesn't impact speed +// Use fastest available ints unless it's 64 bits because that uses more memory #if INT_FAST16_MAX == INT_FAST64_MAX typedef int rowsint_t; typedef unsigned columnsint_t; From 315b59ec29d8bb20e751b97877e378cd8e07ce09 Mon Sep 17 00:00:00 2001 From: AnnaSnoeijs Date: Sat, 14 Jun 2025 22:13:29 +0200 Subject: [PATCH 03/10] Commented makefile --- makefile | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index f08e653..707ac60 100644 --- a/makefile +++ b/makefile @@ -1,27 +1,46 @@ #!/usr/bin/make -f + +# Target architecture for compilation +ARCH = native + +# Optimization level +O = 3 + +# Flags for the compiler FLAGS = -std=c23 -FLAGS += -O3 -FLAGS += -march=native +FLAGS += -O$(O) +FLAGS += -march=$(ARCH) +# Only override gcc default tuning if specified in make command line +ifneq (, $(TUNE)) + FLAGS += -mtune=$(TUNE) +endif FLAGS += -pedantic FLAGS += -Wall FLAGS += -Wextra FLAGS += -Werror +# This flag is because of the compiler otherwise giving too much warning 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: @@ -29,44 +48,57 @@ 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) From 4bfaa26297d7d0ff71015e0e31b11f1483262145 Mon Sep 17 00:00:00 2001 From: AnnaSnoeijs Date: Sat, 14 Jun 2025 22:15:47 +0200 Subject: [PATCH 04/10] Acknowledged lack of documentation --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ba3fd52..6abf6df 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,7 @@ AnnaConnect is a silly little text-based connect 4 game c: -Supports vt100 escape codes and ncurses for drawing the UI \ No newline at end of file +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 From c72abd8bbfe6bc80721c116c4d41f418b43c5c4f Mon Sep 17 00:00:00 2001 From: AnnaSnoeijs Date: Sat, 14 Jun 2025 23:02:26 +0200 Subject: [PATCH 05/10] Added attributes to code such that -Wformat-truncation=0 can be removed --- makefile | 2 +- ui_ncurses.c | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/makefile b/makefile index 707ac60..5d10e86 100644 --- a/makefile +++ b/makefile @@ -19,7 +19,7 @@ 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)' diff --git a/ui_ncurses.c b/ui_ncurses.c index cdf0e7b..8da8914 100644 --- a/ui_ncurses.c +++ b/ui_ncurses.c @@ -71,6 +71,7 @@ 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( @@ -96,8 +97,10 @@ 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", board.rows - row + FIRST_NUMBER - 1 + rownum, sizeof(rownum), "%2d", intToPrint ); mvaddstr( BOARD_Y + BOARD_DY * ( row + 1 ), @@ -215,8 +218,13 @@ columnsint_t askColumn( if( board.player ) addstr( "p1" ); else addstr( "p0" ); refresh(); - for(; board.height[ column ] >= board.rows; ) - column += ( column < board.columns - 1 ); + for(; board.height[ column ] >= board.rows; ){ + column++; + if( column == board.columns ){ + getch(); + return QUITCOLUMN; + } + } for(;;){ int ch = mvgetch( BOARD_Y + BOARD_DY * ( board.rows - board.height[ column ] ), From 316fbbc66e9e1664f468ce6706cb4f974b80298b Mon Sep 17 00:00:00 2001 From: AnnaSnoeijs Date: Wed, 25 Jun 2025 11:18:46 +0200 Subject: [PATCH 06/10] Removed needless inlines --- logic.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/logic.c b/logic.c index 43e192e..47ac14a 100644 --- a/logic.c +++ b/logic.c @@ -18,27 +18,27 @@ */ #include "logic.h" -static inline int top( const int a, const int b ){ +static int top( const int a, const int b ){ return a < b ? b : a; } -static inline int bottom( const int a, const int b ){ +static int bottom( const int a, const int b ){ return a < b ? a : b; } -static inline int heightMask( const int a ){ +static int heightMask( const int a ){ return ( 1 << a ) - 1; } -static inline int safeHeightMask( const int a ){ +static int safeHeightMask( const int a ){ return a > 0 ? heightMask( a ) : 0; } -static inline int bottomHeightMask( const int a, const int b ){ +static int bottomHeightMask( const int a, const int b ){ return safeHeightMask( bottom( a, b ) ); } -inline void playMove( +void playMove( board_t *boardptr, const int column ){ @@ -47,7 +47,7 @@ inline void playMove( boardptr->height [ column ]++; } -inline void calcWins( +void calcWins( wins_t *wins, const board_t board, const int column From 8c41443935e0dc124436caf1537868e9b633d5b4 Mon Sep 17 00:00:00 2001 From: AnnaSnoeijs Date: Wed, 25 Jun 2025 11:26:06 +0200 Subject: [PATCH 07/10] Moved top() and bottom() to macros.h --- logic.c | 9 +-------- macros.h | 3 +++ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/logic.c b/logic.c index 47ac14a..1bd09c3 100644 --- a/logic.c +++ b/logic.c @@ -17,14 +17,7 @@ * along with this program. If not, see . */ #include "logic.h" - -static int top( const int a, const int b ){ - return a < b ? b : a; -} - -static int bottom( const int a, const int b ){ - return a < b ? a : b; -} +#include "macros.h" static int heightMask( const int a ){ return ( 1 << a ) - 1; diff --git a/macros.h b/macros.h index a364109..0326c6c 100644 --- a/macros.h +++ b/macros.h @@ -1,5 +1,8 @@ /* 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 XSTR(s) STR(s) #define STR(s) #s From 22356ca52901e24182f46e01d74122f808a92e17 Mon Sep 17 00:00:00 2001 From: AnnaSnoeijs Date: Wed, 25 Jun 2025 11:31:45 +0200 Subject: [PATCH 08/10] Fixed types --- logic.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/logic.c b/logic.c index 1bd09c3..9ff57de 100644 --- a/logic.c +++ b/logic.c @@ -19,21 +19,21 @@ #include "logic.h" #include "macros.h" -static int heightMask( const int a ){ +static column_t heightMask( const rowsint_t a ){ return ( 1 << a ) - 1; } -static int safeHeightMask( const int a ){ +static column_t safeHeightMask( const rowsint_t a ){ return a > 0 ? heightMask( a ) : 0; } -static int bottomHeightMask( const int a, const int b ){ +static column_t bottomHeightMask( const rowsint_t a, const rowsint_t b ){ return safeHeightMask( bottom( a, b ) ); } void playMove( board_t *boardptr, - const int column + const columnsint_t column ){ boardptr->column [ column ] |= boardptr->player << boardptr->height [ column ]; @@ -43,7 +43,7 @@ void playMove( void calcWins( wins_t *wins, const board_t board, - const int column + const columnsint_t column ){ // First the simplest win, the humble tower // Check for lil towers @@ -72,7 +72,7 @@ void calcWins( // Now the rest of the wins // First connect 2 for( - int i = top( column - 1, 0 ); + columnsint_t i = top( column - 1, 0 ); i < bottom( column + 1, board.columns - 1 ); i++ ){ @@ -101,7 +101,7 @@ void calcWins( } // Then stitch the twos together and count for( - int i = top( column - 3, 0 ); + columnsint_t i = top( column - 3, 0 ); i < bottom( column + 1, board.columns - 3 ); i++ ){ From e31258e26cccefedcbfc7ec93b70bbf231a40282 Mon Sep 17 00:00:00 2001 From: AnnaSnoeijs Date: Wed, 25 Jun 2025 11:41:51 +0200 Subject: [PATCH 09/10] Fixed a little silly --- logic.c | 4 ++-- logic.h | 4 ++-- macros.h | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/logic.c b/logic.c index 9ff57de..aa36dff 100644 --- a/logic.c +++ b/logic.c @@ -72,7 +72,7 @@ void calcWins( // Now the rest of the wins // First connect 2 for( - columnsint_t i = top( column - 1, 0 ); + columnsint_t i = clipped_subtract( column, 1 ); i < bottom( column + 1, board.columns - 1 ); i++ ){ @@ -101,7 +101,7 @@ void calcWins( } // Then stitch the twos together and count for( - columnsint_t i = top( column - 3, 0 ); + columnsint_t i = clipped_subtract( column, 3 ); i < bottom( column + 1, board.columns - 3 ); i++ ){ diff --git a/logic.h b/logic.h index 4123f8a..488894c 100644 --- a/logic.h +++ b/logic.h @@ -6,11 +6,11 @@ extern void playMove( board_t *boardptr, - const int column + const columnsint_t column ); extern void calcWins( wins_t *wins, const board_t board, - const int column + const columnsint_t column ); diff --git a/macros.h b/macros.h index 0326c6c..20b6cf4 100644 --- a/macros.h +++ b/macros.h @@ -3,6 +3,7 @@ #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 From a5fcaa00d750566b1f4ff0254e9923a424e3bed2 Mon Sep 17 00:00:00 2001 From: AnnaSnoeijs Date: Sun, 27 Jul 2025 22:10:35 +0200 Subject: [PATCH 10/10] Made ui_vt100 able to be used without askColumn between every updateBoard --- ui_vt100.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ui_vt100.c b/ui_vt100.c index cbf68b4..03b0a8d 100644 --- a/ui_vt100.c +++ b/ui_vt100.c @@ -65,14 +65,13 @@ 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 + 3, + height + 2, column * 3 + 4, '0' + !!( board.player ), height + 1 @@ -85,11 +84,11 @@ void updateBoard( "" WININT_FORMAT " │" WININT_FORMAT "\033[2B\033[8D" "" WININT_FORMAT " │" WININT_FORMAT "\033[2B" ,( 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 - ,wins.count0.diagonalDown, wins.count1.diagonalDown - ,wins.count0.total, wins.count1.total + ,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 ); printf( "\033[2K\n" ); } @@ -112,9 +111,10 @@ columnsint_t askColumn( if( column < FIRST_NUMBER ) return QUITCOLUMN; column -= FIRST_NUMBER; if( column < board.columns ) - if( board.height [ column ] < board.rows ) + if( board.height [ column ] < board.rows ){ + printf( "\033[A" ); 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" );