PageRenderTime 44ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/system/sudoku/sudoku.c

https://bitbucket.org/bkueng/nuttx-apps
C | 577 lines | 457 code | 68 blank | 52 comment | 119 complexity | 53ed373e7c2cd4182825afdd924c3a38 MD5 | raw file
Possible License(s): BSD-3-Clause, BSD-2-Clause
  1. /****************************************************************************
  2. * apps/system/sudoku/sudoku.c
  3. *
  4. * Copyright (C) 2014 Gregory Nutt. All rights reserved.
  5. * Author: Gregory Nutt <gnutt@nuttx.org>
  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. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <stdint.h>
  39. #include <stdio.h>
  40. #include <string.h>
  41. #include "system/readline.h"
  42. /****************************************************************************
  43. * Pre-processor Definitions
  44. ****************************************************************************/
  45. #define NHISTORY 16
  46. /****************************************************************************
  47. * Private Types
  48. ****************************************************************************/
  49. struct sudoku_s
  50. {
  51. uint16_t canbe;
  52. uint16_t is;
  53. };
  54. typedef struct sudoku_s sudoku_t[81];
  55. /****************************************************************************
  56. * Private Data
  57. ****************************************************************************/
  58. static sudoku_t history[NHISTORY];
  59. static sudoku_t working;
  60. static int first;
  61. static int last;
  62. static int current;
  63. static const char *r1[8] =
  64. {" ", "1 ", " 2 ", "12 ", " 3", "1 3", " 23", "123" };
  65. static const char *r2[8] =
  66. {" ", "4 ", " 5 ", "45 ", " 6", "4 6", " 56", "456" };
  67. static const char *r3[8] =
  68. {" ", "7 ", " 8 ", "78 ", " 9", "7 9", " 89", "789" };
  69. static char line[256];
  70. static int nis = 0;
  71. /****************************************************************************
  72. * Private Functions
  73. ****************************************************************************/
  74. static inline void init_array(void)
  75. {
  76. int i;
  77. first = 0;
  78. last = 0;
  79. current = 0;
  80. for (i = 0; i < 81; i++)
  81. {
  82. working[i].canbe = 0x1ff;
  83. working[i].is = 0x000;
  84. }
  85. }
  86. static inline void push(void)
  87. {
  88. int next = current + 1;
  89. if (next >= NHISTORY) next = 0;
  90. if (current == last)
  91. {
  92. last = next;
  93. }
  94. if (first == next)
  95. {
  96. if (++first >= NHISTORY) first = 0;
  97. }
  98. memcpy (history[current], working, sizeof(sudoku_t));
  99. current = next;
  100. }
  101. static inline void undo(void)
  102. {
  103. if (current == first)
  104. {
  105. printf("Cannot undo\n");
  106. }
  107. else
  108. {
  109. if (--current < 0) current = NHISTORY-1;
  110. memcpy (working, history[current], sizeof(sudoku_t));
  111. }
  112. }
  113. static inline void redo(void)
  114. {
  115. if (current == last)
  116. {
  117. printf("Cannot redo\n");
  118. }
  119. else
  120. {
  121. if (++current >= NHISTORY) current = 0;
  122. memcpy(working, history[current], sizeof(sudoku_t));
  123. }
  124. }
  125. static inline void show_row(int row)
  126. {
  127. printf(" |%3s|%3s|%3s| |%3s|%3s|%3s| |%3s|%3s|%3s|\n",
  128. r1[working[9*row + 0].canbe & 0x007],
  129. r1[working[9*row + 1].canbe & 0x007],
  130. r1[working[9*row + 2].canbe & 0x007],
  131. r1[working[9*row + 3].canbe & 0x007],
  132. r1[working[9*row + 4].canbe & 0x007],
  133. r1[working[9*row + 5].canbe & 0x007],
  134. r1[working[9*row + 6].canbe & 0x007],
  135. r1[working[9*row + 7].canbe & 0x007],
  136. r1[working[9*row + 8].canbe & 0x007]);
  137. printf(" %2d |%3s|%3s|%3s| |%3s|%3s|%3s| |%3s|%3s|%3s|\n", row + 1,
  138. r2[(working[9*row + 0].canbe >> 3) & 0x007],
  139. r2[(working[9*row + 1].canbe >> 3) & 0x007],
  140. r2[(working[9*row + 2].canbe >> 3) & 0x007],
  141. r2[(working[9*row + 3].canbe >> 3) & 0x007],
  142. r2[(working[9*row + 4].canbe >> 3) & 0x007],
  143. r2[(working[9*row + 5].canbe >> 3) & 0x007],
  144. r2[(working[9*row + 6].canbe >> 3) & 0x007],
  145. r2[(working[9*row + 7].canbe >> 3) & 0x007],
  146. r2[(working[9*row + 8].canbe >> 3) & 0x007]);
  147. printf(" |%3s|%3s|%3s| |%3s|%3s|%3s| |%3s|%3s|%3s|\n",
  148. r3[(working[9*row + 0].canbe >> 6) & 0x007],
  149. r3[(working[9*row + 1].canbe >> 6) & 0x007],
  150. r3[(working[9*row + 2].canbe >> 6) & 0x007],
  151. r3[(working[9*row + 3].canbe >> 6) & 0x007],
  152. r3[(working[9*row + 4].canbe >> 6) & 0x007],
  153. r3[(working[9*row + 5].canbe >> 6) & 0x007],
  154. r3[(working[9*row + 6].canbe >> 6) & 0x007],
  155. r3[(working[9*row + 7].canbe >> 6) & 0x007],
  156. r3[(working[9*row + 8].canbe >> 6) & 0x007]);
  157. }
  158. static inline void show_array(void)
  159. {
  160. int row;
  161. int i;
  162. printf(" +===+===+===+ +===+===+===+ +===+===+===+\n");
  163. printf(" | 1 | 2 | 3 | | 4 | 5 | 6 | | 7 | 8 | 9 |\n");
  164. printf(" +===+===+===+ +===+===+===+ +===+===+===+\n");
  165. row = 0;
  166. for (i = 0; i < 3; i++)
  167. {
  168. show_row(row++);
  169. printf(" +---+---+---+ +---+---+---+ +---+---+---+\n");
  170. show_row(row++);
  171. printf(" +---+---+---+ +---+---+---+ +---+---+---+\n");
  172. show_row(row++);
  173. printf(" +===+===+===+ +===+===+===+ +===+===+===+\n");
  174. }
  175. }
  176. static inline int is_unique(unsigned int val)
  177. {
  178. switch (val)
  179. {
  180. case 0x001:
  181. case 0x002:
  182. case 0x004:
  183. case 0x008:
  184. case 0x010:
  185. case 0x020:
  186. case 0x040:
  187. case 0x080:
  188. case 0x100:
  189. return 1;
  190. default:
  191. return 0;
  192. }
  193. }
  194. static inline int impossible(void)
  195. {
  196. int nchanges = 0;
  197. unsigned int val;
  198. int row1, col1;
  199. int row2, col2;
  200. int i, j;
  201. int ndx1, ndx2;
  202. for (row1 = 0; row1 < 9; row1++)
  203. {
  204. row2 = row1 / 3;
  205. for (col1 = 0; col1 < 9; col1++)
  206. {
  207. col2 = col1 / 3;
  208. ndx1 = row1*9 + col1;
  209. val = working[ndx1].canbe;
  210. for (i = 0; i < 9; i++)
  211. {
  212. ndx2 = i*9 + col1;
  213. if (ndx1 != ndx2)
  214. {
  215. val &= ~working[ndx2].is;
  216. }
  217. }
  218. for (j = 0; j < 9; j++)
  219. {
  220. ndx2 = row1*9 + j;
  221. if (ndx1 != ndx2)
  222. {
  223. val &= ~working[ndx2].is;
  224. }
  225. }
  226. for (i = 0; i < 3; i++)
  227. {
  228. for (j = 0; j < 3; j++)
  229. {
  230. ndx2 = (row2*3 + i)*9 + (col2*3 + j);
  231. if (ndx1 != ndx2)
  232. {
  233. val &= ~working[ndx2].is;
  234. }
  235. }
  236. }
  237. if (val == 0)
  238. {
  239. return -1;
  240. }
  241. if (val != working[ndx1].canbe)
  242. {
  243. nchanges++;
  244. working[ndx1].canbe = val;
  245. if (is_unique(val))
  246. {
  247. working[ndx1].is = val;
  248. }
  249. }
  250. }
  251. }
  252. return nchanges;
  253. }
  254. static inline int unique(void)
  255. {
  256. int noccurences[9];
  257. int lastndx[9];
  258. int nchanges = 0;
  259. unsigned int mask;
  260. unsigned int val;
  261. int row1, col1;
  262. int row2, col2;
  263. int ndx;
  264. int i;
  265. for (row1 = 0; row1 < 9; row1++)
  266. {
  267. for (i = 0; i < 9; i++)
  268. {
  269. noccurences[i] = 0;
  270. lastndx[i] = -1;
  271. }
  272. for (i = 0; i < 9; i++)
  273. {
  274. mask = 1 << i;
  275. for (col1 = 0; col1 < 9; col1++)
  276. {
  277. ndx = row1 * 9 + col1;
  278. if (working[ndx].canbe & mask)
  279. {
  280. noccurences[i]++;
  281. lastndx[i] = ndx;
  282. }
  283. }
  284. for (i = 0; i < 9; i++)
  285. {
  286. if (noccurences[i] == 1)
  287. {
  288. val = 1 << i;
  289. ndx = lastndx[i];
  290. if (working[ndx].is != val)
  291. {
  292. working[ndx].is = val;
  293. working[ndx].canbe = val;
  294. nchanges++;
  295. }
  296. }
  297. }
  298. }
  299. }
  300. for (col1 = 0; col1 < 9; col1++)
  301. {
  302. for (i = 0; i < 9; i++)
  303. {
  304. noccurences[i] = 0;
  305. lastndx[i] = -1;
  306. }
  307. for (i = 0; i < 9; i++)
  308. {
  309. mask = 1 << i;
  310. for (row1 = 0; row1 < 9; row1++)
  311. {
  312. ndx = row1 * 9 + col1;
  313. if (working[ndx].canbe & mask)
  314. {
  315. noccurences[i]++;
  316. lastndx[i] = ndx;
  317. }
  318. }
  319. for (i = 0; i < 9; i++)
  320. {
  321. if (noccurences[i] == 1)
  322. {
  323. val = 1 << i;
  324. ndx = lastndx[i];
  325. if (working[ndx].is != val)
  326. {
  327. working[ndx].is = val;
  328. working[ndx].canbe = val;
  329. nchanges++;
  330. }
  331. }
  332. }
  333. }
  334. }
  335. for (row2 = 0; row2 < 3; row2++)
  336. {
  337. for (col2 = 0; col2 < 3; col2++)
  338. {
  339. for (i = 0; i < 9; i++)
  340. {
  341. noccurences[i] = 0;
  342. lastndx[i] = -1;
  343. }
  344. for (i = 0; i < 9; i++)
  345. {
  346. mask = 1 << i;
  347. for ( row1 = 0; row1 < 3; row1++)
  348. {
  349. for ( col1 = 0; col1 < 3; col1++)
  350. {
  351. ndx = (row2*3 + row1)*9 + (col2*3 + col1);
  352. if (working[ndx].canbe & mask)
  353. {
  354. noccurences[i]++;
  355. lastndx[i] = ndx;
  356. }
  357. }
  358. }
  359. }
  360. for (i = 0; i < 9; i++)
  361. {
  362. if (noccurences[i] == 1)
  363. {
  364. val = 1 << i;
  365. ndx = lastndx[i];
  366. if (working[ndx].is != val)
  367. {
  368. working[ndx].is = val;
  369. working[ndx].canbe = val;
  370. nchanges++;
  371. }
  372. }
  373. }
  374. }
  375. }
  376. return nchanges;
  377. }
  378. static inline int getcell(int *pndx, int *pval)
  379. {
  380. int row, col, ndx;
  381. unsigned int val;
  382. int i = 0;
  383. while ((line[i] == ' ' || line[i] == '\t') && (line[i] != '\0') && (line[i] != '\n')) i++;
  384. if (line[i] < '1' || line[i] > '9')
  385. {
  386. printf("Bad row: %c\n", line[i]);
  387. return -1;
  388. }
  389. row = line[i++] -'0' - 1;
  390. while ((line[i] == ' ' || line[i] == '\t') && (line[i] != '\0') && (line[i] != '\n')) i++;
  391. if (line[i] < '1' || line[i] > '9')
  392. {
  393. printf("Bad col: %c\n", line[i]);
  394. return -1;
  395. }
  396. col = line[i++] -'0' - 1;
  397. ndx = row*9 + col;
  398. while ((line[i] == ' ' || line[i] == '\t') && (line[i] != '\0') && (line[i] != '\n')) i++;
  399. if (line[i] < '1' || line[i] > '9')
  400. {
  401. printf("Bad value: %c\n", line[i]);
  402. return -1;
  403. }
  404. val = 1 << ((line[i] - '0') - 1);
  405. if (( val & working[ndx].canbe) == 0)
  406. {
  407. printf("Impossible value: %c\n", line[i]);
  408. return -1;
  409. }
  410. *pndx = ndx;
  411. *pval = val;
  412. return 0;
  413. }
  414. static inline int get_command(void)
  415. {
  416. printf("%d of 81> ", nis);
  417. fflush(stdout);
  418. (void)readline(line, 256, stdin, stdout);
  419. int i = 0;
  420. while ((line[i] == ' ' || line[i] == '\t') && (line[i] != '\0') && (line[i] != '\n')) i++;
  421. return line[i];
  422. }
  423. static inline void show_usage(void)
  424. {
  425. printf("ABC - Set cell[A,B] to C where A,B, and C are in {1..9}\n");
  426. printf("U - Undo last cell assignment\n");
  427. printf("R - Redo last cell assignment\n");
  428. printf("H|? - Show this message\n");
  429. printf("Q - Quit\n");
  430. }
  431. static inline void count_cells(void)
  432. {
  433. int i;
  434. nis = 0;
  435. for (i = 0; i < 81; i++) if (working[i].is > 0) nis++;
  436. }
  437. /****************************************************************************
  438. * Private Functions
  439. ****************************************************************************/
  440. #ifdef CONFIG_BUILD_KERNEL
  441. int main(int argc, FAR char *argv[])
  442. #else
  443. int sudoku_main(int argc, char **argv, char **envp)
  444. #endif
  445. {
  446. int cmd;
  447. int nchanged;
  448. int val;
  449. int ndx;
  450. init_array();
  451. for (;;)
  452. {
  453. count_cells();
  454. show_array();
  455. if (nis == 81)
  456. {
  457. printf("GAME OVER: 81 of 81 assigned\n");
  458. return 0;
  459. }
  460. else
  461. {
  462. cmd = get_command();
  463. switch (cmd)
  464. {
  465. case 'U':
  466. case 'u':
  467. undo();
  468. break;
  469. case 'R':
  470. case 'r':
  471. redo();
  472. break;
  473. case 'H':
  474. case 'h':
  475. case '?':
  476. show_usage();
  477. break;
  478. case 'Q':
  479. case 'q':
  480. return 0;
  481. default:
  482. if (getcell(&ndx, &val) == 0)
  483. {
  484. push();
  485. working[ndx].is = val;
  486. working[ndx].canbe = val;
  487. for (;;)
  488. {
  489. nchanged = impossible();
  490. if (nchanged < 0)
  491. {
  492. printf("This move is not possible\n");
  493. undo();
  494. break;
  495. }
  496. else if (nchanged == 0)
  497. {
  498. nchanged = unique();
  499. if (nchanged == 0)
  500. {
  501. break;
  502. }
  503. }
  504. }
  505. }
  506. }
  507. }
  508. }
  509. }