diff --git a/config.h b/config.h
index 96adca5..361eb2e 100644
--- a/config.h
+++ b/config.h
@@ -8,17 +8,3 @@
#define ONLYPUT
#define ARROWS
-
-#define INPUT_X 2
-#define INPUT_Y 1
-
-#define SCOREBOARD_X INPUT_X
-#define SCOREBOARD_Y INPUT_Y + 2
-
-#define BOARD_X SCOREBOARD_X + 28
-#define BOARD_Y SCOREBOARD_Y + 1
-
-#define BOARD_DX 3
-#define BOARD_DY 1
-
-#define SCOREBOARD_HEIGTH 10
diff --git a/connect4.c b/connect4.c
index 1c8cdc3..a18fd26 100644
--- a/connect4.c
+++ b/connect4.c
@@ -17,15 +17,13 @@
* along with this program. If not, see .
*/
#include
-#include "logic.h"
+#include "macros.h"
#include "config.h"
+#include "logic.h"
#include "types.h"
#include "ui.h"
-#define VERSION 0.0.1
-
-#define XSTR(s) STR(s)
-#define STR(s) #s
+#define VERSION 0.0.2
int main(){
// First the boilerplate stuffs
diff --git a/macros.h b/macros.h
new file mode 100644
index 0000000..a364109
--- /dev/null
+++ b/macros.h
@@ -0,0 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#pragma once
+
+#define XSTR(s) STR(s)
+#define STR(s) #s
diff --git a/makefile b/makefile
index 104db08..515ddf8 100644
--- a/makefile
+++ b/makefile
@@ -10,10 +10,13 @@ OUTDIR = out
OBJ = $(SRC:%.c=$(OBJDIR)/%.o)
+#UI_TARGET = vt100
UI_TARGET = ncurses
CC = cc
+.NOTINTERMEDIATE:
+
MSG_LINKING = Linking:
MSG_COMPILING = Compiling C:
MSG_CLEANING = Cleaning:
@@ -22,18 +25,19 @@ MSG_CLEANING_OUT = Cleaning $(OUTDIR):
all: $(OUTDIR)/connect4_$(UI_TARGET).elf
-clean_run: clean run
-
run: $(OUTDIR)/connect4_$(UI_TARGET).elf
./$<
-$(OUTDIR)/connect4_ncurses.elf: $(OBJDIR)/ui_ncurses.o $(OBJDIR)/logic.o $(OBJDIR)/connect4.o
+run_%: $(OUTDIR)/connect4_%.elf
+ ./$<
+
+$(OUTDIR)/connect4_ncurses.elf: $(addprefix $(OBJDIR)/,ui_ncurses.o logic.o connect4.o)
@echo
@echo $(MSG_LINKING) $@
mkdir -p $(@D)
$(CC) $(FLAGS) -lncursesw -o $@ $^
-$(OUTDIR)/connect4_%.elf: $(OBJDIR)/ui_%.o $(OBJDIR)/logic.o $(OBJDIR)/connect4.o
+$(OUTDIR)/connect4_%.elf: $(addprefix $(OBJDIR)/,ui_%.o logic.o connect4.o)
@echo
@echo $(MSG_LINKING) $@
mkdir -p $(@D)
@@ -49,6 +53,6 @@ clean:
@echo
@echo $(MSG_CLEANING)
@echo $(MSG_CLEANING_OBJ)
- rm $(OBJDIR)/*.o
+ rm -f $(OBJDIR)/*.o
@echo $(MSG_CLEANING_OUT)
- rm $(OUTDIR)/*.elf
+ rm -f $(OUTDIR)/*.elf
diff --git a/types.h b/types.h
index 395c3f0..ca14da5 100644
--- a/types.h
+++ b/types.h
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#pragma once
+
#include "config.h"
typedef enum {
diff --git a/ui_ncurses.c b/ui_ncurses.c
index dcdf661..9e01c9f 100644
--- a/ui_ncurses.c
+++ b/ui_ncurses.c
@@ -20,6 +20,51 @@
#include
#include
+#ifndef INPUT_X
+#define INPUT_X 2
+#endif
+#ifndef INPUT_Y
+#define INPUT_Y 1
+#endif
+
+#ifdef ARROWS
+
+#ifndef SCOREBOARD_X
+#define SCOREBOARD_X 2
+#endif
+#ifndef SCOREBOARD_Y
+#define SCOREBOARD_Y 1
+#endif
+
+#else
+
+#ifndef SCOREBOARD_X
+#define SCOREBOARD_X INPUT_X
+#endif
+#ifndef SCOREBOARD_Y
+#define SCOREBOARD_Y INPUT_Y + 2
+#endif
+
+#endif
+
+#ifndef BOARD_X
+#define BOARD_X SCOREBOARD_X + 28
+#endif
+#ifndef BOARD_Y
+#define BOARD_Y SCOREBOARD_Y + 1
+#endif
+
+#ifndef BOARD_DX
+#define BOARD_DX 3
+#endif
+#ifndef BOARD_DY
+#define BOARD_DY 1
+#endif
+
+#ifndef SCOREBOARD_HEIGTH
+#define SCOREBOARD_HEIGTH 10
+#endif
+
void initBoard( void ){
setlocale(LC_ALL, "");
initscr();
@@ -249,9 +294,19 @@ int askColumn(
}
#ifndef ONLYPUT
-static move_t askMove( void ){
+move_t askMove( void ){
move_t move = PUT;
// TODO: actually ask what move
return move;
}
#endif /* ! ONLYPUT */
+
+#undef INPUT_X
+#undef INPUT_Y
+#undef SCOREBOARD_X
+#undef SCOREBOARD_Y
+#undef BOARD_X
+#undef BOARD_Y
+#undef BOARD_DX
+#undef BOARD_DY
+#undef SCOREBOARD_HEIGTH
diff --git a/ui_vt100.c b/ui_vt100.c
new file mode 100644
index 0000000..37cab86
--- /dev/null
+++ b/ui_vt100.c
@@ -0,0 +1,169 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * AnnaConnect is a silly little text-based connect 4 game c:
+ * Copyright (C) 2025 Anna Snoeijs. anna@snoeijs.tech
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include "ui.h"
+#include
+#include "macros.h"
+
+#define BOARD_WIDTH_CHARS ( 3 * BOARD_WIDTH + 6 )
+#define SCOREBOARD_OFFSET 5
+#define SCOREBOARD_WIDTH 27
+#define SCOREBOARD_HEIGTH 9
+
+void initBoard( void ){
+ for( int i = SCOREBOARD_HEIGTH - ( BOARD_HEIGTH + 2 ); i > 0; i-- )
+ putchar( '\n' );
+ printf( "\n " );
+ for( int column = 0; column < BOARD_WIDTH; column++ )
+ printf( "%2d ", column + FIRST_NUMBER );
+ putchar( '\n' );
+ for( int row = BOARD_HEIGTH - 1; row > -1; row-- ){
+ // begin row
+ printf( "%2d " , row + FIRST_NUMBER );
+ for( int column = 0; column < BOARD_WIDTH; column++ )
+ printf( "[ ]" );
+ // end of row
+ printf( "%2d" , row + FIRST_NUMBER );
+ switch( row ){
+ }
+ putchar( '\n' );
+ }
+ // end of board
+ printf( " " );
+ for( int column = 0; column < BOARD_WIDTH; 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_HEIGTH)"A"
+ "┌───────────────┬────┬────┐"SCOREBOARD_LINE_END
+ "│ player │ 0 │ 1 │"SCOREBOARD_LINE_END
+ "├───────────────┼────┼────┤"SCOREBOARD_LINE_END
+ "│ vertical │ │ │"SCOREBOARD_LINE_END
+ "│ horizontal │ │ │"SCOREBOARD_LINE_END
+ "│ diagonal up │ │ │"SCOREBOARD_LINE_END
+ "│ diagonal down │ │ │"SCOREBOARD_LINE_END
+ "├───────────────┼────┼────┤"SCOREBOARD_LINE_END
+ "│ total │ │ │"SCOREBOARD_LINE_END
+ "└───────────────┴────┴────┘"SCOREBOARD_LINE_END
+ );
+#undef SCOREBOARD_LINE_END
+ putchar( '\n' );
+ putchar( '\n' );
+}
+
+void updateBoard(
+ const wins_t wins,
+ const board_t board,
+ const int column
+){
+ int heigth = board.heigth [ column ];
+#ifndef ONLYPUT
+ switch( move ){
+ case PUT: // Only print the put one
+#endif /* ! ONLYPUT */
+ printf(
+ "\033[%dA\033[%dC%c\033[%dB",
+ heigth + 3,
+ column * 3 + 4,
+ '0' + !!( board.player ),
+ heigth + 1
+ );
+#ifndef ONLYPUT
+ break;
+ default: // Print all the pieces in the column and the air above
+ printf( "\033[%dA", heigth + 4 );
+ if( heigth < BOARD_HEIGTH ) printf( "\033[%dC ", column * 3 + 4 );
+ else printf( "\033[%dC", column * 3 + 5 );
+ for( int row = heigth; row --> 0; )
+ printf(
+ "\033[B\033[D%c",
+ '0' + !!( board.column [ column ] & ( 1 << row ) )
+ );
+ printf( "\033[2B" );
+ }
+#endif /* ! ONLYPUT */
+ printf(
+ "\r\033[7A\033[%dC"
+ "%3d │%3d\033[B\033[8D"
+ "%3d │%3d\033[B\033[8D"
+ "%3d │%3d\033[B\033[8D"
+ "%3d │%3d\033[2B\033[8D"
+ "%3d │%3d\033[2B"
+ ,BOARD_WIDTH_CHARS + 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
+ );
+ printf( "\033[2K\n" );
+}
+
+int askColumn(
+ const board_t board
+#ifndef ONLYPUT
+ ,const move_t move
+#endif /* ONLYPUT */
+){
+ int column;
+ for(;;){
+#ifndef ONLYPUT
+ switch( move ){
+ case PUT: printf( "Wher player %d put? ", board.player );
+ break;
+ case POP: printf( "Wher player %d pop? ", board.player );
+ }
+#else /* ONLYPUT */
+ printf( "Wher player %d put? ", board.player );
+#endif /* ONLYPUT */
+ printf( "\033[K" ); // clear everything after cursor
+ scanf( "%d", &column );
+ column -= FIRST_NUMBER;
+ if( column >= 0 && column < BOARD_WIDTH )
+#ifndef ONLYPUT
+ switch( move ){
+ case PUT:
+#endif /* ! ONLYPUT */
+ if( board.heigth [ column ] < BOARD_HEIGTH )
+ return column;
+ else printf( "\033[2Apls enter a column that ain't full" );
+#ifndef ONLYPUT
+ break;
+ case POP:
+ if( board.heigth [ column ] != 0 )
+ return column;
+ else printf( "\033[2Apls enter a column that ain't empty" );
+ }
+#endif /* ! ONLYPUT */
+ else
+ printf( "\033[2Apls enter valid column" );
+ printf( "\033[K\n" );
+ }
+}
+
+#ifndef ONLYPUT
+move_t askMove( void ){
+ move_t move = PUT;
+ // TODO: actually ask what move
+ return move;
+}
+#endif /* ! ONLYPUT */
+
+#undef BOARD_WIDTH_CHARS
+#undef SCOREBOARD_OFFSET
+#undef SCOREBOARD_WIDTH
+#undef SCOREBOARD_HEIGTH