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" 37RCSID("$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 47BOARD::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 63BOARD::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 78BOARD::~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 89void 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 */ 107int 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 147int 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 160int 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 166void 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 176void BOARD::clean(void) const 177{ 178 if (!_scrn) 179 return; 180 _scrn->clean(); 181} 182 183// Move cursor to x, y 184void 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 193int BOARD::getmove(void) const 194{ 195 if (!_scrn) 196 return 'q'; 197 _scrn->redraw(); 198 return _scrn->getinput(); 199} 200 201// Ring the bell 202void 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 210void 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 218void 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 226void 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 234void 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 242void 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