stego.git

stego.c

espurr
/* stego - chess engine
 * Copyright (C) 2025 ArcNyxx <me@arcnyxx.net>
 * see LICENCE file for licensing information */

#include <ctype.h>

#include <curses.h>

#include "move.h"
#include "stego.h"

int
main(void)
{
	board_t board, *bd = &board;
	bd->king   = bd->eking   = 0b00010000;
	bd->queen  = bd->equeen  = 0b00001000;
	bd->rook   = bd->erook   = 0b10000001;
	bd->bishop = bd->ebishop = 0b00100100;
	bd->knight = bd->eknight = 0b01000010;
	bd->pawn   = bd->epawn   = 0b11111111;

	bd->epawn <<= 8, bd->pawn <<= 48;
	bd->king <<= 56, bd->queen <<= 56, bd->rook <<= 56;
	bd->bishop <<= 56, bd->knight <<= 56;

	bd->enpassant = 64;
	bd->wkcastle = bd->wqcastle = bd->bkcastle = bd->bqcastle = true;
	bd->white = true;

	initscr(); /* initialises curses */
	noecho(); /* no echo characters */
	nonl(); /* no output newline */
	raw(); /* raw input mode */
	curs_set(0); /* hide cursor */

	if (has_colors()) {
		start_color();
		init_pair(1, COLOR_WHITE, COLOR_BLACK); /* regular */
		init_pair(2, COLOR_BLACK, COLOR_WHITE); /* cursor */
	}

	int x = 0, y = 0;
	int cur = 60, sel = -1; /* start on white king */
	u64 possible;
	bool run = true, state = false;
	while (run) {
		if (state != bd->white) {
			for (int i = 0; i < 64; ++i)
				bd->moves[i] = 0;
			mv(bd);
			state = bd->white;
		}

		if (sel == -1)
			possible = bd->moves[cur];

		int newx, newy;
		getmaxyx(stdscr, newy, newx);
		newx = (newx - 15) / 2, newy = (newy - 8) / 2;
		if (newx != x || newy != y) {
			clear();
			x = newx, y = newy;
		}

		for (int i = 0; i < 64; ++i) {
			int map = possible & (1ULL << i) ?
					COLOR_PAIR(2) : COLOR_PAIR(1);
			if (i == cur || i == sel)
				map |= A_BOLD;

			char letter = '.';
			if ((1ULL << i) & (bd->king | bd->eking))
				letter = 'k';
			else if ((1ULL << i) & (bd->queen | bd->equeen))
				letter = 'q';
			else if ((1ULL << i) & (bd->rook | bd->erook))
				letter = 'r';
			else if ((1ULL << i) & (bd->bishop | bd->ebishop))
				letter = 'b';
			else if ((1ULL << i) & (bd->knight | bd->eknight))
				letter = 'n';
			else if ((1ULL << i) & (bd->pawn | bd->epawn))
				letter = 'p';

			u64 friend = bd->friend;
			if (!bd->white)
				friend = ~friend;
			if (letter != '.' && ((1ULL << i) & friend))
				letter = toupper(letter);

			mvaddch(y, x, letter | map);

			if (i % 8 == 7)
				++y, x -= 14;
			else
				x += 2;
		}

		switch (getch()) {
		default: break;
		case 'h': if (cur % 8 != 0) cur -= 1; break;
		case 'j': if (cur <= 55)    cur += 8; break;
		case 'k': if (cur >= 8)     cur -= 8; break;
		case 'l': if (cur % 8 != 7) cur += 1; break;
		case 'q': run = false; break;
		case ' ':
			/* no selection yet */
			if (sel == -1) {
				if (possible)      /* only select if has */
					sel = cur; /* available moves */
			/* selection made */
			} else if (possible & (1ULL << cur)) {
				/* make the move */
				mk(bd, sel, cur);
				sel = -1;
			} else {
				/* not a valid move */
				sel = -1;
			}
		}
	}

	endwin();
}