chessboard.ino 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. #include <SPI.h>
  2. #include <GD.h>
  3. #include "Wood32.h"
  4. #include "staunton.h" // Chess pieces from eboard's Staunton set: http://www.bergo.eng.br
  5. #define digits (sizeof(staunton_img) / 256)
  6. #include "digits.h"
  7. int atxy(int x, int y)
  8. {
  9. return (y << 6) + x;
  10. }
  11. static void square(byte x, byte y, byte light)
  12. {
  13. flash_uint8_t *src = Wood32_pic + (16 * light);
  14. int addr = atxy(x, y);
  15. GD.copy(addr + 0 * 64, src, 4);
  16. GD.copy(addr + 1 * 64, src + 4, 4);
  17. GD.copy(addr + 2 * 64, src + 8, 4);
  18. GD.copy(addr + 3 * 64, src + 12, 4);
  19. }
  20. #define QROOK 0
  21. #define QKNIGHT 1
  22. #define QBISHOP 2
  23. #define QUEEN 3
  24. #define KING 4
  25. #define KBISHOP 5
  26. #define KKNIGHT 6
  27. #define KROOK 7
  28. #define PAWN 8
  29. #define WHITE 0x00
  30. #define BLACK 0x10
  31. static char board[32];
  32. static void startboard()
  33. {
  34. byte i;
  35. for (i = 0; i < 8; i++) {
  36. board[i] = 56 + i;
  37. board[8+i] = 48 + i;
  38. board[16+i] = i;
  39. board[24+i] = 8 + i;
  40. }
  41. }
  42. // Return the piece at pos, or -1 if pos is empty
  43. static char find(byte pos)
  44. {
  45. byte slot;
  46. for (slot = 0; slot < 32; slot++)
  47. if (board[slot] == pos)
  48. return slot;
  49. return -1;
  50. }
  51. byte images[16] = { 0, 1, 2, 3, 4, 2, 1, 0, 5, 5, 5, 5, 5, 5, 5, 5 };
  52. static void piece(byte slot, int x, int y)
  53. {
  54. byte i = (4 * slot);
  55. byte j = images[slot & 0xf] * 2;
  56. byte bw = (slot >> 4) & 1;
  57. GD.sprite(i, x, y, j, bw, 0);
  58. GD.sprite(i + 1, x + 16, y, j + 1, bw, 0);
  59. GD.sprite(i + 2, x, y + 16, j + 12, bw, 0);
  60. GD.sprite(i + 3, x + 16, y + 16, j + 13, bw, 0);
  61. }
  62. #define BOARDX(pos) (8 + (((pos) & 7) << 5))
  63. #define BOARDY(pos) (24 + ((((pos) >> 3) & 7) << 5))
  64. static void drawboard()
  65. {
  66. byte slot;
  67. for (slot = 0; slot < 32; slot++) {
  68. char pos = board[slot];
  69. if (pos < 0)
  70. piece(slot, 400, 400);
  71. else {
  72. piece(slot, BOARDX(pos), BOARDY(pos));
  73. }
  74. }
  75. }
  76. static float smoothstep(float x)
  77. {
  78. return x*x*(3-2*x);
  79. }
  80. static int screenshot_i; // JCB
  81. // move piece 'slot' to position 'pos'.
  82. // return true if a piece was taken.
  83. static byte movepiece(byte slot, byte pos)
  84. {
  85. int x0 = BOARDX(board[slot]);
  86. int y0 = BOARDY(board[slot]);
  87. int x1 = BOARDX(pos);
  88. int y1 = BOARDY(pos);
  89. // move at 1.5 pix/frame
  90. int d = int(sqrt(pow(x0 - x1, 2) + pow(y0 - y1, 2)) / 2);
  91. int it;
  92. for (it = 0; it < d; it++) {
  93. float t = smoothstep(float(it) / d);
  94. GD.waitvblank();
  95. GD.waitvblank();
  96. // GD.screenshot(screenshot_i++); // JCB
  97. piece(slot, int(x0 + t * (x1 - x0)), int(y0 + t * (y1 - y0)));
  98. }
  99. byte taken = find(pos) != -1;
  100. if (taken)
  101. board[find(pos)] = -1;
  102. board[slot] = pos;
  103. drawboard();
  104. return taken;
  105. }
  106. void setup()
  107. {
  108. int i, j;
  109. Serial.begin(1000000); // JCB
  110. GD.begin();
  111. GD.ascii();
  112. GD.putstr(0, 0, "Chess board");
  113. GD.copy(RAM_CHR, Wood32_chr, sizeof(Wood32_chr));
  114. GD.copy(RAM_PAL, Wood32_pal, sizeof(Wood32_pal));
  115. GD.copy(RAM_SPRIMG, staunton_img, sizeof(staunton_img));
  116. GD.copy(RAM_SPRPAL, staunton_white, sizeof(staunton_white));
  117. GD.copy(RAM_SPRPAL + 512, staunton_black, sizeof(staunton_black));
  118. GD.copy(RAM_SPRIMG + (digits << 8), digits_img, sizeof(digits_img));
  119. GD.copy(RAM_SPRPAL + 2 * 512, digits_pal, sizeof(digits_pal));
  120. for (i = 0; i < 256; i++) {
  121. unsigned int b = GD.rd16(RAM_SPRPAL + 2 * 512 + 2 * i);
  122. GD.wr16(RAM_SPRPAL + 3 * 512 + 2 * i, b ^ 0x7fff);
  123. }
  124. // Draw the 64 squares of the board
  125. for (i = 0; i < 8; i++)
  126. for (j = 0; j < 8; j++)
  127. square(1 + (i << 2), 3 + (j << 2), (i ^ j) & 1);
  128. // Draw the rank and file markers 1-8 a-h
  129. for (i = 0; i < 8; i++) {
  130. GD.wr(atxy(3 + (i << 2), 2), 'a' + i);
  131. GD.wr(atxy(3 + (i << 2), 35), 'a' + i);
  132. GD.wr(atxy(0, 5 + (i << 2)), '8' - i);
  133. GD.wr(atxy(33, 5 + (i << 2)), '8' - i);
  134. }
  135. startboard();
  136. drawboard();
  137. }
  138. static int clock[2];
  139. // draw digit d in sprite slots spr,spr+1 at (x,y)
  140. static void digit(byte spr, byte d, byte bw, int x, int y)
  141. {
  142. GD.sprite(spr, x, y, digits + d, 2 + bw, 0);
  143. GD.sprite(spr + 1, x, y + 16, digits + d + 11, 2 + bw, 0);
  144. }
  145. static void showclock(byte bw)
  146. {
  147. int t = clock[bw];
  148. byte spr = 128 + (bw * 16);
  149. byte s = t % 60;
  150. int y = (bw ? 31 : 3) * 8;
  151. byte d0 = s % 10; s /= 10;
  152. digit(spr, d0, bw, 400 - 1 * 16, y);
  153. digit(spr + 2, s, bw, 400 - 2 * 16, y);
  154. digit(spr + 4, 10, bw, 400 - 3 * 16, y); // colon
  155. spr += 6;
  156. int x = 400 - 4 * 16;
  157. byte m = t / 60;
  158. do {
  159. d0 = m % 10; m /= 10;
  160. digit(spr, d0, bw, x, y);
  161. spr += 2;
  162. x -= 16;
  163. } while (m);
  164. }
  165. static int turn;
  166. #define ALG(r,f) ((r - 'a') + ((8 - f) * 8))
  167. #define CASTLE 255,255
  168. static byte game[] = {
  169. ALG('e', 2),ALG('e', 4), ALG('e', 7),ALG('e', 5),
  170. ALG('g', 1),ALG('f', 3), ALG('b', 8),ALG('c', 6),
  171. ALG('f', 1),ALG('b', 5), ALG('a', 7),ALG('a', 6),
  172. ALG('b', 5),ALG('a', 4), ALG('g', 8),ALG('f', 6),
  173. ALG('d', 1),ALG('e', 2), ALG('b', 7),ALG('b', 5),
  174. ALG('a', 4),ALG('b', 3), ALG('f', 8),ALG('e', 7),
  175. ALG('c', 2),ALG('c', 3), CASTLE,
  176. CASTLE, ALG('d', 7),ALG('d', 5),
  177. ALG('e', 4),ALG('d', 5), ALG('f', 6),ALG('d', 5),
  178. ALG('f', 3),ALG('e', 5), ALG('d', 5),ALG('f', 4),
  179. ALG('e', 2),ALG('e', 4), ALG('c', 6),ALG('e', 5),
  180. ALG('e', 4),ALG('a', 8), ALG('d', 8),ALG('d', 3),
  181. ALG('b', 3),ALG('d', 1), ALG('c', 8),ALG('h', 3),
  182. ALG('a', 8),ALG('a', 6), ALG('h', 3),ALG('g', 2),
  183. ALG('f', 1),ALG('e', 1), ALG('d', 3),ALG('f', 3),
  184. };
  185. static void putalg(byte x, byte y, byte a)
  186. {
  187. GD.wr(atxy(x, y), 'a' + (a & 7));
  188. GD.wr(atxy(x+1, y), '8' - ((a >> 3) & 7));
  189. }
  190. void loop()
  191. {
  192. byte i;
  193. for (i = random(25); i; i--) {
  194. clock[(1 & turn) ^ 1]++;
  195. GD.waitvblank();
  196. showclock(0);
  197. showclock(1);
  198. delay(20);
  199. // GD.screenshot(screenshot_i++); // JCB
  200. }
  201. if (turn < (sizeof(game) / 2)) {
  202. byte yy = 8 + (turn >> 1);
  203. byte xx = (turn & 1) ? 44 : 38;
  204. byte i = 1 + (turn >> 1);
  205. if (i >= 10)
  206. GD.wr(atxy(35, yy), '0' + i / 10);
  207. GD.wr(atxy(36, yy), '0' + i % 10);
  208. GD.wr(atxy(37, yy), '.');
  209. byte from = game[2 * turn];
  210. byte to = game[2 * turn + 1];
  211. if (from != 255) {
  212. putalg(xx, yy, from);
  213. GD.wr(atxy(xx + 2, yy), movepiece(find(from), to) ? 'x' : '-');
  214. putalg(xx + 3, yy, to);
  215. } else {
  216. byte rank = (turn & 1) ? 8 : 1;
  217. movepiece(find(ALG('e', rank)), ALG('g', rank));
  218. movepiece(find(ALG('h', rank)), ALG('f', rank));
  219. GD.putstr(xx, yy, "O-O");
  220. }
  221. turn++;
  222. } else {
  223. delay(4000);
  224. setup();
  225. turn = 0;
  226. clock[0] = 0;
  227. clock[1] = 0;
  228. }
  229. }