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 */
/*
* 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
* 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
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ncurses.h>
#include <locale.h>
#define VERSION 25.01.sid
#define BOARD_WIDTH 7
#define BOARD_HEIGTH 6
#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 STR(s) #s
@ -89,104 +107,144 @@ static inline int bottomHeigthMask( const int a, const int 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 ){
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 ){
setlocale(LC_ALL, "");
initscr();
keypad(stdscr, TRUE);
nonl();
echo();
for( int column = 0; column < BOARD_WIDTH; column++ ){
char colnum[4];
sprintf( colnum, "%2d", column + FIRST_NUMBER );
mvaddstr(
BOARD_Y,
BOARD_X + BOARD_DX * ( column + 1 ),
colnum
);
for(int row = 0; row < BOARD_HEIGTH; row++){
mvaddstr(
BOARD_Y + BOARD_DY * ( row + 1 ),
BOARD_X + BOARD_DX * ( column + 1 ),
"[ ]"
);
}
putchar( '\n' );
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
);
}
// 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' );
}
static void updateBoard(
const wins_t wins,
const board_t board,
#ifndef ONLYPUT
const move_t move,
#endif /* ! ONLYPUT */
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" );
for(int row = 0; row < board.heigth[ column ]; row++){
mvaddstr(
BOARD_Y + BOARD_DY * ( BOARD_HEIGTH - row ),
BOARD_X + 1 + BOARD_DX * ( column + 1 ),
board.column[ column ] & 1 << row ? "1" : "0"
);
}
#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
char num[4];
sprintf( num, "%3d", wins.count0.vertical );
mvaddstr(
SCOREBOARD_Y + 3,
SCOREBOARD_X + 17,
num
);
sprintf( num, "%3d", wins.count1.vertical );
mvaddstr(
SCOREBOARD_Y + 3,
SCOREBOARD_X + 22,
num
);
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(
board_t *boardptr,
@ -217,39 +275,53 @@ static int askColumn(
,const move_t move
#endif /* ONLYPUT */
){
int column;
int column = 0;
for(;;){
mvaddstr(
INPUT_Y,
INPUT_X,
"Where does player "
);
if( board.player ) addstr( "1" );
else addstr( "0" );
#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 );
case PUT:
#endif /* ONLYPUT */
printf( "\033[K" ); // clear everything after cursor
scanf( "%d", &column );
addstr( " put the piece? " );
#ifndef ONLYPUT
break;
case POP:
addstr( " pop a piece? " );
}
#endif /* ONLYPUT */
clrtoeol();
refresh();
scanw( " %d", &column );
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
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" );
else addstr( "Pls 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" );
else addstr( "Pls enter a column that ain't empty" );
}
#endif /* ! ONLYPUT */
else
printf( "\033[2Apls enter valid column" );
printf( "\033[K\n" );
else addstr( "Pls enter a column that exists" );
}
}
@ -367,12 +439,13 @@ static void calcWins(
int main(){
// First the boilerplate stuffs
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"
"This is free software, and you are welcome to redistribute it\n"
"under certain condtions\n"
);
// board, innit?
initBoard();
board_t playboard = {
.player = 0,
.column = {0},
@ -396,22 +469,16 @@ int main(){
.win0 = {0},
.win1 = {0},
};
for(;; playboard.player = !playboard.player ){
#ifndef ONLYPUT
move_t move = PUT;
#endif /* ! ONLYPUT */
initBoard();
for( int column = 0;; playboard.player = !playboard.player ){
#ifndef ONLYPUT
move = askMove();
column = askColumn( playboard, move );
move_t move = askMove();
int column = askColumn( playboard, move );
playMove( &playboard, move, column );
calcWins( &wins, playboard );
updateBoard( wins, playboard, move, column );
#else /* ONLYPUT */
column = askColumn( playboard );
int column = askColumn( playboard );
playMove( &playboard, column );
#endif /* ONLYPUT */
calcWins( &wins, playboard );
updateBoard( wins, playboard, column );
#endif /* ONLYPUT */
}
}

View file

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