/* 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(); __attribute__((assume(board.columns < 999))); for( columnsint_t column = 0; column < board.columns; column++ ){ char colnum[4]; snprintf( colnum, sizeof(colnum), "%2d", column + FIRST_NUMBER ); mvaddstr( BOARD_Y, BOARD_X + BOARD_DX * ( column + 1 ), colnum ); for( rowsint_t 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( rowsint_t row = 0; row < board.rows; row++ ){ char rownum[4]; const int intToPrint = board.rows - row + FIRST_NUMBER - 1; __attribute__((assume(intToPrint <= 256))); snprintf( rownum, sizeof(rownum), "%2d", intToPrint ); 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( uint_fast8_t 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 board_t board, const columnsint_t column ){ rowsint_t height = board.height[ column ]; mvaddstr( BOARD_Y + BOARD_DY * ( board.rows - height + 1 ), BOARD_X + 1 + BOARD_DX * ( column + 1 ), board.column[ column ] & 1 << ( height - 1 ) ? "1" : "0" ); char num[4]; snprintf( num, sizeof(num), WININT_FORMAT, board.count0.vertical ); mvaddstr( SCOREBOARD_Y + 3, SCOREBOARD_X + 17, num ); snprintf( num, sizeof(num), WININT_FORMAT, board.count1.vertical ); mvaddstr( SCOREBOARD_Y + 3, SCOREBOARD_X + 22, num ); snprintf( num, sizeof(num), WININT_FORMAT, board.count0.horizontal ); mvaddstr( SCOREBOARD_Y + 4, SCOREBOARD_X + 17, num ); snprintf( num, sizeof(num), WININT_FORMAT, board.count1.horizontal ); mvaddstr( SCOREBOARD_Y + 4, SCOREBOARD_X + 22, num ); snprintf( num, sizeof(num), WININT_FORMAT, board.count0.diagonalUp ); mvaddstr( SCOREBOARD_Y + 5, SCOREBOARD_X + 17, num ); snprintf( num, sizeof(num), WININT_FORMAT, board.count1.diagonalUp ); mvaddstr( SCOREBOARD_Y + 5, SCOREBOARD_X + 22, num ); snprintf( num, sizeof(num), WININT_FORMAT, board.count0.diagonalDown ); mvaddstr( SCOREBOARD_Y + 6, SCOREBOARD_X + 17, num ); snprintf( num, sizeof(num), WININT_FORMAT, board.count1.diagonalDown ); mvaddstr( SCOREBOARD_Y + 6, SCOREBOARD_X + 22, num ); snprintf( num, sizeof(num), WININT_FORMAT, board.count0.total ); mvaddstr( SCOREBOARD_Y + 8, SCOREBOARD_X + 17, num ); snprintf( num, sizeof(num), WININT_FORMAT, board.count1.total ); mvaddstr( SCOREBOARD_Y + 8, SCOREBOARD_X + 22, num ); } columnsint_t askColumn( const board_t board ){ columnsint_t column = 0; move( BOARD_Y, BOARD_X ); if( board.player ) addstr( "p1" ); else addstr( "p0" ); refresh(); for(; board.height[ column ] >= board.rows; ){ column++; if( column == board.columns ){ getch(); return QUITCOLUMN; } } 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: if( column == 0 ) return QUITCOLUMN; column --; break; case KEY_DOWN: return column; } 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 ) return QUITCOLUMN; else column--; break; } } } void exit_ui(void){ endwin(); } #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