Rewrote alot of shtuff to trans the code to ncurses instead of using VT100 escape codes directly

This commit is contained in:
AnnaSnoeijs 2025-06-06 21:31:59 +02:00
parent 2e807ba279
commit a561d5b61c
2 changed files with 182 additions and 115 deletions

View file

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* /*
* AnnaConnect is a silly little text-based connect 4 game c: * AnnaConnect is a silly little text-based connect 4 game c:
* Copyright (C) 2024 Anna Snoeijs. anna@snoeijs.tech * Copyright (C) 2025 Anna Snoeijs. anna@snoeijs.tech
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -16,14 +16,32 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <ncurses.h>
#include <locale.h>
#define VERSION 25.01.sid
#define BOARD_WIDTH 7 #define BOARD_WIDTH 7
#define BOARD_HEIGTH 6 #define BOARD_HEIGTH 6
#define FIRST_NUMBER 1 #define FIRST_NUMBER 1
#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
#define XSTR(s) STR(s) #define XSTR(s) STR(s)
#define STR(s) #s #define STR(s) #s
@ -89,104 +107,144 @@ static inline int bottomHeigthMask( const int a, const int b ){
return safeHeigthMask( bottom( a, b ) ); return safeHeigthMask( bottom( a, b ) );
} }
#define BOARD_WIDTH_CHARS ( 3 * BOARD_WIDTH + 6 )
#define SCOREBOARD_OFFSET 5
#define SCOREBOARD_WIDTH 27
#define SCOREBOARD_HEIGTH 9
static void initBoard( void ){ static void initBoard( void ){
for(int i = SCOREBOARD_HEIGTH - ( BOARD_HEIGTH + 2 ); i > 0; i-- ) setlocale(LC_ALL, "");
putchar( '\n' ); initscr();
printf( "\n " ); keypad(stdscr, TRUE);
for( int column = 0; column < BOARD_WIDTH; column++ ) nonl();
printf( "%2d ", column + FIRST_NUMBER ); echo();
putchar( '\n' ); for( int column = 0; column < BOARD_WIDTH; column++ ){
for( int row = BOARD_HEIGTH - 1; row > -1; row-- ){ char colnum[4];
// begin row sprintf( colnum, "%2d", column + FIRST_NUMBER );
printf( "%2d " , row + FIRST_NUMBER ); mvaddstr(
for( int column = 0; column < BOARD_WIDTH; column++ ) BOARD_Y,
printf( "[ ]" ); BOARD_X + BOARD_DX * ( column + 1 ),
// end of row colnum
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 for(int row = 0; row < BOARD_HEIGTH; row++){
putchar( '\n' ); mvaddstr(
putchar( '\n' ); BOARD_Y + BOARD_DY * ( row + 1 ),
BOARD_X + BOARD_DX * ( column + 1 ),
"[ ]"
);
}
mvaddstr(
BOARD_Y + BOARD_DY * ( BOARD_HEIGTH + 1 ),
BOARD_X + BOARD_DX * ( column + 1 ),
colnum
);
}
for(int row = 0; row < BOARD_HEIGTH; row++ ){
char rownum[4];
sprintf( rownum, "%2d", row + FIRST_NUMBER );
mvaddstr(
BOARD_Y + BOARD_DY * ( row + 1 ),
BOARD_X,
rownum
);
mvaddstr(
BOARD_Y + BOARD_DY * ( row + 1 ),
BOARD_X + BOARD_DX * ( BOARD_WIDTH + 1 ),
rownum
);
}
for( int y = 0; y < SCOREBOARD_HEIGTH; y++ ){
char *str;
switch(y){
case 0: str = "┌───────────────┬────┬────┐"; break;
case 1: str = "│ player │ 0 │ 1 │"; break;
case 2: str = "├───────────────┼────┼────┤"; break;
case 3: str = "│ vertical │ │ │"; break;
case 4: str = "│ horizontal │ │ │"; break;
case 5: str = "│ diagonal up │ │ │"; break;
case 6: str = "│ diagonal down │ │ │"; break;
case 7: str = "├───────────────┼────┼────┤"; break;
case 8: str = "│ total │ │ │"; break;
case 9: str = "└───────────────┴────┴────┘"; break;
default: str = "The code be brokeys at initboard for the score";
}
mvaddstr(
SCOREBOARD_Y + y,
SCOREBOARD_X,
str
);
}
} }
static void updateBoard( static void updateBoard(
const wins_t wins, const wins_t wins,
const board_t board, const board_t board,
#ifndef ONLYPUT
const move_t move,
#endif /* ! ONLYPUT */
const int column const int column
){ ){
int heigth = board.heigth [ column ]; for(int row = 0; row < board.heigth[ column ]; row++){
#ifndef ONLYPUT mvaddstr(
switch( move ){ BOARD_Y + BOARD_DY * ( BOARD_HEIGTH - row ),
case PUT: // Only print the put one BOARD_X + 1 + BOARD_DX * ( column + 1 ),
#endif /* ! ONLYPUT */ board.column[ column ] & 1 << row ? "1" : "0"
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 */ char num[4];
printf( sprintf( num, "%3d", wins.count0.vertical );
"\r\033[7A\033[%dC" mvaddstr(
"%3d │%3d\033[B\033[8D" SCOREBOARD_Y + 3,
"%3d │%3d\033[B\033[8D" SCOREBOARD_X + 17,
"%3d │%3d\033[B\033[8D" num
"%3d │%3d\033[2B\033[8D" );
"%3d │%3d\033[2B" sprintf( num, "%3d", wins.count1.vertical );
,BOARD_WIDTH_CHARS + SCOREBOARD_WIDTH - 8 mvaddstr(
,wins.count0.vertical, wins.count1.vertical SCOREBOARD_Y + 3,
,wins.count0.horizontal, wins.count1.horizontal SCOREBOARD_X + 22,
,wins.count0.diagonalUp, wins.count1.diagonalUp num
,wins.count0.diagonalDown, wins.count1.diagonalDown );
,wins.count0.total, wins.count1.total sprintf( num, "%3d", wins.count0.horizontal );
mvaddstr(
SCOREBOARD_Y + 4,
SCOREBOARD_X + 17,
num
);
sprintf( num, "%3d", wins.count1.horizontal );
mvaddstr(
SCOREBOARD_Y + 4,
SCOREBOARD_X + 22,
num
);
sprintf( num, "%3d", wins.count0.diagonalUp );
mvaddstr(
SCOREBOARD_Y + 5,
SCOREBOARD_X + 17,
num
);
sprintf( num, "%3d", wins.count1.diagonalUp );
mvaddstr(
SCOREBOARD_Y + 5,
SCOREBOARD_X + 22,
num
);
sprintf( num, "%3d", wins.count0.diagonalDown );
mvaddstr(
SCOREBOARD_Y + 6,
SCOREBOARD_X + 17,
num
);
sprintf( num, "%3d", wins.count1.diagonalDown );
mvaddstr(
SCOREBOARD_Y + 6,
SCOREBOARD_X + 22,
num
);
sprintf( num, "%3d", wins.count0.total );
mvaddstr(
SCOREBOARD_Y + 8,
SCOREBOARD_X + 17,
num
);
sprintf( num, "%3d", wins.count1.total );
mvaddstr(
SCOREBOARD_Y + 8,
SCOREBOARD_X + 22,
num
); );
printf( "\033[2K\n" );
} }
#undef BOARD_WIDTH_CHARS
#undef SCOREBOARD_OFFSET
#undef SCOREBOARD_WIDTH
#undef SCOREBOARD_HEIGTH
static void playMove( static void playMove(
board_t *boardptr, board_t *boardptr,
@ -217,39 +275,53 @@ static int askColumn(
,const move_t move ,const move_t move
#endif /* ONLYPUT */ #endif /* ONLYPUT */
){ ){
int column; int column = 0;
for(;;){ for(;;){
mvaddstr(
INPUT_Y,
INPUT_X,
"Where does player "
);
if( board.player ) addstr( "1" );
else addstr( "0" );
#ifndef ONLYPUT #ifndef ONLYPUT
switch( move ){ switch( move ){
case PUT: printf( "Wher player %d put? ", board.player ); case PUT:
break;
case POP: printf( "Wher player %d pop? ", board.player );
}
#else /* ONLYPUT */
printf( "Wher player %d put? ", board.player );
#endif /* ONLYPUT */ #endif /* ONLYPUT */
printf( "\033[K" ); // clear everything after cursor addstr( " put the piece? " );
scanf( "%d", &column ); #ifndef ONLYPUT
break;
case POP:
addstr( " pop a piece? " );
}
#endif /* ONLYPUT */
clrtoeol();
refresh();
scanw( " %d", &column );
column -= FIRST_NUMBER; column -= FIRST_NUMBER;
if( column >= 0 && column < BOARD_WIDTH ) move(
INPUT_Y + 1,
INPUT_X
);
clrtoeol();
if( column >= 0 && column < BOARD_WIDTH ) // The collumn--; is a really
// temporary placeholder to make the unfinished shit compile at least
#ifndef ONLYPUT #ifndef ONLYPUT
switch( move ){ switch( move ){
case PUT: case PUT:
#endif /* ! ONLYPUT */ #endif /* ! ONLYPUT */
if( board.heigth [ column ] < BOARD_HEIGTH ) if( board.heigth [ column ] < BOARD_HEIGTH )
return column; return column;
else printf( "\033[2Apls enter a column that ain't full" ); else addstr( "Pls enter a column that ain't full" );
#ifndef ONLYPUT #ifndef ONLYPUT
break; break;
case POP: case POP:
if( board.heigth [ column ] != 0 ) if( board.heigth [ column ] != 0 )
return column; return column;
else printf( "\033[2Apls enter a column that ain't empty" ); else addstr( "Pls enter a column that ain't empty" );
} }
#endif /* ! ONLYPUT */ #endif /* ! ONLYPUT */
else else addstr( "Pls enter a column that exists" );
printf( "\033[2Apls enter valid column" );
printf( "\033[K\n" );
} }
} }
@ -367,12 +439,13 @@ static void calcWins(
int main(){ int main(){
// First the boilerplate stuffs // First the boilerplate stuffs
printf( printf(
"AnnaConnect version 2024, Copyright (C) Anna Snoeijs\n" "AnnaConnect version "XSTR(VERSION)", Copyright (C) Anna Snoeijs\n"
"AnnaConnect comes with ABSOLUTELY NO WARRANTY\n" "AnnaConnect comes with ABSOLUTELY NO WARRANTY\n"
"This is free software, and you are welcome to redistribute it\n" "This is free software, and you are welcome to redistribute it\n"
"under certain condtions\n" "under certain condtions\n"
); );
// board, innit? // board, innit?
initBoard();
board_t playboard = { board_t playboard = {
.player = 0, .player = 0,
.column = {0}, .column = {0},
@ -396,22 +469,16 @@ int main(){
.win0 = {0}, .win0 = {0},
.win1 = {0}, .win1 = {0},
}; };
for(;; playboard.player = !playboard.player ){
#ifndef ONLYPUT #ifndef ONLYPUT
move_t move = PUT; move_t move = askMove();
#endif /* ! ONLYPUT */ int column = askColumn( playboard, move );
initBoard();
for( int column = 0;; playboard.player = !playboard.player ){
#ifndef ONLYPUT
move = askMove();
column = askColumn( playboard, move );
playMove( &playboard, move, column ); playMove( &playboard, move, column );
calcWins( &wins, playboard );
updateBoard( wins, playboard, move, column );
#else /* ONLYPUT */ #else /* ONLYPUT */
column = askColumn( playboard ); int column = askColumn( playboard );
playMove( &playboard, column ); playMove( &playboard, column );
#endif /* ONLYPUT */
calcWins( &wins, playboard ); calcWins( &wins, playboard );
updateBoard( wins, playboard, column ); updateBoard( wins, playboard, column );
#endif /* ONLYPUT */
} }
} }

View file

@ -1,5 +1,5 @@
#!/usr/bin/make -f #!/usr/bin/make -f
FLAGS = -O3 -pedantic -Wall -Wextra -Werror FLAGS = -O3 -pedantic -Wall -Wextra -Werror -lncursesw
AnnaConnect: connect4.c AnnaConnect: connect4.c
cc $(FLAGS) -o connect4 connect4.c cc $(FLAGS) -o connect4 connect4.c