diff --git a/config.h b/config.h new file mode 100644 index 0000000..96adca5 --- /dev/null +++ b/config.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#pragma once + +#define BOARD_WIDTH 7 +#define BOARD_HEIGTH 6 + +#define FIRST_NUMBER 1 + +#define ONLYPUT +#define ARROWS + +#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 diff --git a/connect4.c b/connect4.c index 8e8f4ce..1c8cdc3 100644 --- a/connect4.c +++ b/connect4.c @@ -17,460 +17,16 @@ * along with this program. If not, see . */ #include -#include -#include -#include +#include "logic.h" +#include "config.h" +#include "types.h" +#include "ui.h" #define VERSION 0.0.1 -#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 -#define ONLYPUT - -#define ARROWS - -#ifndef ONLYPUT -typedef enum { - PUT, - POP -} move_t; -#endif /* ! ONLYPUT */ - -typedef struct { - int player; - int heigth [ BOARD_WIDTH ]; - int column [ BOARD_WIDTH ]; -} board_t; - -typedef struct { - int vertical2 [ BOARD_WIDTH ]; - int horizontal2 [ BOARD_WIDTH - 1 ]; - int diagonalUp2 [ BOARD_WIDTH - 1 ]; - int diagonalDown2 [ BOARD_WIDTH - 1 ]; - int vertical4 [ BOARD_WIDTH ]; - int horizontal4 [ BOARD_WIDTH - 3 ]; - int diagonalUp4 [ BOARD_WIDTH - 3 ]; - int diagonalDown4 [ BOARD_WIDTH - 3 ]; -} directions_t; - -typedef struct { - int total; - int horizontal; - int vertical; - int diagonalUp; - int diagonalDown; -} wincount_t; - -typedef struct { - wincount_t count0; - wincount_t count1; - int win0 [ BOARD_WIDTH ]; - int win1 [ BOARD_WIDTH ]; - directions_t same; -} wins_t; - -static inline int top( const int a, const int b ){ - return a < b ? b : a; -} - -static inline int bottom( const int a, const int b ){ - return a < b ? a : b; -} - -static inline int heigthMask( const int a ){ - return ( 1 << a ) - 1; -} - -static inline int safeHeigthMask( const int a ){ - return a > 0 ? heigthMask( a ) : 0; -} - -static inline int bottomHeigthMask( const int a, const int b ){ - return safeHeigthMask( bottom( a, b ) ); -} - -static 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 - ); - } -} - -static 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 - ); -} - -static void playMove( - board_t *boardptr, -#ifndef ONLYPUT - const move_t move, -#endif /* ! ONLYPUT */ - const int column -){ -#ifndef ONLYPUT - switch( move ){ - case PUT: // Put a new piece in the board -#endif /* ! ONLYPUT */ - boardptr->column [ column ] |= - boardptr->player << boardptr->heigth [ column ]; - boardptr->heigth [ column ]++; -#ifndef ONLYPUT - break; - case POP: // Pop out the lowest and make all above fall down - boardptr->column [ column ] >>= 1; - boardptr->heigth [ column ]--; - } -#endif /* ! ONLYPUT */ -} - -static 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 */ - -static void calcWins( - wins_t *wins, - const board_t board -){ - // First the simplest win, the humble tower - wins->count0.vertical = 0; - wins->count1.vertical = 0; - for( int i = 0; i < BOARD_WIDTH; i++ ){ - // Check for lil towers - wins->same.vertical2 [ i ] = - ~( board.column [ i ] - ^ board.column [ i ] >> 1 ) - & safeHeigthMask( board.heigth [ i ] - 1 ); - // Actually check for win - wins->same.vertical4 [ i ] = - wins->same.vertical2 [ i ] - & wins->same.vertical2 [ i ] >> 1 - & wins->same.vertical2 [ i ] >> 2; - // Count 'em - wins->count0.vertical += __builtin_popcount( - wins->same.vertical4 [ i ] & ~board.column [ i ] - ); - wins->count1.vertical += __builtin_popcount( - wins->same.vertical4 [ i ] & board.column [ i ] - ); - } - // Now the rest of the wins - wins->count0.horizontal = 0; - wins->count1.horizontal = 0; - wins->count0.diagonalUp = 0; - wins->count1.diagonalUp = 0; - wins->count0.diagonalDown = 0; - wins->count1.diagonalDown = 0; - // First connect 2 - for( int i = 0; i < BOARD_WIDTH - 1; i++ ){ - wins->same.horizontal2 [ i ] = - ~( board.column [ i ] - ^ board.column [ i + 1 ] ) - & bottomHeigthMask( - board.heigth [ i ], - board.heigth [ i + 1 ] - ); - wins->same.diagonalUp2 [ i ] = - ~( board.column [ i ] - ^ board.column [ i + 1 ] >> 1 ) - & bottomHeigthMask( - board.heigth [ i ], - board.heigth [ i + 1 ] - 1 - ); - wins->same.diagonalDown2 [ i ] = - ~( board.column [ i ] - ^ board.column [ i + 1 ] << 1 ) - & bottomHeigthMask( - board.heigth [ i ], - board.heigth [ i + 1 ] + 1 - ) - & ~1; // A diagonal line down ain't starts at the floor innit? - } - // Then stitch the twos together and count - for( int i = 0; i < BOARD_WIDTH - 3; i++ ){ - wins->same.horizontal4 [ i ] = - wins->same.horizontal2 [ i ] - & wins->same.horizontal2 [ i + 1 ] - & wins->same.horizontal2 [ i + 2 ]; - wins->same.diagonalUp4 [ i ] = - wins->same.diagonalUp2 [ i ] - & wins->same.diagonalUp2 [ i + 1 ] >> 1 - & wins->same.diagonalUp2 [ i + 2 ] >> 2; - wins->same.diagonalDown4 [ i ] = - wins->same.diagonalDown2 [ i ] - & wins->same.diagonalDown2 [ i + 1 ] << 1 - & wins->same.diagonalDown2 [ i + 2 ] << 2; - wins->count0.horizontal += __builtin_popcount( - wins->same.horizontal4 [ i ] & ~board.column [ i ] - ); - wins->count1.horizontal += __builtin_popcount( - wins->same.horizontal4 [ i ] & board.column [ i ] - ); - wins->count0.diagonalUp += __builtin_popcount( - wins->same.diagonalUp4 [ i ] & ~board.column [ i ] - ); - wins->count1.diagonalUp += __builtin_popcount( - wins->same.diagonalUp4 [ i ] & board.column [ i ] - ); - wins->count0.diagonalDown += __builtin_popcount( - wins->same.diagonalDown4 [ i ] & ~board.column [ i ] - ); - wins->count1.diagonalDown += __builtin_popcount( - wins->same.diagonalDown4 [ i ] & board.column [ i ] - ); - } - wins->count0.total = - wins->count0.vertical - + wins->count0.horizontal - + wins->count0.diagonalUp - + wins->count0.diagonalDown; - wins->count1.total = - wins->count1.vertical - + wins->count1.horizontal - + wins->count1.diagonalUp - + wins->count1.diagonalDown; -} - int main(){ // First the boilerplate stuffs printf( diff --git a/logic.c b/logic.c new file mode 100644 index 0000000..5b74d35 --- /dev/null +++ b/logic.c @@ -0,0 +1,165 @@ +/* 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 . + */ +#include "logic.h" + +static inline int top( const int a, const int b ){ + return a < b ? b : a; +} + +static inline int bottom( const int a, const int b ){ + return a < b ? a : b; +} + +static inline int heigthMask( const int a ){ + return ( 1 << a ) - 1; +} + +static inline int safeHeigthMask( const int a ){ + return a > 0 ? heigthMask( a ) : 0; +} + +static inline int bottomHeigthMask( const int a, const int b ){ + return safeHeigthMask( bottom( a, b ) ); +} + +void playMove( + board_t *boardptr, +#ifndef ONLYPUT + const move_t move, +#endif /* ! ONLYPUT */ + const int column +){ +#ifndef ONLYPUT + switch( move ){ + case PUT: // Put a new piece in the board +#endif /* ! ONLYPUT */ + boardptr->column [ column ] |= + boardptr->player << boardptr->heigth [ column ]; + boardptr->heigth [ column ]++; +#ifndef ONLYPUT + break; + case POP: // Pop out the lowest and make all above fall down + boardptr->column [ column ] >>= 1; + boardptr->heigth [ column ]--; + } +#endif /* ! ONLYPUT */ +} + +void calcWins( + wins_t *wins, + const board_t board +){ + // First the simplest win, the humble tower + wins->count0.vertical = 0; + wins->count1.vertical = 0; + for( int i = 0; i < BOARD_WIDTH; i++ ){ + // Check for lil towers + wins->same.vertical2 [ i ] = + ~( board.column [ i ] + ^ board.column [ i ] >> 1 ) + & safeHeigthMask( board.heigth [ i ] - 1 ); + // Actually check for win + wins->same.vertical4 [ i ] = + wins->same.vertical2 [ i ] + & wins->same.vertical2 [ i ] >> 1 + & wins->same.vertical2 [ i ] >> 2; + // Count 'em + wins->count0.vertical += __builtin_popcount( + wins->same.vertical4 [ i ] & ~board.column [ i ] + ); + wins->count1.vertical += __builtin_popcount( + wins->same.vertical4 [ i ] & board.column [ i ] + ); + } + // Now the rest of the wins + wins->count0.horizontal = 0; + wins->count1.horizontal = 0; + wins->count0.diagonalUp = 0; + wins->count1.diagonalUp = 0; + wins->count0.diagonalDown = 0; + wins->count1.diagonalDown = 0; + // First connect 2 + for( int i = 0; i < BOARD_WIDTH - 1; i++ ){ + wins->same.horizontal2 [ i ] = + ~( board.column [ i ] + ^ board.column [ i + 1 ] ) + & bottomHeigthMask( + board.heigth [ i ], + board.heigth [ i + 1 ] + ); + wins->same.diagonalUp2 [ i ] = + ~( board.column [ i ] + ^ board.column [ i + 1 ] >> 1 ) + & bottomHeigthMask( + board.heigth [ i ], + board.heigth [ i + 1 ] - 1 + ); + wins->same.diagonalDown2 [ i ] = + ~( board.column [ i ] + ^ board.column [ i + 1 ] << 1 ) + & bottomHeigthMask( + board.heigth [ i ], + board.heigth [ i + 1 ] + 1 + ) + & ~1; // A diagonal line down ain't starts at the floor innit? + } + // Then stitch the twos together and count + for( int i = 0; i < BOARD_WIDTH - 3; i++ ){ + wins->same.horizontal4 [ i ] = + wins->same.horizontal2 [ i ] + & wins->same.horizontal2 [ i + 1 ] + & wins->same.horizontal2 [ i + 2 ]; + wins->same.diagonalUp4 [ i ] = + wins->same.diagonalUp2 [ i ] + & wins->same.diagonalUp2 [ i + 1 ] >> 1 + & wins->same.diagonalUp2 [ i + 2 ] >> 2; + wins->same.diagonalDown4 [ i ] = + wins->same.diagonalDown2 [ i ] + & wins->same.diagonalDown2 [ i + 1 ] << 1 + & wins->same.diagonalDown2 [ i + 2 ] << 2; + wins->count0.horizontal += __builtin_popcount( + wins->same.horizontal4 [ i ] & ~board.column [ i ] + ); + wins->count1.horizontal += __builtin_popcount( + wins->same.horizontal4 [ i ] & board.column [ i ] + ); + wins->count0.diagonalUp += __builtin_popcount( + wins->same.diagonalUp4 [ i ] & ~board.column [ i ] + ); + wins->count1.diagonalUp += __builtin_popcount( + wins->same.diagonalUp4 [ i ] & board.column [ i ] + ); + wins->count0.diagonalDown += __builtin_popcount( + wins->same.diagonalDown4 [ i ] & ~board.column [ i ] + ); + wins->count1.diagonalDown += __builtin_popcount( + wins->same.diagonalDown4 [ i ] & board.column [ i ] + ); + } + wins->count0.total = + wins->count0.vertical + + wins->count0.horizontal + + wins->count0.diagonalUp + + wins->count0.diagonalDown; + wins->count1.total = + wins->count1.vertical + + wins->count1.horizontal + + wins->count1.diagonalUp + + wins->count1.diagonalDown; +} diff --git a/logic.h b/logic.h new file mode 100644 index 0000000..712ed87 --- /dev/null +++ b/logic.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#pragma once + +#include "config.h" +#include "types.h" + +extern void playMove( + board_t *boardptr, +#ifndef ONLYPUT + const move_t move, +#endif /* ! ONLYPUT */ + const int column +); + +extern void calcWins( + wins_t *wins, + const board_t board +); diff --git a/makefile b/makefile index 290e1a6..911332f 100644 --- a/makefile +++ b/makefile @@ -2,7 +2,7 @@ FLAGS = -O3 -pedantic -Wall -Wextra -Werror -lncursesw AnnaConnect: connect4.c - cc $(FLAGS) -o connect4 connect4.c + cc $(FLAGS) -o connect4 ui_ncurses.c logic.c connect4.c run: AnnaConnect ./connect4 diff --git a/types.h b/types.h new file mode 100644 index 0000000..395c3f0 --- /dev/null +++ b/types.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#pragma once +#include "config.h" + +typedef enum { + PUT, + POP +} move_t; + +typedef struct { + int player; + int heigth [ BOARD_WIDTH ]; + int column [ BOARD_WIDTH ]; +} board_t; + +typedef struct { + int vertical2 [ BOARD_WIDTH ]; + int horizontal2 [ BOARD_WIDTH - 1 ]; + int diagonalUp2 [ BOARD_WIDTH - 1 ]; + int diagonalDown2 [ BOARD_WIDTH - 1 ]; + int vertical4 [ BOARD_WIDTH ]; + int horizontal4 [ BOARD_WIDTH - 3 ]; + int diagonalUp4 [ BOARD_WIDTH - 3 ]; + int diagonalDown4 [ BOARD_WIDTH - 3 ]; +} directions_t; + +typedef struct { + int total; + int horizontal; + int vertical; + int diagonalUp; + int diagonalDown; +} wincount_t; + +typedef struct { + wincount_t count0; + wincount_t count1; + int win0 [ BOARD_WIDTH ]; + int win1 [ BOARD_WIDTH ]; + directions_t same; +} wins_t; diff --git a/ui.h b/ui.h new file mode 100644 index 0000000..4423255 --- /dev/null +++ b/ui.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#pragma once + +#include "types.h" +#include "config.h" + +extern void initBoard( void ); + +extern void updateBoard( + const wins_t wins, + const board_t board, + const int column +); + +extern int askColumn( + const board_t board +#ifndef ONLYPUT + ,const move_t move +#endif /* ! ONLYPUT */ +); + +#ifndef ONLYPUT +extern move_t askMove( void ); +#endif /* ! ONLYPUT */ diff --git a/ui_ncurses.c b/ui_ncurses.c new file mode 100644 index 0000000..dcdf661 --- /dev/null +++ b/ui_ncurses.c @@ -0,0 +1,257 @@ +/* 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 . + */ +#include "ui.h" +#include +#include + +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 */