Refactored a bit

This commit is contained in:
AnnaSnoeijs 2025-06-06 21:31:59 +02:00
parent 99f5c6cd6e
commit 5379f50802
8 changed files with 534 additions and 449 deletions

View file

@ -17,460 +17,16 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ncurses.h>
#include <locale.h>
#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(