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