/* 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 #include "macros.h" #define BOARD_WIDTH_CHARS ( 3 * board.columns + 6 ) #define SCOREBOARD_OFFSET 5 #define SCOREBOARD_WIDTH 27 #define SCOREBOARD_HEIGHT 9 void initBoard( const board_t board ){ for( int i = SCOREBOARD_HEIGHT - ( board.rows + 2 ); i > 0; i-- ) putchar( '\n' ); printf( "\n " ); for( int column = 0; column < board.columns; column++ ) printf( "%2d ", column + FIRST_NUMBER ); putchar( '\n' ); for( int row = board.rows - 1; row > -1; row-- ){ // begin row printf( "%2d " , row + FIRST_NUMBER ); for( int column = 0; column < board.columns; column++ ) printf( "[ ]" ); // end of row printf( "%2d" , row + FIRST_NUMBER ); switch( row ){ } putchar( '\n' ); } // end of board printf( " " ); for( int column = 0; column < board.columns; 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_HEIGHT)"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 move_t move, const int column ){ int height = board.height [ column ]; switch( move ){ case PUT: // Only print the put one printf( "\033[%dA\033[%dC%c\033[%dB", height + 3, column * 3 + 4, '0' + !!( board.player ), height + 1 ); break; default: // Print all the pieces in the column and the air above printf( "\033[%dA", height + 4 ); if( height < board.rows ) printf( "\033[%dC ", column * 3 + 4 ); else printf( "\033[%dC", column * 3 + 5 ); for( int row = height; row --> 0; ) printf( "\033[B\033[D%c", '0' + !!( board.column [ column ] & ( 1 << row ) ) ); printf( "\033[2B" ); } 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" ,( 3 * board.columns + 6 ) + 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, const move_t move ){ int column; for(;;){ switch( move ){ case PUT: printf( "Wher player %d put? ", board.player ); break; case POP: printf( "Wher player %d pop? ", board.player ); } printf( "\033[K" ); // clear everything after cursor fflush( stdout ); column = -1; for( char ch = '0'; ch != '\n'; read( STDIN_FILENO, &ch, 1 ) ){ if( ch >= '0' && ch <= '9' ){ if( column == -1 ) column = 0; else column *= 10; if( column >= 0 ) column += ( int )( ch - '0' ); } else { column = -2; } } column -= FIRST_NUMBER; if( column >= 0 && column < board.columns ) switch( move ){ case PUT: if( board.height [ column ] < board.rows ) return column; else printf( "\033[2Apls enter a column that ain't full" ); break; case POP: if( board.height [ column ] != 0 ) return column; else printf( "\033[2Apls enter a column that ain't empty" ); } else printf( "\033[2Apls enter valid column" ); printf( "\033[K\n" ); } } move_t askMove( void ){ move_t move = PUT; // TODO: actually ask what move return move; } #undef BOARD_WIDTH_CHARS #undef SCOREBOARD_OFFSET #undef SCOREBOARD_WIDTH #undef SCOREBOARD_HEIGHT