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
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/logic.c b/logic.c
index 43e192e..aa36dff 100644
--- a/logic.c
+++ b/logic.c
@@ -17,40 +17,33 @@
* along with this program. If not, see .
*/
#include "logic.h"
+#include "macros.h"
-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 ){
+static column_t heightMask( const rowsint_t a ){
return ( 1 << a ) - 1;
}
-static inline int safeHeightMask( const int a ){
+static column_t safeHeightMask( const rowsint_t a ){
return a > 0 ? heightMask( a ) : 0;
}
-static inline 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 ) );
}
-inline void playMove(
+void playMove(
board_t *boardptr,
- const int column
+ const columnsint_t column
){
boardptr->column [ column ] |=
boardptr->player << boardptr->height [ column ];
boardptr->height [ column ]++;
}
-inline void calcWins(
+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
@@ -79,7 +72,7 @@ inline void calcWins(
// Now the rest of the wins
// First connect 2
for(
- int i = top( column - 1, 0 );
+ columnsint_t i = clipped_subtract( column, 1 );
i < bottom( column + 1, board.columns - 1 );
i++
){
@@ -108,7 +101,7 @@ inline void calcWins(
}
// Then stitch the twos together and count
for(
- int 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 a364109..20b6cf4 100644
--- a/macros.h
+++ b/macros.h
@@ -1,5 +1,9 @@
/* 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 f08e653..5d10e86 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
-FLAGS += -Wformat-truncation=0
+# 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)
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;
diff --git a/ui_ncurses.c b/ui_ncurses.c
index 00bf47c..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 ),
@@ -211,13 +214,17 @@ 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 += ( 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 ] ),
@@ -245,32 +252,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){
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" );