AnnaConnect/ui_ncurses.c
2025-06-06 21:31:59 +02:00

257 lines
6.1 KiB
C

/* 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 <https://www.gnu.org/licenses/>.
*/
#include "ui.h"
#include <ncurses.h>
#include <locale.h>
void initBoard( void ){
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 ),
"[ ]"
);
}
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
);
}
}
void updateBoard(
const wins_t wins,
const board_t board,
const int column
){
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"
);
}
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
);
}
int askColumn(
const board_t board
#ifndef ONLYPUT
,const move_t move
#endif /* ONLYPUT */
){
int column = 0;
#ifdef ARROWS
move( BOARD_Y, BOARD_X );
if( board.player ) addstr( "p1" );
else addstr( "p0" );
refresh();
for(; board.heigth[ column ] >= BOARD_HEIGTH; )
column += ( column < BOARD_WIDTH - 1 );
for(;;){
int ch = mvgetch(
BOARD_Y + BOARD_DY * ( BOARD_HEIGTH - board.heigth[ column ] ),
BOARD_X + 1 + BOARD_DX * ( column + 1 )
);
switch( ch ){
case KEY_RIGHT:
column += ( column < BOARD_WIDTH - 1 );
break;
case KEY_LEFT:
column -= ( column > 0 );
break;
case KEY_DOWN:
return column;
}
for(; board.heigth[ column ] >= BOARD_HEIGTH; ) switch( ch ){
case KEY_RIGHT:
if( column >= BOARD_WIDTH ) ch = KEY_LEFT;
else column++;
break;
case KEY_LEFT:
if( column == 0 ) ch = KEY_RIGHT;
else column--;
break;
}
}
#else /* !ARROWS */
for(;;){
mvaddstr(
INPUT_Y,
INPUT_X,
"Where does player "
);
if( board.player ) addstr( "1" );
else addstr( "0" );
#ifndef ONLYPUT
switch( move ){
case PUT:
#endif /* ONLYPUT */
addstr( " put the piece? " );
#ifndef ONLYPUT
case POP:
addstr( " pop a piece? " );
}
#endif /* ONLYPUT */
clrtoeol();
refresh();
scanw( " %d", &column );
column -= FIRST_NUMBER;
move(
INPUT_Y + 1,
INPUT_X
);
clrtoeol();
if( column >= 0 && column < BOARD_WIDTH )
#ifndef ONLYPUT
switch( move ){
case PUT:
#endif /* ! ONLYPUT */
if( board.heigth [ column ] < BOARD_HEIGTH )
return column;
else addstr( "Pls enter a column that ain't full" );
#ifndef ONLYPUT
break;
case POP:
if( board.heigth [ column ] != 0 )
return column;
else addstr( "Pls enter a column that ain't empty" );
}
#endif /* ! ONLYPUT */
else addstr( "Pls enter a column that exists" );
}
#endif /* ! ARROWS */
}
#ifndef ONLYPUT
static move_t askMove( void ){
move_t move = PUT;
// TODO: actually ask what move
return move;
}
#endif /* ! ONLYPUT */