xref: /openbsd-src/games/backgammon/common_source/fancy.c (revision 87f25a4abf762f43d1a2045a585c035489c33d7d)
1 /*	$OpenBSD: fancy.c,v 1.13 2015/11/30 08:19:25 tb Exp $	*/
2 
3 /*
4  * Copyright (c) 1980, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <err.h>
33 #include "back.h"
34 
35 int     oldb[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
36 int     oldr, oldw;
37 
38 void
fboard(void)39 fboard(void)
40 {
41 	int     i, j, k, l;
42 
43 	/* could use box() or wborder() instead of the following */
44 	move(0, 0);		/* do top line */
45 	for (i = 0; i < 53; i++)
46 		addch('_');
47 
48 	move(15, 0);		/* do bottom line */
49 	for (i = 0; i < 53; i++)
50 		addch('_');
51 
52 	l = 1;			/* do vertical lines */
53 	for (i = 52; i > -1; i -= 28) {
54 		k = (l == 1 ? 1 : 15);
55 		mvaddch(k, i, '|');
56 		for (j = 0; j < 14; j++)
57 			mvaddch(k += l, i, '|');
58 		if (i == 24)
59 			i += 32;
60 		l = -l;		/* alternate directions */
61 	}
62 
63 	/* label positions */
64 	for (i = 13; i < 19; i++)
65 		mvprintw(2, 1 + (i - 13) * 4, "%d", i);
66 	for (i = 19; i < 25; i++)
67 		mvprintw(2, 29 + (i - 19) * 4, "%d", i);
68 	for (i = 12; i > 6; i--)
69 		mvprintw(14, 1 + (12 - i) * 4, "%2d", i);
70 	for (i = 6; i > 0; i--)
71 		mvprintw(14, 30 + (6 - i) * 4, "%d", i);
72 
73 	/* print positions 12-7 */
74 	for (i = 12; i > 6; i--)
75 		if (board[i])
76 			bsect(board[i], 13, 1 + 4 * (12 - i), -1);
77 	/* print red men on bar */
78 	if (board[0])
79 		bsect(board[0], 13, 25, -1);
80 	/* print positions 6-1 */
81 	for (i = 6; i > 0; i--)
82 		if (board[i])
83 			bsect(board[i], 13, 29 + 4 * (6 - i), -1);
84 	/* print white's home */
85 	l = (off[1] < 0 ? off[1] + 15 : off[1]);
86 	bsect(l, 3, 54, 1);
87 
88 	mvaddstr(8, 25, "BAR");
89 
90 	/* print positions 13-18 */
91 	for (i = 13; i < 19; i++)
92 		if (board[i])
93 			bsect(board[i], 3, 1 + 4 * (i - 13), 1);
94 	/* print white's men on bar */
95 	if (board[25])
96 		bsect(board[25], 3, 25, 1);
97 	/* print positions 19-24 */
98 	for (i = 19; i < 25; i++)
99 		if (board[i])
100 			bsect(board[i], 3, 29 + 4 * (i - 19), 1);
101 	/* print red's home */
102 	l = (off[0] < 0 ? off[0] + 15 : off[0]);
103 	bsect(-l, 13, 54, -1);
104 
105 	for (i = 0; i < 26; i++)/* save board position for refresh later */
106 		oldb[i] = board[i];
107 	oldr = (off[1] < 0 ? off[1] + 15 : off[1]);
108 	oldw = -(off[0] < 0 ? off[0] + 15 : off[0]);
109 }
110 
111 /*
112  * bsect (b,rpos,cpos,cnext)
113  *	Print the contents of a board position.  "b" has the value of the
114  * position, "rpos" is the row to start printing, "cpos" is the column to
115  * start printing, and "cnext" is positive if the position starts at the top
116  * and negative if it starts at the bottom.  The value of "cpos" is checked
117  * to see if the position is a player's home, since those are printed
118  * differently.
119  */
120 void
bsect(int b,int rpos,int cpos,int cnext)121 bsect(int b, int rpos, int cpos, int cnext)
122 {
123 	int     j;		/* index */
124 	int     n;		/* number of men on position */
125 	int     bct;		/* counter */
126 	int     k;		/* index */
127 	char    pc;		/* color of men on position */
128 
129 	n = abs(b);		/* initialize n and pc */
130 	pc = (b > 0 ? 'r' : 'w');
131 
132 	if (n < 6 && cpos < 54)	/* position cursor at start */
133 		move(rpos, cpos + 1);
134 	else
135 		move(rpos, cpos);
136 
137 	for (j = 0; j < 5; j++) {	/* print position row by row */
138 
139 		for (k = 0; k < 15; k += 5)	/* print men */
140 			if (n > j + k)
141 				addch(pc);
142 
143 		if (j < 4) {	/* figure how far to back up for next row */
144 			if (n < 6) {	/* stop if none left */
145 				if (j + 1 == n)
146 					break;
147 				bct = 1;	/* single column */
148 			} else {
149 				if (n < 11) {	/* two columns */
150 					if (cpos >= 54) {	/* home pos */
151 						if (j + 5 >= n)
152 							bct = 1;
153 						else
154 							bct = 2;
155 					} else { 	/* not home */
156 						if (j + 6 >= n)
157 							bct = 1;
158 						else
159 							bct = 2;
160 					}
161 				} else {	/* three columns */
162 					if (j + 10 >= n)
163 						bct = 2;
164 					else
165 						bct = 3;
166 				}
167 			}
168 			getyx(stdscr, rpos, cpos);
169 			move(rpos + cnext, cpos - bct);
170 		}
171 	}
172 }
173 
174 void
moveplayers(void)175 moveplayers(void)
176 {
177 	int i, r, c;
178 
179 	getyx(stdscr, r, c);
180 	for (i = 12; i > 6; i--)/* fix positions 12-7 */
181 		if (board[i] != oldb[i]) {
182 			fixpos(oldb[i], board[i], 13, 1 + (12 - i) * 4, -1);
183 			oldb[i] = board[i];
184 		}
185 	if (board[0] != oldb[0]) {	/* fix red men on bar */
186 		fixpos(oldb[0], board[0], 13, 25, -1);
187 		oldb[0] = board[0];
188 	}
189 	for (i = 6; i > 0; i--)	/* fix positions 6-1 */
190 		if (board[i] != oldb[i]) {
191 			fixpos(oldb[i], board[i], 13, 29 + (6 - i) * 4, -1);
192 			oldb[i] = board[i];
193 		}
194 	i = -(off[0] < 0 ? off[0] + 15 : off[0]);	/* fix white's home */
195 	if (oldw != i) {
196 		fixpos(oldw, i, 13, 54, -1);
197 		oldw = i;
198 	}
199 	for (i = 13; i < 19; i++)	/* fix positions 13-18 */
200 		if (board[i] != oldb[i]) {
201 			fixpos(oldb[i], board[i], 3, 1 + (i - 13) * 4, 1);
202 			oldb[i] = board[i];
203 		}
204 	if (board[25] != oldb[25]) {	/* fix white men on bar */
205 		fixpos(oldb[25], board[25], 3, 25, 1);
206 		oldb[25] = board[25];
207 	}
208 	for (i = 19; i < 25; i++)	/* fix positions 19-24 */
209 		if (board[i] != oldb[i]) {
210 			fixpos(oldb[i], board[i], 3, 29 + (i - 19) * 4, 1);
211 			oldb[i] = board[i];
212 		}
213 	i = (off[1] < 0 ? off[1] + 15 : off[1]);	/* fix red's home */
214 	if (oldr != i) {
215 		fixpos(oldr, i, 3, 54, 1);
216 		oldr = i;
217 	}
218 	move(r, c);		/* return to saved position */
219 	refresh();
220 }
221 
222 
223 void
fixpos(int old,int new,int r,int c,int inc)224 fixpos(int old, int new, int r, int c, int inc)
225 {
226 	int     o, n, nv;
227 	int     ov, nc;
228 	char    col;
229 
230 	nc = 0;
231 	if (old * new >= 0) {
232 		ov = abs(old);
233 		nv = abs(new);
234 		col = (old + new > 0 ? 'r' : 'w');
235 		o = (ov - 1) / 5;
236 		n = (nv - 1) / 5;
237 		if (o == n) {
238 			if (o == 2)
239 				nc = c + 2;
240 			if (o == 1)
241 				nc = c < 54 ? c : c + 1;
242 			if (o == 0)
243 				nc = c < 54 ? c + 1 : c;
244 			if (ov > nv)
245 				fixcol(r + inc * (nv - n * 5), nc, abs(ov - nv), ' ', inc);
246 			else
247 				fixcol(r + inc * (ov - o * 5), nc, abs(ov - nv), col, inc);
248 			return;
249 		} else {
250 			if (c < 54) {
251 				if (o + n == 1) {
252 					if (n) {
253 						fixcol(r, c, abs(nv - 5), col, inc);
254 						if (ov != 5)
255 							fixcol(r+inc*ov, c+1, abs(ov-5), col, inc);
256 					} else  {
257 						fixcol(r, c, abs(ov - 5), ' ', inc);
258 						if (nv != 5)
259 							fixcol(r+inc*nv, c+1, abs(nv-5), ' ', inc);
260 					}
261 					return;
262 				}
263 				if (n == 2) {
264 					if (ov != 10)
265 						fixcol(r+inc*(ov-5), c, abs(ov-10), col, inc);
266 					fixcol(r, c + 2, abs(nv - 10), col, inc);
267 				} else {
268 					if (nv != 10)
269 						fixcol(r+inc*(nv-5), c, abs(nv-10), ' ', inc);
270 					fixcol(r, c + 2, abs(ov - 10), ' ', inc);
271 				}
272 				return;
273 			}
274 			if (n > o) {
275 				fixcol(r+inc*(ov%5), c+o, abs(5*n-ov), col, inc);
276 				if (nv != 5 * n)
277 					fixcol(r, c+n, abs(5*n-nv), col, inc);
278 			} else {
279 				fixcol(r+inc*(nv%5), c+n, abs(5*n-nv), ' ', inc);
280 				if (ov != 5 * o)
281 					fixcol(r, c+o, abs(5*o-ov), ' ', inc);
282 			}
283 			return;
284 		}
285 	}
286 	nv = abs(new);
287 	fixcol(r, c + 1, nv, new > 0 ? 'r' : 'w', inc);
288 	if (abs(old) <= abs(new))
289 		return;
290 	fixcol(r + inc * new, c + 1, abs(old + new), ' ', inc);
291 }
292 
293 void
fixcol(int r,int c,int l,int ch,int inc)294 fixcol(int r, int c, int l, int ch, int inc)
295 {
296 	int     i;
297 
298 	mvaddch(r, c, ch);
299 	for (i = 1; i < l; i++) {
300 		r += inc;
301 		mvaddch(r, c, ch);
302 	}
303 }
304 
305 
306 void
initcurses(void)307 initcurses(void)
308 {
309 	initscr();
310 	cbreak();
311 	noecho();
312 	keypad(stdscr, TRUE);
313 	nl();
314 	clear();
315 
316 	if ((LINES < 24) || (COLS < 80)) {
317 		endwin();
318 		errx(1, "screen must be at least 24x80.");
319 	}
320 }
321