ref: cea57785283e17b1a05909860d12e9a7dfe99600
author: mkf <mkf>
date: Tue Apr 4 17:41:24 EDT 2023
import
--- /dev/null
+++ b/m.c
@@ -1,0 +1,369 @@
+/*
+note that program isn't well tested on boardx != 6, boardy != 6
+*/
+#include <stdio.h>
+
+#define boardx 6
+#define boardy 6
+#define empty ' '
+
+char board[boardx * boardy];
+int pieces[2] = { (boardx / 2 - 1)* boardy, (boardx / 2 - 1) * boardy };
+char piece[2] = { '@', '#' };
+int player = 0;
+int direction = -1;
+
+typedef struct
+{
+ int x;
+ int y;
+} point_t;
+
+typedef struct
+{
+ point_t src;
+ point_t dst;
+} swap_t;
+
+int pindex(int, int);
+void setupboard(void);
+void showrules(void);
+void showboard(void);
+void showhelp(void);
+char check(void);
+
+int check_put(point_t);
+int check_move(point_t);
+int check_swap(swap_t);
+
+int put(point_t);
+int move(point_t);
+int swap(swap_t);
+
+typedef struct
+{
+ char act;
+ point_t pos1;
+ point_t pos2;
+} cmd_t;
+
+/* why y and x, and not x and y?
+ C does it as YX, doing it otherwise would make code
+ way too complex */
+int pindex(int y, int x)
+{
+ if(x < 0 || x > boardx || y < 0 || y > boardy)
+ {
+ fprintf(stderr, "pindex(%d, %d) out of range\n", x, y);
+ return -1;
+ }
+ return (x * boardy) + y;
+}
+
+
+void setupboard(void)
+{
+ for(int x = 0; x < boardx; x++)
+ {
+ for(int y = 0; y < boardy; y++)
+ {
+ if(x == 0)
+ board[pindex(x, y)] = piece[1];
+ else if(x == boardx - 1)
+ board[pindex(x, y)] = piece[0];
+ else
+ board[pindex(x, y)] = empty;
+ }
+ }
+}
+
+
+void showboard(void)
+{
+ printf("\n");
+ printf("free %c: %d, free %c: %d\n", piece[0], pieces[0], piece[1], pieces[1]);
+ for(int i = -1; i < boardx; i++)
+ {
+ if(i != -1) // makes top most sqaure ugly
+ printf(" %d |", i);
+ else
+ printf(" * |");
+ for(int j = 0; j < boardy; j++)
+ {
+ if(i == -1)
+ printf(" %d |", j);
+ else
+ printf(" %c |", board[pindex(i, j)]);
+ }
+ printf("\n");
+ }
+}
+
+void showrules(void)
+{
+ printf("The goal is make a 4 in a row, where\n"
+ "at least half (2) of them are other side.\n"
+ "commands:\n"
+ "h: show this help, b: show board, #: comment, NOP \n"
+ "pXY: put a piece on XY, you may only do it for your first two rows.\n"
+ "mXY: move the piece on XY one square forward.\n"
+ "sXYXY: swap first two pieces, only if they are adjecnet.\n");
+}
+
+void chplayer(void)
+{
+ player = !player;
+ direction *= -1;
+}
+
+cmd_t getcmd(void)
+{
+ char string[6];
+ point_t pos1, pos2;
+ cmd_t cmd;
+ printf("\n%c turn> ", piece[player]);
+ scanf("%s", string);
+ switch(string[0])
+ {
+ case 'm':
+ case 'p':
+ sscanf(&string[1], "%1d%1d", &pos1.x, &pos1.y);
+ cmd.pos1 = pos1;
+ break;
+
+ case 's':
+ sscanf(&string[1],"%1d%1d%1d%1d", &pos1.x, &pos1.y, &pos2.x, &pos2.y);
+ cmd.pos1 = pos1;
+ cmd.pos2 = pos2;
+ break;
+ }
+ cmd.act = string[0];
+ return cmd;
+}
+
+int proccmd(cmd_t cmd)
+{
+ switch(cmd.act)
+ {
+ case 'm':
+ {
+ if(pindex(cmd.pos1.x, cmd.pos1.y) == -1)
+ return -1;
+ return move(cmd.pos1);
+ }
+
+ case 's':
+ {
+ if(pindex(cmd.pos1.x, cmd.pos1.y) == -1
+ || pindex(cmd.pos2.x, cmd.pos2.y) == -1)
+ return -1;
+ swap_t s;
+ s.src = cmd.pos1;
+ s.dst = cmd.pos2;
+ return swap(s);
+ }
+
+ case 'p':
+ {
+ if(pindex(cmd.pos1.x, cmd.pos1.y) == -1)
+ return -1;
+ return put(cmd.pos1);
+ }
+
+ case 'b':
+ {
+ showboard();
+ break;
+ }
+
+ case 'h':
+ {
+ showrules();
+ break;
+ }
+ case '#':
+ {
+ break;
+ }
+ default:
+ {
+ fprintf(stderr, "unkown command.\n");
+ break;
+ }
+ }
+ return -1;
+}
+
+char check(void)
+{
+ for(int x = 0 ; x < boardx ; x++)
+ {
+ for(int y = 0 ; y < boardy - 3 ; y++)
+ {
+ if(board[pindex(x, y)] != empty)
+ {
+ // horzictal
+ if((board[pindex(x, y)] == piece[0] && x < (boardx / 2 + 1))
+ || (board[pindex(x, y)] == piece[1] && x >= (boardx / 2)))
+ if(board[pindex(x, y)] == board[pindex(x, y+1)]
+ && board[pindex(x, y)] == board[pindex(x, y+2)]
+ && board[pindex(x, y)] == board[pindex(x, y+3)])
+ {
+ printf("deb\n");
+ return board[pindex(x, y)];
+ }
+ // vertical
+ if((player == 0 && x < ( boardx / 2 + 1 ))
+ || (player == 1 && x >= ( boardx / 2 + 1)))
+ if(board[pindex(x, y)] == board[pindex(x - direction, y)]
+ && board[pindex(x, y)] == board[pindex(x - direction * 2, y)]
+ && board[pindex(x, y)] == board[pindex(x - direction * 3, y)])
+ return board[pindex(x, y)];
+
+ // diagonal rtl
+ if(y == 1 || y == 2)
+ if(board[pindex(x, y)] == board[pindex(x+1, y+1)]
+ && board[pindex(x, y)] == board[pindex(x+2, y+2)]
+ && board[pindex(x, y)] == board[pindex(x+3, y+3)])
+ return board[pindex(x, y)];
+
+ // diagonal ltr
+ if(y == 3 || y == 4)
+ if(board[pindex(x, y)] == board[pindex(x+1, y-1)]
+ && board[pindex(x, y)] == board[pindex(x+2, y-2)]
+ && board[pindex(x, y)] == board[pindex(x+3, y-3)])
+ return board[pindex(x, y)];
+ }
+ }
+ }
+ return empty;
+}
+
+int check_swap(swap_t swap)
+{
+ if((pindex(swap.src.x, swap.src.y) < 0)
+ || (pindex(swap.dst.x, swap.dst.y) < 0))
+ {
+ fprintf(stderr, "invalid input\n");
+ return -1;
+ }
+
+ if(swap.src.x - swap.dst.x > 1
+ || swap.src.x - swap.dst.x < -1
+ || swap.src.y - swap.dst.y > 1
+ || swap.src.y - swap.dst.y < -1)
+ {
+ fprintf(stderr, "src and dst aren't adjecent\n");
+ return -2;
+ }
+
+ if(board[pindex(swap.src.x, swap.src.y)] == empty
+ || board[pindex(swap.dst.x, swap.dst.y)] == empty)
+ {
+ fprintf(stderr, "src or dst is empty\n");
+ return -3;
+ }
+
+ if(board[pindex(swap.src.x, swap.src.y)]
+ == board[pindex(swap.dst.x, swap.dst.y)])
+ {
+ fprintf(stderr, "src and dst have the same piece\n");
+ return -4;
+ }
+
+ if(pindex(swap.src.x, swap.src.y)
+ == pindex(swap.dst.x, swap.dst.y))
+ {
+ fprintf(stderr, "src and dst are the same square\n");
+ return -5;
+ }
+
+ return 0;
+}
+
+int swap(swap_t swap)
+{
+ if(check_swap(swap) < 0)
+ return -1;
+ char temp = board[pindex(swap.src.x, swap.src.y)];
+ board[pindex(swap.src.x, swap.src.y)] = board[pindex(swap.dst.x, swap.dst.y)];
+ board[pindex(swap.dst.x, swap.dst.y)] = temp;
+ return 0;
+}
+
+int check_move(point_t point) // todo: add checks for last row
+{
+ if(pindex(point.x, point.y) == -1)
+ {
+ fprintf(stderr, "invalid input\n");
+ return -1;
+ }
+
+ if(board[pindex(point.x, point.y)] != piece[player])
+ {
+ fprintf(stderr, "src is not your piece\n");
+ return -2;
+ }
+
+ if(board[pindex(point.x + direction, point.y )] != empty)
+ {
+ fprintf(stderr, "dst is not empty\n");
+ return -3;
+ }
+ return 0;
+}
+
+int move(point_t point)
+{
+ if(check_move(point) < 0)
+ return -1;
+ board[pindex(point.x + direction, point.y)] = piece[player];
+ board[pindex(point.x, point.y)] = empty;
+ return 0;
+}
+
+int check_put(point_t point)
+{
+ if(pindex(point.x, point.y) == -1)
+ {
+ fprintf(stderr, "invalid input\n");
+ return -1;
+ }
+ if(board[pindex(point.x, point.y)] != empty)
+ {
+ fprintf(stderr, "dst is not empty\n");
+ return -2;
+ }
+ if((player == 0 && point.x < 4)
+ || (player == 1 && point.x > 1))
+ {
+ fprintf(stderr, "it's not on your first two rows\n");
+ return -3;
+ }
+ return 0;
+}
+
+int put(point_t point)
+{
+ if(check_put(point) < 0)
+ return -1;
+ board[pindex(point.x, point.y)] = piece[player];
+ pieces[player]--;
+ return 0;
+}
+
+int main(void)
+{
+ showrules();
+ setupboard();
+ showboard();
+ while(check() == empty)
+ {
+ if(proccmd(getcmd()) == 0)
+ {
+ chplayer();
+ showboard();
+ }
+ }
+ return 0;
+}