1010 for Arduboy
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Initial release

joshua stein d5e7be34

+802
+1
.gitignore
··· 1 + build-leonardo
+6
Makefile
··· 1 + # requires arduino-makefile 2 + # https://github.com/sudar/Arduino-Makefile 3 + 4 + BOARD_TAG = leonardo 5 + 6 + include /usr/local/share/arduino-makefile/Arduino.mk
+35
README.md
··· 1 + # 1010 for Arduboy 2 + 3 + Gameplay and scoring modeled after the 4 + [1010!](https://itunes.apple.com/us/app/1010/id911793120?mt=8) 5 + game for iOS. 6 + 7 + Highlight one of the three randomly selected pieces with the left and 8 + right directional buttons, then choose a piece with the A button. 9 + Move it around on the board and place it anywhere that isn't overlapping 10 + with the A button, or press B to go back and choose a different piece. 11 + 12 + Position ten blocks in a row or column and it is freed up, play continues 13 + until there are no free spaces to place any of the three pieces. 14 + 15 + One point is scored for each block in the piece placed, and ten points 16 + are scored for clearing a row or column. 17 + 18 + ## Command Mode 19 + 20 + Hold down both A+B buttons and: 21 + 22 + - Up to make the screen backlight brighter, 23 + - Down to make it dimmer, or 24 + - Left or Right to reset the game. 25 + 26 + ## Compiling 27 + 28 + Requires 29 + [Arduino-Makefile](https://github.com/sudar/Arduino-Makefile) 30 + installed. 31 + Adjust the path to `Arduino.mk` in `Makefile`. 32 + 33 + Compile with `make` (requires GNU Make, which is `gmake` on OpenBSD). 34 + 35 + Connect your Arduboy and power it on, then flash it with `make upload`.
+760
arduboy-1010.ino
··· 1 + /* 2 + * 1010 for Arduboy 3 + * Copyright (c) 2018 joshua stein <jcs@jcs.org> 4 + * 5 + * Permission to use, copy, modify, and distribute this software for any 6 + * purpose with or without fee is hereby granted, provided that the above 7 + * copyright notice and this permission notice appear in all copies. 8 + * 9 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 + */ 17 + 18 + #include <EEPROM.h> 19 + #include <SPI.h> 20 + 21 + #include <Arduboy2.h> 22 + 23 + Arduboy2 arduboy; 24 + 25 + /* this many tiles wide and tall */ 26 + const byte BOARD_SIZE = 10; 27 + 28 + /* pixel position of board */ 29 + const byte BOARD_X = 66; 30 + const byte BOARD_Y = 1; 31 + 32 + /* first two bytes of eeprom set to this to indicate a saved game */ 33 + const byte SAVEFLAG = 254; 34 + 35 + /* pieces to choose from in each round */ 36 + const byte ONDECK = 3; 37 + 38 + /* wait this many milliseconds between auto-repeat of d-pad buttons */ 39 + const unsigned int AUTOREPEAT1 = 300; 40 + const unsigned int AUTOREPEATN = 75; 41 + 42 + /* screen backlight levels */ 43 + const byte SCREEN_MAX = 255; 44 + const byte SCREEN_MIN = 10; 45 + 46 + /* game state, written out to eeprom as saved game */ 47 + struct __attribute__((packed)) game_data { 48 + byte saveflag0, saveflag1; 49 + unsigned long hiscore, score; 50 + byte ondeck[ONDECK]; 51 + byte ondecksel; 52 + byte curshape; 53 + byte x, y; 54 + byte over; 55 + byte board[BOARD_SIZE][BOARD_SIZE]; 56 + } game; 57 + 58 + /* possible tile modes */ 59 + enum { 60 + EMPTY, 61 + TAKEN, 62 + PLACING, 63 + SWEEPING, 64 + }; 65 + 66 + /* tile pixmaps */ 67 + const byte TILE_SIZE = 7; 68 + const byte BLOCK_SIZE = TILE_SIZE - 1; 69 + const byte colors[][TILE_SIZE] PROGMEM = { 70 + { /* EMPTY */ 71 + B1111111, 72 + B1000001, 73 + B1000001, 74 + B1000001, 75 + B1000001, 76 + B1000001, 77 + B1111111, 78 + }, 79 + { /* TAKEN */ 80 + B1111111, 81 + B1010101, 82 + B1101011, 83 + B1010101, 84 + B1101011, 85 + B1010101, 86 + B1111111, 87 + }, 88 + { 89 + /* PLACING */ 90 + B1111111, 91 + B1111111, 92 + B1111111, 93 + B1111111, 94 + B1111111, 95 + B1111111, 96 + B1111111, 97 + }, 98 + }; 99 + 100 + /* tiny tile pixmap to use for ondeck pieces */ 101 + const byte PREVIEW_SIZE = 4; 102 + const byte preview_color[PREVIEW_SIZE] PROGMEM = { 103 + B1111, 104 + B1001, 105 + B1001, 106 + B1111, 107 + }; 108 + 109 + /* tile shapes */ 110 + typedef struct { 111 + const byte width, height; 112 + const byte tiles[9]; 113 + } shape; 114 + 115 + const shape shapes[] = { 116 + { 0, 0, { // empty 117 + 0, 118 + } 119 + }, 120 + { 1, 1, { // dot 121 + 1, 122 + } 123 + }, 124 + { 2, 2, { // 2x2 square 125 + 1, 1, 126 + 1, 1, 127 + } 128 + }, 129 + { 3, 3, { // 3x3 square 130 + 1, 1, 1, 131 + 1, 1, 1, 132 + 1, 1, 1, 133 + } 134 + }, 135 + { 2, 1, { // 2x1 horizontal 136 + 1, 1, 137 + } 138 + }, 139 + { 3, 1, { // 3x1 horizontal 140 + 1, 1, 1, 141 + } 142 + }, 143 + { 4, 1, { // 4x1 horizontal 144 + 1, 1, 1, 1, 145 + } 146 + }, 147 + { 5, 1, { // 5x1 horizontal 148 + 1, 1, 1, 1, 1, 149 + } 150 + }, 151 + { 1, 2, { // 1x2 vertical 152 + 1, 153 + 1, 154 + } 155 + }, 156 + { 1, 3, { // 1x3 vertical 157 + 1, 158 + 1, 159 + 1, 160 + } 161 + }, 162 + { 1, 4, { // 1x4 vertical 163 + 1, 164 + 1, 165 + 1, 166 + 1, 167 + } 168 + }, 169 + { 1, 5, { // 1x5 vertical 170 + 1, 171 + 1, 172 + 1, 173 + 1, 174 + 1, 175 + } 176 + }, 177 + { 2, 2, { // 2x2 elbow 178 + 1, 1, 179 + 0, 1, 180 + } 181 + }, 182 + { 2, 2, { // 2x2 elbow 183 + 1, 0, 184 + 1, 1, 185 + } 186 + }, 187 + { 2, 2, { // 2x2 elbow 188 + 1, 1, 189 + 1, 0, 190 + } 191 + }, 192 + { 2, 2, { // 2x2 elbow 193 + 0, 1, 194 + 1, 1, 195 + } 196 + }, 197 + { 3, 3, { // 3x3 elbow 198 + 1, 1, 1, 199 + 0, 0, 1, 200 + 0, 0, 1, 201 + } 202 + }, 203 + { 3, 3, { // 3x3 elbow 204 + 1, 0, 0, 205 + 1, 0, 0, 206 + 1, 1, 1, 207 + } 208 + }, 209 + { 3, 3, { // 3x3 elbow 210 + 1, 1, 1, 211 + 1, 0, 0, 212 + 1, 0, 0, 213 + } 214 + }, 215 + { 3, 3, { // 3x3 elbow 216 + 0, 0, 1, 217 + 0, 0, 1, 218 + 1, 1, 1, 219 + } 220 + }, 221 + }; 222 + 223 + void backlight(int); 224 + void new_game(void); 225 + void save_game(void); 226 + uint8_t pressed_dpad_autorepeat(void); 227 + bool place_shape(void); 228 + void draw_screen(void); 229 + void draw_board(void); 230 + void draw_shape(const shape *s, const byte, const byte, const byte, 231 + const byte[]); 232 + byte left_ondeck(void); 233 + void new_shapes(void); 234 + bool shape_clear(const shape *s, const byte, const byte); 235 + bool move_to_clear(const shape *s); 236 + 237 + /* these don't need to be preserved in game state */ 238 + static byte leds[3] = { 0 }; 239 + static int8_t ledsweep[3] = { 0 }; 240 + static unsigned long dpad_millis_next = 0; 241 + static bool dpad_repeatn = false; 242 + static int screen_backlight = SCREEN_MAX; 243 + 244 + void 245 + setup(void) 246 + { 247 + arduboy.begin(); 248 + arduboy.initRandomSeed(); 249 + 250 + /* 251 + * setup screen backlight adjustment 252 + * https://community.arduboy.com/t/screen-brightness/2662/22 253 + */ 254 + arduboy.LCDCommandMode(); 255 + SPI.transfer(0xd9); 256 + SPI.transfer(0x2f); 257 + SPI.transfer(0xdb); 258 + SPI.transfer(0x00); 259 + SPI.transfer(0x81); 260 + SPI.transfer(screen_backlight); 261 + arduboy.LCDDataMode(); 262 + 263 + if (EEPROM.read(0) == SAVEFLAG && EEPROM.read(1) == SAVEFLAG) { 264 + EEPROM.get(0, game); 265 + 266 + if (game.over) 267 + new_game(); 268 + } 269 + else 270 + new_game(); 271 + 272 + arduboy.fillRect(0, 0, BOARD_X - 1, 64, BLACK); 273 + draw_screen(); 274 + } 275 + 276 + void 277 + backlight(int level) 278 + { 279 + if (level < SCREEN_MIN) 280 + level = SCREEN_MIN; 281 + else if (level > SCREEN_MAX) 282 + level = SCREEN_MAX; 283 + 284 + arduboy.LCDCommandMode(); 285 + SPI.transfer(0x81); 286 + SPI.transfer(level); 287 + arduboy.LCDDataMode(); 288 + 289 + screen_backlight = level; 290 + } 291 + 292 + void 293 + new_game(void) 294 + { 295 + unsigned long oldhi = game.hiscore; 296 + 297 + memset(&game, 0, sizeof(game_data)); 298 + game.hiscore = oldhi; 299 + 300 + memset(&leds, 0, sizeof(leds)); 301 + memset(&ledsweep, 0, sizeof(ledsweep)); 302 + game.saveflag0 = SAVEFLAG; 303 + game.saveflag1 = SAVEFLAG; 304 + 305 + arduboy.setRGBled(0, 0, 0); 306 + 307 + new_shapes(); 308 + 309 + save_game(); 310 + } 311 + 312 + void 313 + save_game(void) 314 + { 315 + EEPROM.put(0, game); 316 + } 317 + 318 + uint8_t 319 + pressed_dpad_autorepeat(void) 320 + { 321 + bool left = false; 322 + bool right = false; 323 + bool up = false; 324 + bool down = false; 325 + uint8_t ret = 0; 326 + 327 + /* 328 + * arduboy.pressed() checks for all passed buttons at once, so check 329 + * each individually 330 + */ 331 + left = arduboy.pressed(LEFT_BUTTON); 332 + right = arduboy.pressed(RIGHT_BUTTON); 333 + up = arduboy.pressed(UP_BUTTON); 334 + down = arduboy.pressed(DOWN_BUTTON); 335 + 336 + ret = (left ? LEFT_BUTTON : 0) | (right ? RIGHT_BUTTON : 0) | 337 + (up ? UP_BUTTON : 0) | (down ? DOWN_BUTTON : 0); 338 + 339 + if (ret == 0) { 340 + dpad_millis_next = 0; 341 + dpad_repeatn = false; 342 + return 0; 343 + } 344 + 345 + if (dpad_millis_next == 0) { 346 + /* first pressing of buttons, return immediately */ 347 + dpad_millis_next = millis() + AUTOREPEAT1; 348 + dpad_repeatn = true; 349 + return ret; 350 + } 351 + 352 + if (millis() >= dpad_millis_next) { 353 + dpad_millis_next = millis() + (dpad_repeatn ? AUTOREPEATN : 354 + AUTOREPEAT1); 355 + return ret; 356 + } 357 + 358 + /* otherwise we're waiting until dpad_millis_next */ 359 + return 0; 360 + } 361 + 362 + void 363 + game_over(void) 364 + { 365 + game.over = true; 366 + ledsweep[0] = 1; 367 + 368 + arduboy.fillRect(0, 40, BOARD_X - 1, 64, BLACK); 369 + 370 + arduboy.setCursor(0, 50); 371 + arduboy.print(F("Game Over")); 372 + 373 + arduboy.display(); 374 + save_game(); 375 + } 376 + 377 + void 378 + loop(void) 379 + { 380 + const shape *s; 381 + bool redraw = false; 382 + int8_t x; 383 + uint8_t dpad; 384 + 385 + if (!arduboy.nextFrame()) 386 + return; 387 + 388 + arduboy.pollButtons(); 389 + 390 + /* command mode */ 391 + if (arduboy.pressed(A_BUTTON + B_BUTTON)) { 392 + if (arduboy.justPressed(DOWN_BUTTON)) 393 + backlight(screen_backlight - 20); 394 + else if (arduboy.justPressed(UP_BUTTON)) 395 + backlight(screen_backlight + 20); 396 + else if (arduboy.justPressed(LEFT_BUTTON) || 397 + arduboy.justPressed(RIGHT_BUTTON)) { 398 + new_game(); 399 + draw_screen(); 400 + } 401 + 402 + return; 403 + } 404 + 405 + if (game.over) { 406 + /* if we achieved the high score, flash green, else red */ 407 + x = (game.score == game.hiscore ? 1 : 0); 408 + 409 + if (ledsweep[x] == 1) { 410 + if (leds[x] >= 50) 411 + ledsweep[x] = -1; 412 + else 413 + leds[x]++; 414 + } else { 415 + if (leds[x] <= 10) 416 + ledsweep[x] = 1; 417 + else 418 + leds[x]--; 419 + } 420 + 421 + arduboy.setRGBled(leds[0], leds[1], leds[2]); 422 + 423 + if (arduboy.justPressed(A_BUTTON) || 424 + arduboy.justPressed(B_BUTTON)) { 425 + new_game(); 426 + draw_screen(); 427 + return; 428 + } 429 + } 430 + 431 + if (game.curshape == 0) { 432 + /* selecting an ondeck piece */ 433 + if (arduboy.justPressed(LEFT_BUTTON)) { 434 + for (x = game.ondecksel - 1; x >= 0; x--) { 435 + if (game.ondeck[x]) { 436 + game.ondecksel = x; 437 + redraw = true; 438 + break; 439 + } 440 + } 441 + } else if (arduboy.justPressed(RIGHT_BUTTON)) { 442 + for (x = game.ondecksel + 1; x < ONDECK; x++) { 443 + if (game.ondeck[x]) { 444 + game.ondecksel = x; 445 + redraw = true; 446 + break; 447 + } 448 + } 449 + } else if (arduboy.justPressed(A_BUTTON) || 450 + arduboy.justPressed(B_BUTTON)) { 451 + game.curshape = game.ondeck[game.ondecksel]; 452 + game.ondeck[game.ondecksel] = 0; 453 + 454 + if (!move_to_clear(&shapes[game.curshape])) { 455 + game_over(); 456 + return; 457 + } 458 + 459 + redraw = true; 460 + } 461 + } else { 462 + /* moving the selected piece around on the board */ 463 + s = &shapes[game.curshape]; 464 + 465 + if (arduboy.justPressed(A_BUTTON)) { 466 + if (place_shape()) 467 + redraw = true; 468 + else { 469 + arduboy.setRGBled(50, 0, 0); 470 + delay(50); 471 + arduboy.setRGBled(leds[0], leds[1], leds[2]); 472 + } 473 + } else if (arduboy.justPressed(B_BUTTON)) { 474 + /* put the piece back on deck */ 475 + game.ondeck[game.ondecksel] = game.curshape; 476 + game.curshape = 0; 477 + redraw = true; 478 + } else { 479 + dpad = pressed_dpad_autorepeat(); 480 + redraw = true; 481 + 482 + if ((dpad & UP_BUTTON) && (game.y > 0)) 483 + game.y--; 484 + else if ((dpad & DOWN_BUTTON) && 485 + (game.y < BOARD_SIZE - s->height)) 486 + game.y++; 487 + else if ((dpad & LEFT_BUTTON) && (game.x > 0)) 488 + game.x--; 489 + else if ((dpad & RIGHT_BUTTON) && 490 + (game.x < BOARD_SIZE - s->width)) 491 + game.x++; 492 + else 493 + redraw = false; 494 + } 495 + } 496 + 497 + if (redraw) 498 + draw_screen(); 499 + } 500 + 501 + void 502 + draw_screen(void) 503 + { 504 + const shape *s = NULL; 505 + const shape *ts = NULL; 506 + int i; 507 + byte x; 508 + 509 + draw_board(); 510 + 511 + if (game.curshape > 0 && !game.over) { 512 + s = &shapes[game.curshape]; 513 + 514 + draw_shape(s, BOARD_X + (game.x * BLOCK_SIZE), 515 + BOARD_Y + (game.y * BLOCK_SIZE), BLOCK_SIZE, 516 + colors[PLACING]); 517 + } 518 + 519 + arduboy.setCursor(0, 0); 520 + arduboy.print(F("Score\n")); 521 + arduboy.print(game.score); 522 + 523 + arduboy.setCursor(0, 20); 524 + arduboy.print(F("Hi-Score\n")); 525 + arduboy.print(game.hiscore); 526 + 527 + /* previews */ 528 + for (x = 0; x < sizeof(game.ondeck); x++) { 529 + ts = &shapes[game.ondeck[x]]; 530 + if (ts == 0) 531 + continue; 532 + 533 + i = (((BOARD_X - 10) / ONDECK) * (x + 1)) - 534 + ((BOARD_X - 10) / (ONDECK * 2)); 535 + 536 + draw_shape(ts, 537 + i - ((ts->width * PREVIEW_SIZE) / 2), 538 + 48 - ((ts->height * PREVIEW_SIZE) / 2), 539 + PREVIEW_SIZE, preview_color); 540 + 541 + if (x == game.ondecksel && !game.curshape) { 542 + arduboy.drawPixel(i, 59, WHITE); 543 + arduboy.drawLine(i - 1, 60, i + 1, 60, WHITE); 544 + arduboy.drawLine(i - 2, 61, i + 2, 61, WHITE); 545 + } 546 + } 547 + 548 + arduboy.display(); 549 + } 550 + 551 + void 552 + draw_board(void) 553 + { 554 + byte x, y; 555 + 556 + arduboy.clear(); 557 + 558 + for (y = 0; y < BOARD_SIZE; y++) 559 + for (x = 0; x < BOARD_SIZE; x++) 560 + arduboy.drawBitmap(BOARD_X + (x * BLOCK_SIZE), 561 + BOARD_Y + (y * BLOCK_SIZE), 562 + colors[game.board[x][y]], 563 + TILE_SIZE, TILE_SIZE, WHITE); 564 + 565 + arduboy.drawLine(BOARD_X + 1, 566 + BOARD_Y + (BOARD_SIZE * BLOCK_SIZE) + 1, 567 + BOARD_X + (BOARD_SIZE * BLOCK_SIZE) + 1, 568 + BOARD_Y + (BOARD_SIZE * BLOCK_SIZE) + 1, 569 + WHITE); 570 + arduboy.drawLine(BOARD_X + (BOARD_SIZE * BLOCK_SIZE) + 1, 571 + BOARD_Y + 1, 572 + BOARD_X + (BOARD_SIZE * BLOCK_SIZE) + 1, 573 + BOARD_Y + (BOARD_SIZE * BLOCK_SIZE) + 1, 574 + WHITE); 575 + } 576 + 577 + byte 578 + left_ondeck(void) 579 + { 580 + byte x, od = 0; 581 + 582 + for (x = 0; x < ONDECK; x++) { 583 + if (game.ondeck[x] != 0) 584 + od++; 585 + } 586 + 587 + return od; 588 + } 589 + 590 + void 591 + new_shapes(void) 592 + { 593 + byte x; 594 + 595 + if (left_ondeck()) 596 + return; 597 + 598 + for (x = 0; x < ONDECK; x++) 599 + game.ondeck[x] = random(1, sizeof(shapes) / sizeof(shape)); 600 + } 601 + 602 + bool 603 + shape_clear(const shape *s, const byte x, const byte y) 604 + { 605 + byte tx, ty; 606 + 607 + if (x + s->width > BOARD_SIZE || y + s->height > BOARD_SIZE) 608 + return false; 609 + 610 + for (ty = 0; ty < s->height; ty++) 611 + for (tx = 0; tx < s->width; tx++) 612 + if (s->tiles[tx + (ty * s->width)] != EMPTY && 613 + game.board[x + tx][y + ty] != EMPTY) 614 + return false; 615 + 616 + return true; 617 + } 618 + 619 + bool 620 + move_to_clear(const shape *s) 621 + { 622 + for (game.y = 0; game.y <= BOARD_SIZE - s->height; game.y++) 623 + for (game.x = 0; game.x <= BOARD_SIZE - s->width; game.x++) 624 + if (shape_clear(s, game.x, game.y)) 625 + return true; 626 + 627 + return false; 628 + } 629 + 630 + void 631 + draw_shape(const shape *s, const byte x, const byte y, const byte size, 632 + const byte color[]) 633 + { 634 + byte tx, ty; 635 + 636 + /* walk the shape, stamping its tile in each non-zero spot */ 637 + for (ty = 0; ty < s->height; ty++) 638 + for (tx = 0; tx < s->width; tx++) 639 + if (s->tiles[tx + (ty * s->width)]) 640 + arduboy.drawBitmap(x + (tx * size), 641 + y + (ty * size), color, size, size, 642 + WHITE); 643 + } 644 + 645 + void 646 + explode_swept(void) 647 + { 648 + byte i, x, y; 649 + 650 + for (i = 1; i < TILE_SIZE; i++) { 651 + for (x = 0; x < BOARD_SIZE; x++) 652 + for (y = 0; y < BOARD_SIZE; y++) { 653 + if (game.board[x][y] != SWEEPING) 654 + continue; 655 + 656 + arduboy.drawRect(BOARD_X + (x * BLOCK_SIZE) + i, 657 + BOARD_Y + (y * BLOCK_SIZE) + i, 658 + BLOCK_SIZE - i, BLOCK_SIZE - i, 659 + BLACK); 660 + } 661 + 662 + arduboy.display(); 663 + delay(40 + (i * 10)); 664 + } 665 + 666 + for (x = 0; x < BOARD_SIZE; x++) 667 + for (y = 0; y < BOARD_SIZE; y++) 668 + if (game.board[x][y] == SWEEPING) 669 + game.board[x][y] = EMPTY; 670 + } 671 + 672 + bool 673 + place_shape(void) 674 + { 675 + const shape *s = &shapes[game.curshape]; 676 + byte x, y; 677 + int c; 678 + bool swept = false; 679 + 680 + if (!shape_clear(s, game.x, game.y)) 681 + return false; 682 + 683 + for (y = 0; y < s->height; y++) { 684 + for (x = 0; x < s->width; x++) { 685 + if (s->tiles[x + (y * s->width)] != EMPTY) { 686 + game.board[game.x + x][game.y + y] = 687 + s->tiles[x + (y * s->width)]; 688 + 689 + game.score++; 690 + } 691 + } 692 + } 693 + 694 + /* 695 + * Sweep through each row, then each column, and mark any completed 696 + * rows or columns as such. Then sweep through again and clear them 697 + * out. 698 + * 699 + * This must be done twice because otherwise when a column and row are 700 + * both complete, clearing out one would break the completion of the 701 + * other one. 702 + */ 703 + for (y = 0; y < BOARD_SIZE; y++) { 704 + for (x = 0, c = 0; x < BOARD_SIZE; x++) 705 + if (game.board[x][y] != EMPTY) 706 + c++; 707 + 708 + if (c == BOARD_SIZE) { 709 + /* complete row, empty */ 710 + for (x = 0; x < BOARD_SIZE; x++) { 711 + game.board[x][y] = SWEEPING; 712 + game.score++; 713 + swept = true; 714 + } 715 + } 716 + } 717 + 718 + for (x = 0; x < BOARD_SIZE; x++) { 719 + for (y = 0, c = 0; y < BOARD_SIZE; y++) 720 + if (game.board[x][y] != EMPTY) 721 + c++; 722 + 723 + if (c == BOARD_SIZE) { 724 + /* complete column, empty */ 725 + for (y = 0; y < BOARD_SIZE; y++) { 726 + game.board[x][y] = SWEEPING; 727 + game.score++; 728 + swept = true; 729 + } 730 + } 731 + } 732 + 733 + if (swept) 734 + explode_swept(); 735 + 736 + if (game.score > game.hiscore) 737 + game.hiscore = game.score; 738 + 739 + game.curshape = 0; 740 + new_shapes(); 741 + 742 + /* auto-highlight the next available on-deck piece */ 743 + for (x = 0; x < ONDECK; x++) 744 + if (game.ondeck[x] != 0) { 745 + game.ondecksel = x; 746 + break; 747 + } 748 + 749 + save_game(); 750 + 751 + /* if there is only one piece left and it can't be placed, don't bother 752 + * waiting for the user to select it */ 753 + if (left_ondeck() == 1 && 754 + !move_to_clear(&shapes[game.ondeck[game.ondecksel]])) { 755 + game_over(); 756 + return false; 757 + } 758 + 759 + return true; 760 + }