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