Home | History | Annotate | Line # | Download | only in dab
      1 /*	$NetBSD: board.cc,v 1.5 2021/12/05 09:22:45 rillig Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2003 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Christos Zoulas.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Board manipulations
     34  */
     35 
     36 #include "defs.h"
     37 RCSID("$NetBSD: board.cc,v 1.5 2021/12/05 09:22:45 rillig Exp $")
     38 
     39 #include <stdio.h>
     40 #include <string.h>
     41 #include <stdarg.h>
     42 #include "board.h"
     43 #include "gamescreen.h"
     44 #include "box.h"
     45 #include "player.h"
     46 
     47 BOARD::BOARD(size_t y, size_t x, GAMESCREEN* scrn) :
     48     _ny(y),
     49     _nx(x),
     50     _scrn(scrn)
     51 {
     52     _ty = 2 * _ny + 1;
     53     _tx = 2 * _nx + 1;
     54 
     55     _b = new int*[_ty];
     56 
     57     for (y = 0; y < _ty; y++)
     58 	_b[y] = new int[_tx];
     59 
     60     init();
     61 }
     62 
     63 BOARD::BOARD(const BOARD& b) :
     64     _ty(b._ty),
     65     _tx(b._tx),
     66     _ny(b._ny),
     67     _nx(b._nx),
     68     _scrn(NULL)
     69 {
     70     _b = new int*[_ty];
     71 
     72     for (size_t y = 0; y < _ty; y++) {
     73 	_b[y] = new int[_tx];
     74 	static_cast<void>(memcpy(_b[y], b._b[y], _tx * sizeof(int)));
     75     }
     76 }
     77 
     78 BOARD::~BOARD()
     79 {
     80     size_t y;
     81 
     82     for (y = 0; y < _ty; y++)
     83 	delete[] _b[y];
     84 
     85     delete[] _b;
     86 }
     87 
     88 // Clear all boxes and reset state for a new game
     89 void BOARD::init(void)
     90 {
     91     size_t x, y;
     92 
     93     for (y = 0; y < _ny; y++)
     94 	for (x = 0; x < _nx; x++) {
     95 	    BOX box(y, x, *this);
     96 	    box.reset();
     97 	}
     98 }
     99 
    100 /*
    101  * Make a move for player with initial 'c', adding an edge at box(x, y)
    102  * and the specified direction.
    103  * returns:
    104  *	-1:	Invalid move
    105  *	 n:	Number of closures n E [0..2]
    106  */
    107 int BOARD::domove(size_t y, size_t x, int dir, char c)
    108 {
    109     int closed = 0;
    110 
    111     // Check if out of bounds
    112     if (!bounds(y, x))
    113 	return -1;
    114 
    115     BOX box1(y, x, *this);
    116 
    117     // Check if the edge is already there
    118     if (box1.isset(dir))
    119 	return -1;
    120 
    121     box1.set(dir);
    122 
    123     if (box1.count() == 4) {
    124 	// New box; name it and count it
    125 	box1.name() = c;
    126 	closed++;
    127     }
    128 
    129     box1.paint();
    130 
    131     // Check other box
    132     x += BOX::edges[dir].x;
    133     y += BOX::edges[dir].y;
    134 
    135     if (bounds(y, x)) {
    136 	BOX box2(y, x, *this);
    137 	if (box2.count() == 4) {
    138 	    box2.name() = c;
    139 	    box2.paint();
    140 	    closed++;
    141 	}
    142     }
    143     return closed;
    144 }
    145 
    146 // Return true if the board is full
    147 int BOARD::full(void) const
    148 {
    149     for (size_t y = 0; y < _ny; y++)
    150 	for (size_t x = 0; x < _nx; x++) {
    151 	    BOX box(y, x, const_cast<BOARD&>(*this));
    152 	    if (box.count() != 4)
    153 		return 0;
    154 	}
    155     return 1;
    156 }
    157 
    158 // Return if the coordinates are within bounds; we don't check for < 0,
    159 // since size_t is unsigned
    160 int BOARD::bounds(size_t y, size_t x) const
    161 {
    162     return x < _nx && y < _ny;
    163 }
    164 
    165 // Paint all boxes, effectively redrawing the board
    166 void BOARD::paint(void) const
    167 {
    168     for (size_t y = 0; y < _ny; y++)
    169 	for (size_t x = 0; x < _nx; x++) {
    170 	    BOX box(y, x, const_cast<BOARD&>(*this));
    171 	    box.paint();
    172 	}
    173 }
    174 
    175 // Clear the screen
    176 void BOARD::clean(void) const
    177 {
    178     if (!_scrn)
    179 	return;
    180     _scrn->clean();
    181 }
    182 
    183 // Move cursor to x, y
    184 void BOARD::setpos(size_t y, size_t x) const
    185 {
    186     if (!_scrn)
    187 	return;
    188     _scrn->moveto(y, x);
    189     _scrn->redraw();
    190 }
    191 
    192 // Return character indicating move
    193 int BOARD::getmove(void) const
    194 {
    195     if (!_scrn)
    196 	return 'q';
    197     _scrn->redraw();
    198     return _scrn->getinput();
    199 }
    200 
    201 // Ring the bell
    202 void BOARD::bell(void) const
    203 {
    204     if (!_scrn)
    205 	return;
    206     _scrn->bell();
    207 }
    208 
    209 // Post the score in the current game for player i
    210 void BOARD::score(size_t i, const PLAYER& p)
    211 {
    212     if (_scrn == NULL)
    213 	return;
    214     _scrn->score(i, p);
    215 }
    216 
    217 // Post the number of games won for player i
    218 void BOARD::games(size_t i, const PLAYER& p)
    219 {
    220     if (_scrn == NULL)
    221 	return;
    222     _scrn->games(i, p);
    223 }
    224 
    225 // Post the total score for player i
    226 void BOARD::total(size_t i, const PLAYER& p)
    227 {
    228     if (_scrn == NULL)
    229 	return;
    230     _scrn->total(i, p);
    231 }
    232 
    233 // Post the total score for player i
    234 void BOARD::ties(const PLAYER& p)
    235 {
    236     if (_scrn == NULL)
    237 	return;
    238     _scrn->ties(p);
    239 }
    240 
    241 // Internal algorithm error; post and abort
    242 void BOARD::abort(const char* s, ...) const
    243 {
    244     for (size_t i = 0; i < _ny; i++)
    245 	fprintf(stderr, "\n");
    246 
    247     va_list ap;
    248     fprintf(stderr, "Algorithm internal error: ");
    249     va_start(ap, s);
    250     vfprintf(stderr, s, ap);
    251     va_end(ap);
    252     fprintf(stderr, "\n");
    253     ::abort();
    254 }
    255