2 * sr -- A sample robot for Netris
3 * Copyright (C) 1994,1995,1996 Mark H. Weaver <mhw@netris.org>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 * $Id: sr.c,v 1.10 1996/02/09 08:22:20 mhw Exp $
29 /* Both of these should be at least twice the actual max */
30 #define MAX_BOARD_WIDTH 32
31 #define MAX_BOARD_HEIGHT 64
37 int boardHeight, boardWidth;
38 int board[MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH];
42 int board1[MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH];
46 int pieceCount; /* Serial number of current piece, for sending commands */
47 int pieceVisible; /* How many blocks of the current piece are visible */
48 int pieceBottom, pieceLeft; /* Position of bottom-left square */
49 int pieceBottomLast, pieceLeftLast;
54 * 2 = move in progress
55 * 3 = drop in progress
62 int masterEnable = 1, dropEnable = 1;
64 float curTime, moveTimeout;
71 char *ReadLine(char *buf, int size)
75 if (!fgets(buf, size, stdin))
78 if (len > 0 && buf[len-1] == '\n')
81 fprintf(logFile, " %s\n", buf);
85 int WriteLine(char *fmt, ...)
91 result = vfprintf(stdout, fmt, args);
93 fprintf(logFile, "> ");
94 vfprintf(logFile, fmt, args);
105 pieceBottom = MAX_BOARD_HEIGHT;
106 pieceLeft = MAX_BOARD_WIDTH;
107 for (row = boardHeight - 1; row >= 0; --row)
108 for (col = boardWidth - 1; col >= 0; --col)
109 if (board[row][col] < 0) {
115 for (row = 0; row < 4; ++row)
116 for (col = 0; col < 4; ++col)
117 piece[row][col] = board[pieceBottom + row][pieceLeft + col] < 0;
120 void RotatePiece1(void)
122 int row, col, height = 0;
124 for (row = 0; row < 4; ++row)
125 for (col = 0; col < 4; ++col)
127 piece2[row][col] = piece1[row][col];
128 piece1[row][col] = 0;
129 if (piece2[row][col])
132 for (row = 0; row < 4; ++row)
133 for (col = 0; col < height; ++col)
134 piece1[row][col] = piece2[height - col - 1][row];
137 int PieceFits(int row, int col)
143 for (i = 0; i < 4; ++i)
144 for (j = 0; j < 4; ++j)
146 if (col+j >= boardWidth || board[row+i][col+j] > 0)
151 int SimPlacement(int row, int col)
156 for (i = 0; i < boardHeight; ++i)
157 for (j = 0; j < boardWidth; ++j) {
158 board1[i][j] = board[i][j] > 0;
159 if (i >= row && i < row+4 && j >= col && j < col+4)
160 if (piece1[i - row][j - col])
163 for (from = to = 0; to < boardHeight; ++from) {
165 for (j = 0; j < boardWidth; ++j)
166 count -= board1[to][j] = board1[from][j];
172 double BoardScore(int linesCleared, int pRow, int verbose)
175 double avgHeight2 = 0, avgHolesTimesDepth = 0;
176 int maxMidHeight = 0, maxHeight = 0;
177 int height[MAX_BOARD_WIDTH];
178 int holesTimesDepth[MAX_BOARD_WIDTH];
179 int holes[MAX_BOARD_WIDTH];
180 double hardFit[MAX_BOARD_HEIGHT];
181 int depend[MAX_BOARD_HEIGHT];
182 int cover[MAX_BOARD_WIDTH];
183 int row, col, count, i;
184 int deltaLeft, deltaRight;
185 double closeToTop, topShape = 0, fitProbs = 0, space = 0;
188 for (col = 0; col < boardWidth; ++col) {
191 for (row = 0; row < boardHeight; ++row)
192 if (board1[row][col])
193 height[col] = row + 1;
194 avgHeight2 += height[col] * height[col];
195 if (maxHeight < height[col])
196 maxHeight = height[col];
197 if (col >= 2 && col < boardWidth - 2 && maxMidHeight < height[col])
198 maxMidHeight = height[col];
200 holesTimesDepth[col] = 0;
201 for (row = 0; row < height[col]; ++row) {
202 if (board1[row][col])
203 holesTimesDepth[col] += holes[col];
207 avgHolesTimesDepth += holesTimesDepth[col];
209 avgHeight2 /= boardWidth;
210 avgHolesTimesDepth /= boardWidth;
212 /* Calculate dependencies */
213 for (row = maxHeight - 1; row >= 0; --row) {
215 for (col = 0; col < boardWidth; ++col) {
216 if (board1[row][col])
217 cover[col] |= 1 << row;
219 depend[row] |= cover[col];
221 for (i = row + 1; i < maxHeight; ++i)
222 if (depend[row] & (1 << i))
223 depend[row] |= depend[i];
226 /* Calculate hardness of fit */
227 for (row = maxHeight - 1; row >= 0; --row) {
230 for (col = 0; col < boardWidth; ++col) {
231 if (board1[row][col]) {
234 else if (!board1[row][col]) {
238 if (height[col] < row)
239 hardFit[row] += row - height[col];
241 deltaLeft = height[col - 1] - row;
243 deltaLeft = MAX_BOARD_HEIGHT;
244 if (col < boardWidth - 1)
245 deltaRight = height[col + 1] - row;
247 deltaRight = MAX_BOARD_HEIGHT;
248 if (deltaLeft > 2 && deltaRight > 2)
250 else if (deltaLeft > 2 || deltaRight > 2)
252 else if (abs(deltaLeft) == 2 && abs(deltaRight) == 2)
254 else if (abs(deltaLeft) == 2 || abs(deltaRight) == 2)
259 for (i = row + 1; i < row + 5 && i < maxHeight; ++i)
260 if (depend[row] & (1 << i))
261 if (maxHard < hardFit[i])
262 maxHard = hardFit[i];
263 fitProbs += maxHard * count;
266 /* Calculate score based on top shape */
267 for (col = 0; col < boardWidth; ++col) {
269 deltaLeft = height[col - 1] - height[col];
271 deltaLeft = MAX_BOARD_HEIGHT;
272 if (col < boardWidth - 1)
273 deltaRight = height[col + 1] - height[col];
275 deltaRight = MAX_BOARD_HEIGHT;
276 if (deltaLeft > 2 && deltaRight > 2)
277 topShape += 15 + 15 * (min(deltaLeft, deltaRight) / 4);
278 else if (deltaLeft > 2 || deltaRight > 2)
280 else if (abs(deltaLeft) == 2 && abs(deltaRight) == 2)
282 else if (abs(deltaLeft) == 2 || abs(deltaRight) == 2)
286 closeToTop = (pRow / (double)boardHeight);
287 closeToTop *= closeToTop;
291 score = space + closeToTop + topShape + fitProbs - linesCleared * 10;
294 WriteLine("Message space=%g, close=%g, shape=%g\n",
295 space, closeToTop, topShape);
296 WriteLine("Message fitProbs=%g, cleared=%d\n",
297 fitProbs, -linesCleared * 10);
309 for (i = 0; i < 4; ++i) {
311 for (j = 0; j < 4; ++j)
312 b[c++] = pieceDest[i][j] ? '*' : ' ';
316 WriteLine("Message Goal %d %s\n", leftDest, b);
319 double MakeDecision(void)
324 double minScore = 0, score;
326 memcpy(piece1, piece, sizeof(piece));
327 for (rot = 0; rot < 4; ++rot) {
329 for (col = 0; col < boardWidth; ++col) {
330 if (!PieceFits(pieceBottom, col))
332 for (row = pieceBottom; PieceFits(row-1, col); --row)
334 linesCleared = SimPlacement(row, col);
335 score = BoardScore(linesCleared, row, 0);
336 if (first || minScore > score) {
339 memcpy(pieceDest, piece1, sizeof(piece));
348 double PeekScore(int verbose)
350 int row, col, linesCleared;
352 memcpy(piece1, piece, sizeof(piece));
354 for (row = pieceBottom; PieceFits(row-1, col); --row)
356 linesCleared = SimPlacement(row, col);
357 return BoardScore(linesCleared, row, verbose);
360 int main(int argc, char **argv)
365 if (argc == 2 && !strcmp(argv[1], "-l")) {
366 logFile = fopen("log", "w");
372 setvbuf(stdout, NULL, _IOLBF, 0);
373 WriteLine("Version 1\n");
374 while(ReadLine(b, sizeof b)) {
375 av[0] = strtok(b, " ");
379 while ((av[ac] = strtok(NULL, " ")))
381 if (!strcmp(av[0], "Exit"))
383 else if (!strcmp(av[0], "NewPiece") && ac >= 2) {
384 pieceCount = atoi(av[1]);
387 else if (!strcmp(av[0], "BoardSize") && ac >= 4) {
388 if (atoi(av[1]) != 0)
390 boardHeight = atoi(av[2]);
391 boardWidth = atoi(av[3]);
393 else if (!strcmp(av[0], "RowUpdate") && ac >= 3 + boardWidth) {
400 for (col = 0; col < boardWidth; col++)
401 board[row][col] = atoi(av[3 + col]);
403 else if (!strcmp(av[0], "UserKey") && ac >= 3) {
411 WriteLine("Message Score = %g\n", PeekScore(key == 'v'));
414 masterEnable = !masterEnable;
415 WriteLine("Message Enable = %d\n", masterEnable);
418 dropEnable = !dropEnable;
419 WriteLine("Message Drop Enable = %d\n", dropEnable);
422 if (strcmp(av[2], "?"))
423 WriteLine("%s %d\n", av[2], pieceCount);
427 else if (!strcmp(av[0], "TimeStamp") && ac >= 2 && masterEnable) {
428 curTime = atof(av[1]);
430 if (pieceVisible < 4)
432 if (memcmp(piece, pieceLast, sizeof(piece)) ||
433 pieceLeft != pieceLeftLast) {
436 memcpy(pieceLast, piece, sizeof(piece));
437 pieceLeftLast = pieceLeft;
439 if (pieceState == 0) { /* Undecided */
443 if (pieceState >= 2) { /* Move or drop in progress */
444 if (curTime >= moveTimeout)
447 if (pieceState == 1) { /* Decided */
448 if (memcmp(piece, pieceDest, sizeof(piece))) {
449 WriteLine("Rotate %d\n", pieceCount);
452 else if (pieceLeft != leftDest) {
453 if (pieceLeft < leftDest)
454 WriteLine("Right %d\n", pieceCount);
456 WriteLine("Left %d\n", pieceCount);
459 else if (dropEnable) {
460 WriteLine("Drop %d\n", pieceCount);
464 moveTimeout = curTime + 0.5;