/* 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@hotmail.com * * 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 #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_HEIGHT #define SCOREBOARD_HEIGHT 10 #endif void initBoard( const board_t board ){ setlocale(LC_ALL, ""); initscr(); keypad(stdscr, TRUE); nonl(); echo(); for( int column = 0; column < board.columns; 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.rows; row++){ mvaddstr( BOARD_Y + BOARD_DY * ( row + 1 ), BOARD_X + BOARD_DX * ( column + 1 ), "[ ]" ); } mvaddstr( BOARD_Y + BOARD_DY * ( board.rows + 1 ), BOARD_X + BOARD_DX * ( column + 1 ), colnum ); } for(int row = 0; row < board.rows; row++ ){ char rownum[4]; sprintf( rownum, "%2d", board.rows - row + FIRST_NUMBER - 1 ); mvaddstr( BOARD_Y + BOARD_DY * ( row + 1 ), BOARD_X, rownum ); mvaddstr( BOARD_Y + BOARD_DY * ( row + 1 ), BOARD_X + BOARD_DX * ( board.columns + 1 ), rownum ); } for( int y = 0; y < SCOREBOARD_HEIGHT; 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 move_t move, const int column ){ int height = board.height[ column ]; switch( move ){ case PUT: mvaddstr( BOARD_Y + BOARD_DY * ( board.rows - height + 1 ), BOARD_X + 1 + BOARD_DX * ( column + 1 ), board.column[ column ] & 1 << ( height - 1 ) ? "1" : "0" ); break; default: for( int row = 0; row < height; row++ ){ mvaddstr( BOARD_Y + BOARD_DY * ( board.rows - row ), BOARD_X + 1 + BOARD_DX * ( column + 1 ), board.column[ column ] & 1 << row ? "1" : "0" ); } break; } 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, const move_t move ){ int column = 0; #ifdef ARROWS move( BOARD_Y, BOARD_X ); if( board.player ) addstr( "p1" ); else addstr( "p0" ); refresh(); for(; board.height[ column ] >= board.rows; ) column += ( column < board.columns - 1 ); for(;;){ int ch = mvgetch( BOARD_Y + BOARD_DY * ( board.rows - board.height[ column ] ), BOARD_X + 1 + BOARD_DX * ( column + 1 ) ); switch( ch ){ case KEY_RIGHT: column += ( column < board.columns - 1 ); break; case KEY_LEFT: column -= ( column > 0 ); break; case KEY_DOWN: return column; } switch( move ){ case PUT: for(; board.height[ column ] >= board.rows; ) switch( ch ){ case KEY_RIGHT: if( column >= board.columns ) ch = KEY_LEFT; else column++; break; case KEY_LEFT: if( column == 0 ) ch = KEY_RIGHT; else column--; break; } break; case POP: for(; board.height[ column ] <= 0; ) switch( ch ){ case KEY_RIGHT: if( column >= board.columns ) ch = KEY_LEFT; else column++; break; case KEY_LEFT: if( column == 0 ) ch = KEY_RIGHT; else column--; break; } break; // Do nothing } } #else /* !ARROWS */ for(;;){ mvaddstr( INPUT_Y, INPUT_X, "Where does player " ); if( board.player ) addstr( "1" ); else addstr( "0" ); switch( move ){ case PUT: addstr( " put the piece? " ); case POP: addstr( " pop a piece? " ); } clrtoeol(); refresh(); scanw( " %d", &column ); column -= FIRST_NUMBER; move( INPUT_Y + 1, INPUT_X ); clrtoeol(); if( column >= 0 && column < board.columns ) switch( move ){ case PUT: if( board.height [ column ] < board.columns ) return column; else addstr( "Pls enter a column that ain't full" ); break; case POP: if( board.height [ column ] != 0 ) return column; else addstr( "Pls enter a column that ain't empty" ); } else addstr( "Pls enter a column that exists" ); } #endif /* ! ARROWS */ } move_t askMove( void ){ move_t move = PUT; // TODO: actually ask what move return move; } #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_HEIGHT