aboutsummaryrefslogtreecommitdiff
path: root/dab
diff options
context:
space:
mode:
authorB. Watson <yalhcru@gmail.com>2015-05-07 16:32:32 -0400
committerB. Watson <yalhcru@gmail.com>2015-05-07 16:32:32 -0400
commit013ac7742311556022304e8b30ca170d48b3a016 (patch)
tree53faa33e75991363f1a6dcc7edc83a66b70e6995 /dab
downloadbsd-games-extra-013ac7742311556022304e8b30ca170d48b3a016.tar.gz
initial commit
Diffstat (limited to 'dab')
-rw-r--r--dab/Makefile14
-rw-r--r--dab/algor.cc310
-rw-r--r--dab/algor.h76
-rw-r--r--dab/board.cc253
-rw-r--r--dab/board.h86
-rw-r--r--dab/box.cc150
-rw-r--r--dab/box.h93
-rw-r--r--dab/dab.6112
-rw-r--r--dab/defs.h43
-rw-r--r--dab/gamescreen.cc43
-rw-r--r--dab/gamescreen.h72
-rw-r--r--dab/human.cc149
-rw-r--r--dab/human.h53
-rw-r--r--dab/main.cc191
-rw-r--r--dab/player.cc91
-rw-r--r--dab/player.h70
-rw-r--r--dab/random.cc79
-rw-r--r--dab/random.h66
-rw-r--r--dab/test.cc50
-rw-r--r--dab/ttyscrn.cc233
-rw-r--r--dab/ttyscrn.h74
21 files changed, 2308 insertions, 0 deletions
diff --git a/dab/Makefile b/dab/Makefile
new file mode 100644
index 0000000..03491e3
--- /dev/null
+++ b/dab/Makefile
@@ -0,0 +1,14 @@
+# $NetBSD: Makefile,v 1.7 2010/02/03 15:34:38 roy Exp $
+
+DPADD+=${LIBCURSES} ${LIBTERMINFO} ${LIBM}
+LDADD+=-lcurses -lm
+
+# 20150209 bkw: hackery because slack's old pmake doesn't
+# support PROG_CXX.
+CC=c++
+PROG=dab
+MAN=dab.6
+SRCS=algor.cc board.cc main.cc human.cc box.cc player.cc gamescreen.cc \
+ ttyscrn.cc random.cc
+
+.include <bsd.prog.mk>
diff --git a/dab/algor.cc b/dab/algor.cc
new file mode 100644
index 0000000..86fc6e1
--- /dev/null
+++ b/dab/algor.cc
@@ -0,0 +1,310 @@
+/* $NetBSD: algor.cc,v 1.5 2012/02/29 23:39:53 joerg Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * algor.C: Computer algorithm
+ */
+#include "defs.h"
+RCSID("$NetBSD: algor.cc,v 1.5 2012/02/29 23:39:53 joerg Exp $")
+
+#include "algor.h"
+#include "board.h"
+#include "box.h"
+#include "random.h"
+
+ALGOR::ALGOR(const char c) : PLAYER(c)
+{
+#ifdef notyet
+ // Single Edges = (x + y) * 2
+ _edge1 = (_b.nx() * _b.ny()) * 2;
+ // Shared Edges = (x * (y - 1)) + ((x - 1) * y)
+ _edge2 = (_b.nx() * (_b.ny() - 1)) + ((_b.nx() - 1) * _b.ny());
+ // Maximum Edges filled before closure = x * y * 2
+ _maxedge = _b.nx() * _b.ny() * 2;
+#endif
+}
+
+// Find the first closure, i.e. a box that has 3 edges
+int ALGOR::find_closure(size_t& y, size_t& x, int& dir, BOARD& b)
+{
+ RANDOM rdy(b.ny()), rdx(b.nx());
+
+ for (y = rdy(); y < b.ny(); y = rdy()) {
+ rdx.clear();
+ for (x = rdx(); x < b.nx(); x = rdx()) {
+ BOX box(y, x, b);
+ if (box.count() == 3) {
+ for (dir = BOX::first; dir < BOX::last; dir++)
+ if (!box.isset(dir))
+ return 1;
+ b.abort("find_closure: 3 sided box[%zu,%zu] has no free sides",
+ y, x);
+ }
+ }
+ }
+ return 0;
+}
+
+#if 0
+size_t ALGOR::find_single()
+{
+ size_t ne;
+
+ // Find the number of single edges in use
+ for (size_t x = 0; x < b.nx(); x++) {
+ BOX tbox(0, x, b);
+ ne += tbox.isset(BOX::top);
+ BOX bbox(b.ny() - 1, x, b);
+ ne += bbox.isset(BOX::bottom);
+ }
+ for (size_t y = 0; y < _b.ny(); y++) {
+ BOX lbox(y, 0, b);
+ ne += lbox.isset(BOX::left);
+ BOX rbox(y,_b.nx() - 1, b);
+ ne += rbox.isset(BOX::right);
+ }
+ return ne;
+}
+#endif
+
+
+// Count a closure, by counting all boxes that we can close in the current
+// move
+size_t ALGOR::count_closure(size_t& y, size_t& x, int& dir, BOARD& b)
+{
+ size_t i = 0;
+ size_t tx, ty;
+ int tdir, mv;
+
+ while (find_closure(ty, tx, tdir, b)) {
+ if (i == 0) {
+ // Mark the beginning of the closure
+ x = tx;
+ y = ty;
+ dir = tdir;
+ }
+ if ((mv = b.domove(ty, tx, tdir, getWho())) == -1)
+ b.abort("count_closure: Invalid move (%zu, %zu, %d)", y, x, dir);
+ else
+ i += mv;
+ }
+ return i;
+}
+
+
+/*
+ * Find the largest closure, by closing all possible closures.
+ * return the number of boxes closed in the maximum closure,
+ * and the first box of the maximum closure in (x, y, dir)
+ */
+size_t ALGOR::find_max_closure(size_t& y, size_t& x, int& dir, const BOARD& b)
+{
+ BOARD nb(b);
+ int maxdir = -1;
+ size_t nbox, maxbox = 0;
+ size_t maxx = ~0, maxy = ~0;
+ size_t tx = 0, ty = 0; /* XXX: GCC */
+ int tdir = 0; /* XXX: GCC */
+
+ while ((nbox = count_closure(ty, tx, tdir, nb)) != 0)
+ if (nbox > maxbox) {
+ // This closure is better, update max
+ maxbox = nbox;
+ maxx = tx;
+ maxy = ty;
+ maxdir = tdir;
+ }
+
+ // Return the max found
+ y = maxy;
+ x = maxx;
+ dir = maxdir;
+ return maxbox;
+}
+
+
+// Find if a turn does not result in a capture on the given box
+// and return the direction if found.
+int ALGOR::try_good_turn(BOX& box, size_t y, size_t x, int& dir, BOARD& b)
+{
+ // Sanity check; we must have a good box
+ if (box.count() >= 2)
+ b.abort("try_good_turn: box[%zu,%zu] has more than 2 sides occupied",
+ y, x);
+
+ // Make sure we don't make a closure in an adjacent box.
+ // We use a random direction to randomize the game
+ RANDOM rd(BOX::last);
+ for (dir = rd(); dir < BOX::last; dir = rd())
+ if (!box.isset(dir)) {
+ size_t by = y + BOX::edges[dir].y;
+ size_t bx = x + BOX::edges[dir].x;
+ if (!b.bounds(by, bx))
+ return 1;
+
+ BOX nbox(by, bx, b);
+ if (nbox.count() < 2)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+// Try to find a turn that does not result in an opponent closure, and
+// return it in (x, y, dir); if not found return 0.
+int ALGOR::find_good_turn(size_t& y, size_t& x, int& dir, const BOARD& b)
+{
+ BOARD nb(b);
+ RANDOM rdy(b.ny()), rdx(b.nx());
+
+ for (y = rdy(); y < b.ny(); y = rdy()) {
+ rdx.clear();
+ for (x = rdx(); x < b.nx(); x = rdx()) {
+ BOX box(y, x, nb);
+ if (box.count() < 2 && try_good_turn(box, y, x, dir, nb))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+// On a box with 2 edges, return the first or the last free edge, depending
+// on the order specified
+int ALGOR::try_bad_turn(BOX& box, size_t& y, size_t& x, int& dir, BOARD& b,
+ int last)
+{
+ if (4 - box.count() <= last)
+ b.abort("try_bad_turn: Called at [%zu,%zu] for %d with %d",
+ y, x, last, box.count());
+ for (dir = BOX::first; dir < BOX::last; dir++)
+ if (!box.isset(dir)) {
+ if (!last)
+ return 1;
+ else
+ last--;
+ }
+ return 0;
+}
+
+// Find a box that has 2 edges and return the first free edge of that
+// box or the last free edge of that box
+int ALGOR::find_bad_turn(size_t& y, size_t& x, int& dir, BOARD& b, int last)
+{
+ RANDOM rdy(b.ny()), rdx(b.nx());
+ for (y = rdy(); y < b.ny(); y = rdy()) {
+ rdx.clear();
+ for (x = rdx(); x < b.nx(); x = rdx()) {
+ BOX box(y, x, b);
+ if ((4 - box.count()) > last &&
+ try_bad_turn(box, y, x, dir, b, last))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+size_t ALGOR::find_min_closure1(size_t& y, size_t& x, int& dir, const BOARD& b,
+ int last)
+{
+ BOARD nb(b);
+ int tdir, mindir = -1, mv;
+ // number of boxes per closure
+ size_t nbox, minbox = nb.nx() * nb.ny() + 1;
+ size_t tx, ty, minx = ~0, miny = ~0;
+ int xdir = 0; /* XXX: GCC */
+
+ while (find_bad_turn(ty, tx, tdir, nb, last)) {
+
+ // Play a bad move that would cause the opponent's closure
+ if ((mv = nb.domove(ty, tx, tdir, getWho())) != 0)
+ b.abort("find_min_closure1: Invalid move %d (%zu, %zu, %d)", mv,
+ ty, tx, tdir);
+
+ // Count the opponent's closure
+ if ((nbox = count_closure(y, x, xdir, nb)) == 0)
+ b.abort("find_min_closure1: no closure found");
+
+ if (nbox <= minbox) {
+ // This closure has fewer boxes
+ minbox = nbox;
+ minx = tx;
+ miny = ty;
+ mindir = tdir;
+ }
+ }
+
+ y = miny;
+ x = minx;
+ dir = mindir;
+ return minbox;
+}
+
+
+// Search for the move that makes the opponent close the least number of
+// boxes; returns 1 if a move found, 0 otherwise
+size_t ALGOR::find_min_closure(size_t& y, size_t& x, int& dir, const BOARD& b)
+{
+ size_t x1, y1;
+ int dir1;
+ size_t count = b.ny() * b.nx() + 1, count1;
+
+ for (size_t i = 0; i < 3; i++)
+ if (count > (count1 = find_min_closure1(y1, x1, dir1, b, i))) {
+ count = count1;
+ y = y1;
+ x = x1;
+ dir = dir1;
+ }
+
+ return count != b.ny() * b.nx() + 1;
+}
+
+// Return a move in (y, x, dir)
+void ALGOR::play(const BOARD& b, size_t& y, size_t& x, int& dir)
+{
+ // See if we can close the largest closure available
+ if (find_max_closure(y, x, dir, b))
+ return;
+
+#ifdef notyet
+ size_t sgl = find_single();
+ size_t dbl = find_double();
+#endif
+
+ // See if we can play an edge without giving the opponent a box
+ if (find_good_turn(y, x, dir, b))
+ return;
+
+ // Too bad, find the move that gives the opponent the fewer boxes
+ if (find_min_closure(y, x, dir, b))
+ return;
+}
diff --git a/dab/algor.h b/dab/algor.h
new file mode 100644
index 0000000..00b3c25
--- /dev/null
+++ b/dab/algor.h
@@ -0,0 +1,76 @@
+/* $NetBSD: algor.h,v 1.5 2012/06/15 10:51:25 joerg Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * algor.h: Computer's algorithm
+ */
+
+#ifndef _H_ALGOR
+#define _H_ALGOR
+
+#include "player.h"
+
+class BOARD;
+class BOX;
+
+class ALGOR : public PLAYER {
+ public:
+ ALGOR(const char c);
+ virtual ~ALGOR() {}
+ // Return a proposed move in (y, x, dir)
+ void play(const BOARD& b, size_t& y, size_t& x, int& dir);
+
+ private:
+ // Closure searches
+ int find_closure(size_t& y, size_t& x, int& dir, BOARD& b);
+ size_t find_max_closure(size_t& y, size_t& x, int& dir, const BOARD& b);
+ size_t find_min_closure1(size_t& y, size_t& x, int& dir, const BOARD& b,
+ int last);
+ size_t find_min_closure(size_t& y, size_t& x, int& dir, const BOARD& b);
+
+ // Move searches
+ int find_good_turn(size_t& y, size_t& x, int& dir, const BOARD& b);
+ int find_bad_turn(size_t& y, size_t& x, int& dir, BOARD& b, int last);
+
+ // Move Attempts
+ int try_bad_turn(BOX& box, size_t& y, size_t& x, int& dir, BOARD& b,
+ int last);
+ int try_good_turn(BOX& box, size_t y, size_t x, int& dir, BOARD& b);
+
+ // Utils
+ size_t count_closure(size_t& y, size_t& x, int& dir, BOARD& b);
+
+#ifdef notyet
+ size_t find_single(void);
+#endif
+};
+
+#endif
diff --git a/dab/board.cc b/dab/board.cc
new file mode 100644
index 0000000..b8340a0
--- /dev/null
+++ b/dab/board.cc
@@ -0,0 +1,253 @@
+/* $NetBSD: board.cc,v 1.4 2008/04/28 20:22:53 martin Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * board.C: Board manipulations
+ */
+#include "defs.h"
+RCSID("$NetBSD: board.cc,v 1.4 2008/04/28 20:22:53 martin Exp $")
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include "board.h"
+#include "gamescreen.h"
+#include "box.h"
+#include "player.h"
+
+BOARD::BOARD(size_t y, size_t x, GAMESCREEN* scrn) :
+ _ny(y),
+ _nx(x),
+ _scrn(scrn)
+{
+ _ty = 2 * _ny + 1;
+ _tx = 2 * _nx + 1;
+
+ _b = new int*[_ty];
+
+ for (y = 0; y < _ty; y++)
+ _b[y] = new int[_tx];
+
+ init();
+}
+
+BOARD::BOARD(const BOARD& b) :
+ _ty(b._ty),
+ _tx(b._tx),
+ _ny(b._ny),
+ _nx(b._nx),
+ _scrn(NULL)
+{
+ _b = new int*[_ty];
+
+ for (size_t y = 0; y < _ty; y++) {
+ _b[y] = new int[_tx];
+ static_cast<void>(memcpy(_b[y], b._b[y], _tx * sizeof(int)));
+ }
+}
+
+BOARD::~BOARD()
+{
+ size_t y;
+
+ for (y = 0; y < _ty; y++)
+ delete[] _b[y];
+
+ delete[] _b;
+}
+
+// Clear all boxes and reset state for a new game
+void BOARD::init(void)
+{
+ size_t x, y;
+
+ for (y = 0; y < _ny; y++)
+ for (x = 0; x < _nx; x++) {
+ BOX box(y, x, *this);
+ box.reset();
+ }
+}
+
+/*
+ * Make a move for player with initial 'c', adding an edge at box(x, y)
+ * and the specified direction.
+ * returns:
+ * -1: Invalid move
+ * n: Number of closures n E [0..2]
+ */
+int BOARD::domove(size_t y, size_t x, int dir, char c)
+{
+ int closed = 0;
+
+ // Check if out of bounds
+ if (!bounds(y, x))
+ return -1;
+
+ BOX box1(y, x, *this);
+
+ // Check if the edge is already there
+ if (box1.isset(dir))
+ return -1;
+
+ box1.set(dir);
+
+ if (box1.count() == 4) {
+ // New box; name it and count it
+ box1.name() = c;
+ closed++;
+ }
+
+ box1.paint();
+
+ // Check other box
+ x += BOX::edges[dir].x;
+ y += BOX::edges[dir].y;
+
+ if (bounds(y, x)) {
+ BOX box2(y, x, *this);
+ if (box2.count() == 4) {
+ box2.name() = c;
+ box2.paint();
+ closed++;
+ }
+ }
+ return closed;
+}
+
+// Return true if the board is full
+int BOARD::full(void) const
+{
+ for (size_t y = 0; y < _ny; y++)
+ for (size_t x = 0; x < _nx; x++) {
+ BOX box(y, x, const_cast<BOARD&>(*this));
+ if (box.count() != 4)
+ return 0;
+ }
+ return 1;
+}
+
+// Return if the coordinates are within bounds; we don't check for < 0,
+// since size_t is unsigned
+int BOARD::bounds(size_t y, size_t x) const
+{
+ return x < _nx && y < _ny;
+}
+
+// Paint all boxes, effectively redrawing the board
+void BOARD::paint(void) const
+{
+ for (size_t y = 0; y < _ny; y++)
+ for (size_t x = 0; x < _nx; x++) {
+ BOX box(y, x, const_cast<BOARD&>(*this));
+ box.paint();
+ }
+}
+
+// Clear the screen
+void BOARD::clean(void) const
+{
+ if (!_scrn)
+ return;
+ _scrn->clean();
+}
+
+// Move cursor to x, y
+void BOARD::setpos(size_t y, size_t x) const
+{
+ if (!_scrn)
+ return;
+ _scrn->moveto(y, x);
+ _scrn->redraw();
+}
+
+// Return character indicating move
+int BOARD::getmove(void) const
+{
+ if (!_scrn)
+ return 'q';
+ _scrn->redraw();
+ return _scrn->getinput();
+}
+
+// Ring the bell
+void BOARD::bell(void) const
+{
+ if (!_scrn)
+ return;
+ _scrn->bell();
+}
+
+// Post the score in the current game for player i
+void BOARD::score(size_t i, const PLAYER& p)
+{
+ if (_scrn == NULL)
+ return;
+ _scrn->score(i, p);
+}
+
+// Post the number of games won for player i
+void BOARD::games(size_t i, const PLAYER& p)
+{
+ if (_scrn == NULL)
+ return;
+ _scrn->games(i, p);
+}
+
+// Post the total score for player i
+void BOARD::total(size_t i, const PLAYER& p)
+{
+ if (_scrn == NULL)
+ return;
+ _scrn->total(i, p);
+}
+
+// Post the total score for player i
+void BOARD::ties(const PLAYER& p)
+{
+ if (_scrn == NULL)
+ return;
+ _scrn->ties(p);
+}
+
+// Internal algorithm error; post and abort
+void BOARD::abort(const char* s, ...) const
+{
+ for (size_t i = 0; i < _ny; i++)
+ fprintf(stderr, "\n");
+
+ va_list ap;
+ fprintf(stderr, "Algorithm internal error: ");
+ va_start(ap, s);
+ vfprintf(stderr, s, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ ::abort();
+}
diff --git a/dab/board.h b/dab/board.h
new file mode 100644
index 0000000..67dc3e0
--- /dev/null
+++ b/dab/board.h
@@ -0,0 +1,86 @@
+/* $NetBSD: board.h,v 1.4 2012/02/29 23:39:53 joerg Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * board.h: Board functions
+ */
+
+#ifndef _H_BOARD
+#define _H_BOARD
+
+#include <stdlib.h>
+
+class GAMESCREEN;
+class PLAYER;
+
+class BOARD {
+ public:
+ // Constructors and destructor
+ BOARD(size_t y, size_t x, GAMESCREEN* scrn);// For the main screen
+ BOARD(const BOARD& b); // For scratch screens
+ ~BOARD();
+
+ // member access
+ size_t nx(void) const { return _nx; }
+ size_t ny(void) const { return _ny; }
+ size_t tx(void) const { return _tx; }
+ size_t ty(void) const { return _ty; }
+ GAMESCREEN* getScrn(void) const { return _scrn; }
+ int& data(size_t y, size_t x) { return _b[y][x]; }
+
+ // Computing
+ int domove(size_t y, size_t x, int dir, char c); // Play move
+ void init(void); // Initialize a new game
+ int full(void) const; // True if no more moves
+ int bounds(size_t y, size_t x) const; // True if in bounds
+
+ // Screen updates
+ void paint(void) const; // Redraw screen
+ void clean(void) const; // Clear screen
+ void setpos(size_t y, size_t x) const; // move cursor to pos
+ int getmove(void) const; // Return move
+ void bell(void) const; // Beep!
+ void score(size_t i, const PLAYER& p); // Post score
+ void games(size_t i, const PLAYER& p); // Post games
+ void total(size_t i, const PLAYER& p); // Post totals
+ void ties(const PLAYER& p); // Post ties
+ __printflike(2, 3) __dead
+ void abort(const char *s, ...) const; // Algorithm error
+
+
+ private:
+ size_t _ty, _tx; // number of symbols in x and y dimension
+ size_t _ny, _nx; // number of boxes in the x and y dimension
+ int** _b; // board array of symbols
+ GAMESCREEN* _scrn; // screen access, if we have one
+};
+
+#endif
diff --git a/dab/box.cc b/dab/box.cc
new file mode 100644
index 0000000..1a00c1d
--- /dev/null
+++ b/dab/box.cc
@@ -0,0 +1,150 @@
+/* $NetBSD: box.cc,v 1.3 2008/04/28 20:22:53 martin Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * box.C: Box computations
+ */
+#include "defs.h"
+RCSID("$NetBSD: box.cc,v 1.3 2008/04/28 20:22:53 martin Exp $")
+
+#include "box.h"
+#include "board.h"
+#include "gamescreen.h"
+#include <curses.h>
+
+const POINT BOX::edges[BOX::last] =
+ { { 0, -1 }, { 0, 1 }, { -1, 0 }, { 1, 0 } };
+const POINT BOX::corners[BOX::last] =
+ { { -1, -1 }, { -1, 1 }, { 1, -1 }, { 1, 1 } };
+const int BOX::syms[BOX::last] =
+ { GAMESCREEN::GS_HLINE, GAMESCREEN::GS_HLINE,
+ GAMESCREEN::GS_VLINE, GAMESCREEN::GS_VLINE };
+
+BOX::BOX(size_t py, size_t px, BOARD& b) :
+ _b(b)
+{
+ _centery = py * 2 + 1;
+ _centerx = px * 2 + 1;
+}
+
+void BOX::addcorner(size_t y, size_t x)
+{
+ char sym;
+ _b.getScrn()->moveto(y, x);
+ if (x == 0) {
+ if (y == 0)
+ sym = GAMESCREEN::GS_ULCORNER;
+ else if (y == _b.ty() - 1)
+ sym = GAMESCREEN::GS_LLCORNER;
+ else
+ sym = GAMESCREEN::GS_LTEE;
+ } else if (x == _b.tx() - 1) {
+ if (y == 0)
+ sym = GAMESCREEN::GS_URCORNER;
+ else if (y == _b.ty() - 1)
+ sym = GAMESCREEN::GS_LRCORNER;
+ else
+ sym = GAMESCREEN::GS_RTEE;
+ } else if (y == 0)
+ sym = GAMESCREEN::GS_TTEE;
+ else if (y == _b.ty() - 1)
+ sym = GAMESCREEN::GS_BTEE;
+ else
+ sym = GAMESCREEN::GS_PLUS;
+
+ _b.getScrn()->addedge(sym);
+}
+
+// Paint a box
+void BOX::paint(void)
+{
+ int e;
+ if (_b.getScrn() == NULL)
+ return;
+
+ _b.getScrn()->moveto(_centery, _centerx);
+ _b.getScrn()->addsym(name());
+
+ for (e = BOX::first; e < BOX::last; e++) {
+ addcorner(_centery + corners[e].y, _centerx + corners[e].x);
+ _b.getScrn()->moveto(_centery + edges[e].y, _centerx + edges[e].x);
+ _b.getScrn()->addedge(edge(static_cast<EDGE>(e)));
+ }
+ _b.getScrn()->redraw();
+}
+
+// Return the name
+int& BOX::name(void)
+{
+ return _b.data(_centery, _centerx);
+}
+
+// Set an edge
+void BOX::set(int e)
+{
+ _b.data(_centery + edges[e].y, _centerx + edges[e].x) = syms[e];
+}
+
+// Clear an edge
+void BOX::clr(int e)
+{
+ _b.data(_centery + edges[e].y, _centerx + edges[e].x) = ' ';
+}
+
+// Test an edge
+int BOX::isset(int e) const
+{
+ return _b.data(_centery + edges[e].y, _centerx + edges[e].x) != ' ';
+}
+
+// Return the edge
+int& BOX::edge(int e)
+{
+ return _b.data(_centery + edges[e].y, _centerx + edges[e].x);
+}
+
+// Count the number of edges set in the box
+int BOX::count(void) const
+{
+ int cnt = 0;
+
+ for (int e = BOX::first; e < BOX::last; e++)
+ cnt += isset(static_cast<EDGE>(e));
+ return cnt;
+}
+
+// Clear the box
+void BOX::reset(void)
+{
+ for (int e = BOX::first; e < BOX::last; e++)
+ clr(static_cast<EDGE>(e));
+ name() = ' ';
+}
diff --git a/dab/box.h b/dab/box.h
new file mode 100644
index 0000000..fd13bde
--- /dev/null
+++ b/dab/box.h
@@ -0,0 +1,93 @@
+/* $NetBSD: box.h,v 1.2 2008/04/28 20:22:53 martin Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * box.C: Single box utilities; A box is an entity with four edges, four
+ * corners, and a center that maps directly to a board
+ */
+
+#ifndef _H_BOX
+#define _H_BOX
+
+#include <stdlib.h>
+
+class BOARD;
+
+class POINT {
+ public:
+ int x;
+ int y;
+};
+
+class BOX {
+ public:
+ enum EDGE {
+ first = 0,
+ top = 0,
+ bottom = 1,
+ left = 2,
+ right = 3,
+ last = 4,
+ };
+
+ BOX(size_t py, size_t px, BOARD& b);
+
+ void reset(void); // Clear a box
+ void paint(void); // Paint a box
+
+ // Member access
+ int& name(void);
+ int& edge(int e);
+
+ // Edge maniputations
+ void set(int e);
+ void clr(int e);
+ int isset(int e) const;
+
+ int count(void) const; // Count the number of edges in use
+
+ // Useful constants
+ // Relative coordinates of the edges from the center of the box.
+ static const POINT edges[BOX::last];
+ // Relative coordinates of the corners from the center of the box.
+ static const POINT corners[BOX::last];
+ // Character symbols of the four edges
+ static const int syms[BOX::last];
+
+ private:
+ void addcorner(size_t y, size_t x); // add a corner character
+
+ size_t _centerx; // Coordinates of the center in board units
+ size_t _centery;
+ BOARD& _b; // The board we refer to
+};
+
+#endif
diff --git a/dab/dab.6 b/dab/dab.6
new file mode 100644
index 0000000..039c79a
--- /dev/null
+++ b/dab/dab.6
@@ -0,0 +1,112 @@
+.\" $NetBSD: dab.6,v 1.6 2012/10/06 19:39:51 christos Exp $
+.\"
+.\" Copyright (c) 2003 Thomas Klausner.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd October 7, 2012
+.Dt DAB 6
+.Os
+.Sh NAME
+.Nm dab
+.Nd Dots and Boxes game
+.Sh SYNOPSIS
+.Nm
+.Op Fl aw
+.Op Fl n Ar ngames
+.Op Fl p Ao Ar c|h Ac Ns Ao Ar c|h Ac
+.Op Ar xdim Oo Ar ydim Oc
+.Sh DESCRIPTION
+.Nm
+is a game where each player tries to complete the most
+boxes.
+A turn consists of putting one border of a box; the player
+setting the fourth and final border of a box gets the
+point for the box and has another turn.
+.Pp
+The keys used are the vi keys:
+.Ic k
+for up,
+.Ic j
+for down,
+.Ic h
+for left, and
+.Ic l
+for right.
+To switch between even and odd rows, use one of the following
+keys:
+.Ic u
+.Pq diagonal right up ,
+.Ic y
+.Pq diagonal left up ,
+.Ic b
+.Pq diagonal left down ,
+.Ic n
+.Pq diagonal right down ;
+.Aq Ic space
+sets a new border,
+.Ic CTRL-L
+and
+.Ic CTRL-R
+redraw the screen, and
+.Ic q
+quits the game.
+.Pp
+Support options are:
+.Bl -tag -width XXnXngamesXXXXX
+.It Fl a
+Don't use the alternate character set.
+.It Fl n Ar ngames
+.Ar ngames
+games will be played.
+.Pq Especially useful in Fl p Ar cc No mode.
+.It Fl p Ao Ar c|h Ac Ns Ao Ar c|h Ac
+Select which of the two players is a human
+or a computer.
+The first argument is the first player;
+.Ic c
+stands for computer and
+.Ic h
+for human.
+.It Fl w
+Wait for a character press between games.
+.El
+.Pp
+.Ar xdim
+and
+.Ar ydim
+define the size of the board in the x and y
+dimensions.
+If the dimensions specified are
+.Dv 0
+then the maximum dimensions for the size of the screen are
+used.
+.Sh SEE ALSO
+.Rs
+.%A Elwyn R. Berlekamp
+.%T The Dots and Boxes Game: Sophisticated Child's Play
+.%D 2000
+.%I A K Peters
+.%U http://www.akpeters.com/book.asp?bID=111
+.Re
+.Sh AUTHORS
+.An Christos Zoulas
+.Aq christos@NetBSD.org
diff --git a/dab/defs.h b/dab/defs.h
new file mode 100644
index 0000000..23ebbe5
--- /dev/null
+++ b/dab/defs.h
@@ -0,0 +1,43 @@
+/* $NetBSD: defs.h,v 1.3 2011/05/23 23:06:41 joerg Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * defs.h: Macro defines
+ */
+
+#ifndef _H_DEFS
+#define _H_DEFS
+
+#include <sys/cdefs.h>
+
+#define RCSID(id) __RCSID(id);
+
+#endif
diff --git a/dab/gamescreen.cc b/dab/gamescreen.cc
new file mode 100644
index 0000000..a86ac71
--- /dev/null
+++ b/dab/gamescreen.cc
@@ -0,0 +1,43 @@
+/* $NetBSD: gamescreen.cc,v 1.2 2008/04/28 20:22:53 martin Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * gamescreen.C: Common screen functions
+ */
+#include "defs.h"
+RCSID("$NetBSD: gamescreen.cc,v 1.2 2008/04/28 20:22:53 martin Exp $")
+
+#include "gamescreen.h"
+
+// Nothing to do
+GAMESCREEN::~GAMESCREEN()
+{
+}
diff --git a/dab/gamescreen.h b/dab/gamescreen.h
new file mode 100644
index 0000000..c52c85b
--- /dev/null
+++ b/dab/gamescreen.h
@@ -0,0 +1,72 @@
+/* $NetBSD: gamescreen.h,v 1.3 2010/12/08 17:08:07 joerg Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * screen.h: Screen base class
+ */
+
+#ifndef _H_GAMESCREEN
+#define _H_GAMESCREEN
+
+#include <stdlib.h>
+
+class PLAYER;
+
+class GAMESCREEN {
+ public:
+ enum EDGE {
+ GS_HLINE,
+ GS_VLINE,
+ GS_ULCORNER,
+ GS_URCORNER,
+ GS_LLCORNER,
+ GS_LRCORNER,
+ GS_LTEE,
+ GS_RTEE,
+ GS_TTEE,
+ GS_BTEE,
+ GS_PLUS
+ };
+ virtual ~GAMESCREEN();
+ virtual void clean(void) = 0; // Clear screen
+ virtual void moveto(size_t y, size_t x) = 0; // Move to x, y
+ virtual void addsym(const int sym) = 0; // Add character symbol
+ virtual void addedge(const int sym) = 0; // Add character symbol
+ virtual void redraw(void) = 0; // Refresh
+ virtual int getinput(void) = 0; // Get user input
+ virtual void bell(void) = 0; // Beep
+ virtual void score(size_t l, const PLAYER& p) = 0; // Post current score
+ virtual void games(size_t l, const PLAYER& p) = 0; // Post games won
+ virtual void total(size_t l, const PLAYER& p) = 0; // Post total score
+ virtual void ties(const PLAYER& p) = 0; // Post tie games
+};
+
+#endif
diff --git a/dab/human.cc b/dab/human.cc
new file mode 100644
index 0000000..1c3e3e1
--- /dev/null
+++ b/dab/human.cc
@@ -0,0 +1,149 @@
+/* $NetBSD: human.cc,v 1.3 2008/04/28 20:22:54 martin Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * human.C: Human interface for dots, using rogue-like keys.
+ */
+#include "defs.h"
+RCSID("$NetBSD: human.cc,v 1.3 2008/04/28 20:22:54 martin Exp $")
+
+#include "human.h"
+#include "board.h"
+#include "box.h"
+#include "ttyscrn.h"
+
+#define CONTROL(a) ((a) & 037)
+
+extern GAMESCREEN *sc;
+
+HUMAN::HUMAN(const char c) :
+ PLAYER(c),
+ _curx(0),
+ _cury(1)
+{
+}
+
+void HUMAN::play(const BOARD& b, size_t& y, size_t& x, int& dir)
+{
+ int mv;
+ b.setpos(_cury, _curx);
+
+ for (;;) {
+ switch (mv = b.getmove()) {
+ case 'h': case 'H':
+ _curx -= 2;
+ break;
+
+ case 'l': case 'L':
+ _curx += 2;
+ break;
+
+ case 'k': case 'K':
+ _cury -= 2;
+ break;
+
+ case 'j': case 'J':
+ _cury += 2;
+ break;
+
+ case 'u': case 'U':
+ _curx += 1;
+ _cury -= 1;
+ break;
+
+ case 'y': case 'Y':
+ _curx -= 1;
+ _cury -= 1;
+ break;
+
+ case 'b': case 'B':
+ _curx -= 1;
+ _cury += 1;
+ break;
+
+ case 'n': case 'N':
+ _curx += 1;
+ _cury += 1;
+ break;
+
+ case 'q': case 'Q':
+ // Cleanup
+ delete sc;
+ exit(0);
+
+ case CONTROL('L'): case CONTROL('R'):
+ b.clean();
+ b.paint();
+ break;
+
+ case ' ':
+ {
+ x = _curx / 2;
+ y = _cury / 2;
+
+ if (_cury & 1) {
+ if (_curx == 0)
+ dir = BOX::left;
+ else {
+ x--;
+ dir = BOX::right;
+ }
+ }
+
+ if (_curx & 1) {
+ if (_cury == 0)
+ dir = BOX::top;
+ else {
+ y--;
+ dir = BOX::bottom;
+ }
+ }
+ }
+ return;
+
+ default:
+ break;
+ }
+
+ // We add 2 before the comparison to avoid underflow
+ if ((2 + _curx) - (_curx & 1) < 2)
+ _curx = (b.nx() * 2) + (_curx & 1);
+ if (_curx >= (b.nx() * 2) + 1)
+ _curx = (_curx & 1);
+
+ if ((2 + _cury) - (_cury & 1) < 2)
+ _cury = (b.ny() * 2) + (_cury & 1);
+ if (_cury >= (b.ny() * 2) + 1)
+ _cury = (_cury & 1);
+
+ b.setpos(_cury, _curx);
+ }
+}
diff --git a/dab/human.h b/dab/human.h
new file mode 100644
index 0000000..5d51a50
--- /dev/null
+++ b/dab/human.h
@@ -0,0 +1,53 @@
+/* $NetBSD: human.h,v 1.3 2008/04/28 20:22:54 martin Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * human.h: Human input interface
+ */
+
+#ifndef _H_HUMAN
+#define _H_HUMAN
+#include <stdlib.h>
+#include "player.h"
+
+class BOARD;
+
+class HUMAN : public PLAYER {
+ public:
+ HUMAN(const char c);
+ virtual ~HUMAN() {}
+ // Return move in y, x, and dir
+ void play(const BOARD& b, size_t& y, size_t& x, int& dir);
+ private:
+ size_t _curx, _cury; // Current cursor position
+};
+
+#endif
diff --git a/dab/main.cc b/dab/main.cc
new file mode 100644
index 0000000..49a8850
--- /dev/null
+++ b/dab/main.cc
@@ -0,0 +1,191 @@
+/* $NetBSD: main.cc,v 1.6 2012/10/06 19:39:51 christos Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * main.C: Main dots program
+ */
+#include "defs.h"
+RCSID("$NetBSD: main.cc,v 1.6 2012/10/06 19:39:51 christos Exp $")
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include "algor.h"
+#include "board.h"
+#include "human.h"
+#include "ttyscrn.h"
+
+GAMESCREEN *sc;
+
+// Print the command line usage
+static void usage(char* pname)
+{
+ char* p = strrchr(pname, '/');
+ if (p)
+ p++;
+ else
+ p = pname;
+ (void)::fprintf(stderr,
+ "Usage: %s [-w] [-p <c|h><c|h>] [-n <ngames>] [<ydim> [<xdim>]]\n", p);
+}
+
+// Play a single game
+static void play(BOARD& b, PLAYER* p[2])
+{
+ // Initialize
+ b.init();
+ p[0]->init();
+ p[1]->init();
+ b.paint();
+
+ // Alternate turns between players, scoring each turn
+ for (size_t i = 0;; i = (i + 1) & 1) {
+ b.score(i, *p[i]);
+ if (!p[i]->domove(b)) {
+ // No more moves, game over
+ break;
+ }
+ b.score(i, *p[i]);
+ }
+
+ // Find who won
+ p[0]->wl(p[1]->getScore());
+ p[1]->wl(p[0]->getScore());
+
+ // Post scores
+ b.score(0, *p[0]);
+ b.score(1, *p[1]);
+
+ // Post totals
+ b.total(0, *p[0]);
+ b.total(1, *p[1]);
+
+ // Post games
+ b.games(0, *p[0]);
+ b.games(1, *p[1]);
+
+ // Post ties
+ b.ties(*p[0]);
+}
+
+int main(int argc, char** argv)
+{
+ size_t ny, nx, nn = 1, wt = 0;
+ const char* nc = "ch";
+ int c;
+ int acs = 1;
+
+ while ((c = getopt(argc, argv, "awp:n:")) != -1)
+ switch (c) {
+ case 'a':
+ acs = 0;
+ break;
+ case 'w':
+ wt++;
+ break;
+
+ case 'p':
+ nc = optarg;
+ break;
+
+ case 'n':
+ nn = atoi(optarg);
+ break;
+
+ default:
+ usage(argv[0]);
+ return 1;
+ }
+
+ // Get the size of the board if specified
+ switch (argc - optind) {
+ case 0:
+ ny = nx = 3;
+ break;
+
+ case 1:
+ ny = nx = atoi(argv[optind]);
+ break;
+
+ case 2:
+ nx = atoi(argv[optind]);
+ ny = atoi(argv[optind+1]);
+ break;
+
+ default:
+ usage(argv[0]);
+ return 1;
+ }
+
+
+ PLAYER* p[2];
+
+ // Allocate players
+ for (size_t i = 0; i < 2; i++) {
+ char n = nc[1] == nc[0] ? i + '0' : nc[i];
+ switch (nc[i]) {
+ case 'c':
+ p[i] = new ALGOR(n);
+ break;
+
+ case 'h':
+ p[i] = new HUMAN(n);
+ break;
+
+ default:
+ usage(argv[0]);
+ return 1;
+ }
+ }
+
+ sc = TTYSCRN::create(acs, &ny, &nx);
+ if (sc == NULL)
+ ::errx(1, "Dimensions too large for current screen.");
+
+ BOARD b(ny, nx, sc);
+
+ // Play games
+ while (nn--) {
+ play(b, p);
+ if (wt)
+ b.getmove();
+ }
+
+ if (wt == 0)
+ b.getmove();
+ // Cleanup
+ delete sc;
+ delete p[0];
+ delete p[1];
+ return 0;
+}
diff --git a/dab/player.cc b/dab/player.cc
new file mode 100644
index 0000000..f7fd3d3
--- /dev/null
+++ b/dab/player.cc
@@ -0,0 +1,91 @@
+/* $NetBSD: player.cc,v 1.2 2008/04/28 20:22:54 martin Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * player.C: Player base class
+ */
+
+#include "defs.h"
+RCSID("$NetBSD: player.cc,v 1.2 2008/04/28 20:22:54 martin Exp $")
+
+#include "board.h"
+#include "player.h"
+
+PLAYER::PLAYER(char who) :
+ _who(who),
+ _score(0),
+ _total(0),
+ _games(0),
+ _ties(0)
+{
+}
+
+void PLAYER::init(void)
+{
+ _score = 0;
+}
+
+void PLAYER::wl(size_t sc)
+{
+ _total += _score;
+ _games += sc < _score;
+ _ties += sc == _score;
+}
+
+int PLAYER::domove(BOARD& b)
+{
+ size_t y, x;
+ int dir;
+ int score;
+
+ for (;;) {
+ if (b.full())
+ return 0;
+
+ play(b, y, x, dir);
+
+ switch (score = b.domove(y, x, dir, _who)) {
+ case 0:
+ // No closure
+ return 1;
+
+ case -1:
+ // Not a valid move
+ b.bell();
+ break;
+
+ default:
+ // Closure, play again
+ _score += score;
+ break;
+ }
+ }
+}
diff --git a/dab/player.h b/dab/player.h
new file mode 100644
index 0000000..fe61b67
--- /dev/null
+++ b/dab/player.h
@@ -0,0 +1,70 @@
+/* $NetBSD: player.h,v 1.3 2008/04/28 20:22:54 martin Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * player.h: Player base class
+ */
+#ifndef _H_PLAYER
+#define _H_PLAYER
+
+class BOARD;
+
+#include <stdlib.h>
+
+class PLAYER {
+ public:
+ PLAYER(char who);
+ virtual ~PLAYER() {}
+ virtual void play(const BOARD& b, size_t& y, size_t& x, int& dir) = 0;
+
+ // Helper functions
+ void init(void);
+ int domove(BOARD& b);
+
+ // Member access
+ char getWho(void) const { return _who; }
+
+ // Display
+ size_t getScore(void) const { return _score; }
+ size_t getTotal(void) const { return _total; }
+ size_t getGames(void) const { return _games; }
+ size_t getTies(void) const { return _ties; }
+ void wl(size_t sc);
+
+ private:
+ char _who;
+ size_t _score;
+ size_t _total;
+ size_t _games;
+ size_t _ties;
+};
+
+#endif
diff --git a/dab/random.cc b/dab/random.cc
new file mode 100644
index 0000000..2204c45
--- /dev/null
+++ b/dab/random.cc
@@ -0,0 +1,79 @@
+/* $NetBSD: random.cc,v 1.3 2008/04/28 20:22:54 martin Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * random.C: Randomizer for the dots program
+ */
+
+#include "defs.h"
+RCSID("$NetBSD: random.cc,v 1.3 2008/04/28 20:22:54 martin Exp $")
+
+#include <time.h>
+#include <string.h>
+#include "random.h"
+
+RANDOM::RANDOM(size_t ns) :
+ _bs(ns)
+{
+ _bm = new char[(_bs >> 3) + 1];
+ clear();
+}
+
+RANDOM::~RANDOM()
+{
+ delete[] _bm;
+}
+
+// Reinitialize
+void RANDOM::clear(void)
+{
+ _nv = 0;
+ ::srand48(::time(NULL));
+ (void) ::memset(_bm, 0, (_bs >> 3) + 1);
+}
+
+// Return the next random value
+size_t RANDOM::operator() (void)
+{
+ // No more values
+ if (_nv == _bs)
+ return _bs;
+
+ for (;;) {
+ size_t r = ::lrand48();
+ size_t z = r % _bs;
+ if (!isset(z)) {
+ set(z);
+ _nv++;
+ return z;
+ }
+ }
+}
diff --git a/dab/random.h b/dab/random.h
new file mode 100644
index 0000000..86b24c6
--- /dev/null
+++ b/dab/random.h
@@ -0,0 +1,66 @@
+/* $NetBSD: random.h,v 1.3 2008/04/28 20:22:54 martin Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * random.h: Randomizer; returns a random sequence of values from [0..fx)
+ * returning each value exactly once. After fx calls it returns fx.
+ */
+
+#ifndef _H_RANDOM
+#define _H_RANDOM
+
+#include <stdlib.h>
+
+class RANDOM {
+ public:
+ // Constructor and destructor
+ RANDOM(size_t fx);
+ ~RANDOM();
+
+ size_t operator () (void); // Next random
+ void clear(void); // Reset
+
+ private:
+
+ int isset(size_t z) {
+ return (_bm[z >> 3] & (1 << (z & 7))) != 0;
+ }
+
+ void set(size_t z) {
+ _bm[z >> 3] |= (1 << (z & 7));
+ }
+
+ char* _bm; // Bitmap indicating the numbers used
+ size_t _nv; // Number of values returned so far
+ size_t _bs; // Maximum value
+};
+
+#endif
diff --git a/dab/test.cc b/dab/test.cc
new file mode 100644
index 0000000..a9e0165
--- /dev/null
+++ b/dab/test.cc
@@ -0,0 +1,50 @@
+/* $NetBSD: test.cc,v 1.2 2008/04/28 20:22:54 martin Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * test.C: Test program for randomizer
+ */
+
+#include "defs.h"
+RCSID("$NetBSD: test.cc,v 1.2 2008/04/28 20:22:54 martin Exp $")
+
+#include <iostream>
+#include "random.h"
+
+int
+main(void)
+{
+ RANDOM rd(10);
+
+ for (size_t x = rd(); x < 10; x = rd())
+ std::cout << "x=" << x << std::endl;
+ return 0;
+}
diff --git a/dab/ttyscrn.cc b/dab/ttyscrn.cc
new file mode 100644
index 0000000..eeed5fb
--- /dev/null
+++ b/dab/ttyscrn.cc
@@ -0,0 +1,233 @@
+/* $NetBSD: ttyscrn.cc,v 1.5 2012/10/06 19:39:51 christos Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * ttyscrn.C: Curses screen implementation for dots
+ */
+
+#include "defs.h"
+RCSID("$NetBSD: ttyscrn.cc,v 1.5 2012/10/06 19:39:51 christos Exp $")
+
+#include <stdio.h>
+#include <curses.h>
+#include <sys/ioctl.h>
+
+#include "player.h"
+#include "ttyscrn.h"
+
+void TTYSCRN::clean(void)
+{
+ clear();
+}
+
+void TTYSCRN::moveto(size_t y, size_t x)
+{
+ move(y + TTYSCRN::offsy, x + TTYSCRN::offsx);
+}
+
+void TTYSCRN::addsym(const int sym)
+{
+ addch(sym);
+}
+
+void TTYSCRN::addedge(const int sym)
+{
+ int nsym;
+#ifdef A_ALTCHARSET
+ if (_acs) {
+ switch (sym) {
+ case GS_HLINE:
+ nsym = ACS_HLINE;
+ break;
+ case GS_VLINE:
+ nsym = ACS_VLINE;
+ break;
+ case GS_ULCORNER:
+ nsym = ACS_ULCORNER;
+ break;
+ case GS_URCORNER:
+ nsym = ACS_URCORNER;
+ break;
+ case GS_LLCORNER:
+ nsym = ACS_LLCORNER;
+ break;
+ case GS_LRCORNER:
+ nsym = ACS_LRCORNER;
+ break;
+ case GS_LTEE:
+ nsym = ACS_LTEE;
+ break;
+ case GS_RTEE:
+ nsym = ACS_RTEE;
+ break;
+ case GS_TTEE:
+ nsym = ACS_TTEE;
+ break;
+ case GS_BTEE:
+ nsym = ACS_BTEE;
+ break;
+ case GS_PLUS:
+ nsym = ACS_PLUS;
+ break;
+ case ' ':
+ addsym(' ');
+ return;
+ default:
+ ::abort();
+ }
+ attron(A_ALTCHARSET);
+ addch(nsym);
+ attroff(A_ALTCHARSET);
+ return;
+ }
+#endif
+ switch (sym) {
+ case GS_HLINE:
+ nsym = '-';
+ break;
+ case GS_VLINE:
+ nsym = '|';
+ break;
+ case GS_ULCORNER:
+ nsym = '.';
+ break;
+ case GS_URCORNER:
+ nsym = '.';
+ break;
+ case GS_LLCORNER:
+ nsym = '.';
+ break;
+ case GS_LRCORNER:
+ nsym = '.';
+ break;
+ case GS_LTEE:
+ nsym = '.';
+ break;
+ case GS_RTEE:
+ nsym = '.';
+ break;
+ case GS_TTEE:
+ nsym = '.';
+ break;
+ case GS_BTEE:
+ nsym = '.';
+ break;
+ case GS_PLUS:
+ nsym = '+';
+ break;
+ case ' ':
+ addsym(' ');
+ return;
+ default:
+ ::abort();
+ }
+ addsym(nsym);
+}
+
+void TTYSCRN::redraw(void)
+{
+ refresh();
+ doupdate();
+}
+
+void TTYSCRN::bell(void)
+{
+ putc('\007', stdout);
+}
+
+int TTYSCRN::getinput(void)
+{
+ return getch();
+}
+
+void TTYSCRN::score(size_t s, const PLAYER& p)
+{
+ mvwprintw(stdscr, _sy + s + TTYSCRN::offsscore, _sx, "S %c:%5zd", p.getWho(),
+ p.getScore());
+}
+
+void TTYSCRN::total(size_t s, const PLAYER& p)
+{
+ mvwprintw(stdscr, _sy + s + TTYSCRN::offstotal, _sx, "T %c:%5zd", p.getWho(),
+ p.getTotal());
+}
+
+void TTYSCRN::games(size_t s, const PLAYER& p)
+{
+ mvwprintw(stdscr, _sy + s + TTYSCRN::offsgames, _sx, "G %c:%5zd", p.getWho(),
+ p.getGames());
+}
+
+void TTYSCRN::ties(const PLAYER& p)
+{
+ mvwprintw(stdscr, _sy + TTYSCRN::offsties, _sx, "G =:%5zd", p.getTies());
+}
+
+TTYSCRN* TTYSCRN::create(int acs, size_t *y, size_t *x)
+{
+ int tx, ty;
+
+ initscr();
+
+ tx = getmaxx(stdscr);
+ ty = getmaxy(stdscr);
+
+ if (tx == ERR || ty == ERR
+ || static_cast<size_t>(tx) < *x * 2 + TTYSCRN::offsx + 14
+ || static_cast<size_t>(ty) < *y * 2 + TTYSCRN::offsy) {
+ endwin();
+ return NULL;
+ }
+ if (*x == 0)
+ *x = (tx - 14 - TTYSCRN::offsx) / 2;
+ if (*y == 0)
+ *y = (ty - TTYSCRN::offsy) / 2;
+ cbreak();
+ noecho();
+
+
+ TTYSCRN* that = new TTYSCRN;
+
+ that->_tx = tx;
+ that->_ty = ty;
+ that->_sx = tx - 12;
+ that->_sy = TTYSCRN::offsy;
+ that->_acs = acs;
+
+ return that;
+}
+
+TTYSCRN::~TTYSCRN(void)
+{
+ nocbreak();
+ echo();
+ endwin();
+}
diff --git a/dab/ttyscrn.h b/dab/ttyscrn.h
new file mode 100644
index 0000000..addd91e
--- /dev/null
+++ b/dab/ttyscrn.h
@@ -0,0 +1,74 @@
+/* $NetBSD: ttyscrn.h,v 1.4 2012/10/06 19:39:51 christos Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * ttyscrn.h: Curses based screen for dots
+ */
+
+#ifndef _H_TTYSCRN
+#define _H_TTYSCRN
+
+#include "gamescreen.h"
+
+class TTYSCRN : public GAMESCREEN {
+ public:
+ // Constructor that can fail
+ static TTYSCRN* create(int acs, size_t *y, size_t *x);
+ ~TTYSCRN();
+
+ // Screen virtuals
+ void clean(void);
+ void moveto(size_t y, size_t x);
+ void addsym(const int sym);
+ void addedge(const int sym);
+ void redraw(void);
+ void bell(void);
+ int getinput(void);
+ void score(size_t s, const PLAYER& p);
+ void games(size_t s, const PLAYER& p);
+ void total(size_t s, const PLAYER& p);
+ void ties(const PLAYER& p);
+
+ private:
+ enum {
+ offsx = 2, // board x offset from top left corner
+ offsy = 2, // board y offset from top left corner
+ offsscore = 0, // score y offset from top of the board
+ offstotal = 3, // total y offset from top of the board
+ offsgames = 6, // games y offset from top of the board
+ offsties = 8 // ties y offset from top of the board
+ };
+ size_t _sx, _sy; // board size
+ size_t _tx, _ty; // tty size
+ int _acs; // do we want acs?
+};
+
+#endif