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; +}
