Hey guys.
I implemented an interesting game. I thought this game is cool and could be
fun
for OpenBSD users. I don't know what game will accept on OpenBSD. But I hope
this patch is interesting.
This patch is minimal and featureless. If this patch accepted, I will
improve it
and send more patchs.

Game is explained on following link:
https://en.wikipedia.org/wiki/Dots_and_Boxes

My game hosted on following Github repository and obsd branch:
https://github.com/alirezaarzehgar/dotgame

diff --git a/games/Makefile b/games/Makefile
index a80e4f273ec..3e1f35462e2 100644
--- a/games/Makefile
+++ b/games/Makefile
@@ -4,6 +4,6 @@ SUBDIR= adventure arithmetic atc backgammon banner
battlestar bcd boggle \
  bs caesar canfield cribbage factor fish fortune gomoku grdc hack \
  hangman hunt mille monop morse number phantasia pig pom ppt \
  primes quiz rain random robots sail snake tetris trek wargames \
- worm worms wump
+ worm worms wump dotgame

 .include <bsd.subdir.mk>
diff --git a/games/dotgame/Makefile b/games/dotgame/Makefile
new file mode 100644
index 00000000000..4686a7e0fc5
--- /dev/null
+++ b/games/dotgame/Makefile
@@ -0,0 +1,5 @@
+# $OpenBSD: Makefile,v 1.0 2022/12/12 22:41:05 Alireza Exp $
+PROG= dotgame
+MAN= dotgame.6
+
+.include <bsd.prog.mk>
diff --git a/games/dotgame/dotgame.6 b/games/dotgame/dotgame.6
new file mode 100644
index 00000000000..e9dd30cbd88
--- /dev/null
+++ b/games/dotgame/dotgame.6
@@ -0,0 +1,86 @@
+.\" $OpenBSD: dotgame.6,v 1.15 2022/12/12 17:45:15 Alireza Exp $
+.\"
+.\" Copyright (c) Alireza <[email protected]>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" The following requests are required for all man pages.
+.\"
+.Dd $Mdocdate$
+.Dt NAME 6
+.Os
+.Sh NAME
+.Nm dotgame
+.Nd dots and boxes game
+.Sh SYNOPSIS
+.Nm
+.Op Fl pf
+.Sh DESCRIPTION
+The
+.Nm
+is a pencil-and-paper game for two players (sometimes more).
+It was first published in the 19th century by French mathematician Édouard
Lucas,
+who called it la pipopipette. It has gone by many other names,
+including the dots and dashes, game of dots, dot to dot grid, boxes,
+and pigs in a pen.
+.Pp
+The game starts with an empty grid of dots.
+Usually two players take turns adding a single horizontal or vertical line
between two unjoined adjacent dots.
+A player who completes the fourth side of a 1×1 box earns one point and
takes another turn.
+A point is typically recorded by placing a mark that identifies the player
in the box,
+such as an initial.
+The game ends when no more lines can be placed.
+The winner is the player with the most points.
+The board may be of any size grid. When short on time,
+or to learn the game, a 2×2 board (3×3 dots) is suitable.
+A 5×5 board, on the other hand, is good for experts.
+.Pp
+.Fl p
+Enable professional mode (6×6 dots). Default is (4×4 dots).
+In
+.Nm
+mode specify size of square. Actually, size of square is (mode×mode).
+.Pp
+.Fl f
+Play with computer.
+.Pp
+.Ss How to play
+Players should enter 3 numbers on input for drawing a line.
+Example input is "D X Y". D is for direction. Vertical line or horizontal.
+X and Y is for coordination. For D, number should 0 or 1.
+0 is for horizontal and 1 is for vertical line.
+.Pp
+X and Y limitations is depend on line direction.
+.Pp
+For horizontal lines: 1 <= X <= mode-1 and 1 <= Y <= mode.
+.Pp
+For vertical lines: 1 <= X <= mode and 1 <= Y <= mode-1.
+.Sh EXAMPLES
+.Nm
+final result:
+ *--*--*--*--*--*
+ |A |B |B |B |B |
+ *--*--*--*--*--*
+ |B |A |B |B |A |
+ *--*--*--*--*--*
+ |A |A |A |A |A |
+ *--*--*--*--*--*
+ |B |A |A |B |B |
+ *--*--*--*--*--*
+ |B |A |A |A |B |
+ *--*--*--*--*--*
+.Pp
+ score(A): 13; score(B): 12;
+.Sh AUTHORS
+.An -nosplit
+.An Alireza Arzehgar Aq Mt [email protected]
diff --git a/games/dotgame/dotgame.c b/games/dotgame/dotgame.c
new file mode 100644
index 00000000000..2270dd16657
--- /dev/null
+++ b/games/dotgame/dotgame.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2022 Alireza <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <err.h>
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#define NORMAL_MODE     4
+#define PRO_MODE        6
+#define NPLAYERS        2
+#define I2C(I)          (I + 'A' - 1)
+
+int matr[PRO_MODE][PRO_MODE][3] = {0};
+enum {HOR, VER, WIN};
+
+char *colored(char *msg, int id)
+{
+    /* Max lenght for colored double dash or pipe */
+    static char text[20];
+    sprintf(text, "\033[%dm%s\033[0m", 30 + id, msg);
+    return text;
+}
+
+void print_matrix(int mode) {
+    char *line, *name;
+
+    for (int row = 0; row <= mode; row++) {
+        for (int col = 0; col <= mode; col++) {
+            line = colored("--", matr[row][col][HOR]);
+            printf("*%s", matr[row][col][HOR] ? line : "  ");
+        }
+        putchar('\n');
+
+        for (int col = 0; col <= mode; col++) {
+            line = colored("|", matr[row][col][VER]);
+            printf("%s%c ", matr[row][col][VER] ? line : " ",
+                            matr[row][col][WIN] ? I2C(matr[row][col][WIN])
: ' ');
+        }
+        putchar('\n');
+    }
+}
+
+int is_square(int row, int col)
+{
+    return matr[row][col][HOR] && matr[row][col][VER]   /* current point */
+            && matr[row][col+1][VER]    /* right point */
+            && matr[row+1][col][HOR]    /* down point */
+            && !matr[row][col][WIN];
+}
+
+int is_invalid_input(int mode, int direc, int row, int col)
+{
+    return (direc != HOR && direc != VER)
+            || (direc == VER && row > mode-1)
+            || (direc == HOR && col > mode-1)
+            || (row < 0 || row > mode)
+            || (col < 0 || col > mode)
+            || matr[row][col][direc] > 0;
+}
+
+int seeded_random(int max)
+{
+    struct timespec ts;
+    timespec_get(&ts, TIME_UTC);
+    srand(ts.tv_nsec + rand());
+    return rand() % max;
+}
+
+int check_sides(int row, int col,
+                    int *orow, int *ocol, int *odirec)
+{
+    int side = 0;
+
+    *orow = row;
+    *ocol = col;
+
+    if (matr[row][col][HOR])
+        side++;
+    else
+        *odirec = HOR;
+
+    if (matr[row][col][VER])
+        side++;
+    else
+        *odirec = VER;
+
+    if (matr[row][col + 1][VER]) {
+        side++;
+    } else {
+        *ocol = col + 1;
+        *odirec = VER;
+    }
+
+    if (matr[row + 1][col][HOR]) {
+        side++;
+    } else {
+        *orow = row + 1;
+        *odirec = HOR;
+    }
+
+    (*orow)++, (*ocol)++;
+    return side;
+}
+
+void fake_player(int mode, int *odirec, int *orow, int *ocol)
+{
+    for (int row = 0; row < mode; row++) {
+        for (int col = 0; col < mode; col++) {
+            if (check_sides(row, col, orow, ocol, odirec) == 3)
+                return;
+        }
+    }
+
+    *odirec = seeded_random(2);
+    *orow = seeded_random(mode + 2);
+    *ocol = seeded_random(mode + 2);
+}
+
+int main(int argc, char *const *argv)
+{
+    int direc, row, col, wins, retry = 0, player = 1, faker = 0, opt,
+        sumscore = 0, mode = NORMAL_MODE - 1, scores[NPLAYERS] = {0};
+    char *line;
+    size_t sline;
+
+    if (pledge("stdio", NULL) == -1)
+        err(1, "pledge");
+
+    while ((opt = getopt(argc, argv, "pf")) != -1)
+    {
+        switch (opt)
+        {
+        case 'p':
+            mode = PRO_MODE - 1;
+            break;
+
+        case 'f':
+            faker = 1;
+            break;
+
+        case '?':
+            fprintf(stderr, "Usage: %s\n"
+            "  -p\t\tEnable professional mode\n"
+            "  -f\t\tEnable fake player\n", argv[0]);
+            return -1;
+        }
+    }
+
+    for (;;) {
+        if (!retry && player != faker)
+            print_matrix(mode);
+
+        if (sumscore == mode * mode)
+            break;
+
+        if (player == faker) {
+            fake_player(mode, &direc, &row, &col);
+        } else {
+            line = NULL;
+            printf("Player %c turn.Enter coordinates:\n", I2C(player));
+            getline(&line, &sline, stdin);
+            sscanf(line, "%d%d%d", &direc, &row, &col);
+            if (feof(stdin))
+                return (0);
+        }
+
+        row--, col--;
+        if (is_invalid_input(mode, direc, row, col)) {
+            if (player != faker)
+                fprintf(stderr, "Invalid input. retry\n");
+            retry = 1;
+            continue;
+        }
+        retry = 0;
+        matr[row][col][direc] = player;
+
+        wins = 0;
+        if (is_square(row, col)) {
+            matr[row][col][WIN] = player;
+            wins++;
+        }
+        if (direc) {
+            if (col-- >= 0 && is_square(row, col)) {
+                matr[row][col][WIN] = player;
+                wins++;
+            }
+        } else {
+            if (row-- >= 0 && is_square(row, col)) {
+                matr[row][col][WIN] = player;
+                wins++;
+            }
+        }
+        scores[player-1] += wins;
+        sumscore += wins;
+
+        if (!wins && ++player > NPLAYERS)
+            player = 1;
+    }
+
+    for (int id = 0; id < NPLAYERS; id++)
+        printf("score(%c): %d; ", 'A' + id, scores[id]);
+    putchar('\n');
+    return 0;
+}

Reply via email to