littterate.w 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. \datethis
  2. @* Notice.
  3. This program is not yet completed. It won't even compile yet and has
  4. not been evaluated for valid CWEB syntax.
  5. @* Copying.
  6. Copyright (C) 2015 David McMackins II.
  7. Copyright (C) 2015 Caleb Herbert.
  8. This program is free software: you can redistribute it and/or modify
  9. it under the terms of the GNU Affero General Public License as
  10. published by the Free Software Foundation, version 3 only.
  11. This program is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. Affero General Public License for more details.
  15. You should have received a copy of the GNU Affero General Public
  16. License along with this program. If not, see
  17. <http://www.gnu.org/licenses/>.
  18. @* Introduction.
  19. David McMackns (a.k.a. ``Zerock'', a.k.a. ``VRMac'') wrote a little
  20. tic-tac-toe program for instructing pupils in the C programming
  21. language. It is a very simple program and has only has six parts.
  22. The basic structure of the program is outlined below.
  23. @c
  24. @<includes@> @/
  25. @<|get_bump| function@> @/
  26. @<|find_winner| function@> @/
  27. @<|get_move| function@> @/
  28. @<|draw_board| function@> @/
  29. @<|is_winner| function@> @/
  30. @* History.
  31. ttt was designed and written in response to a challenge from a
  32. colleague of David McMackins who wrote a console tic-tac-toe game in
  33. C++. The code was (frankly) written sloppily, and the program's
  34. structure severely limited its modularity. Furthermore, it was
  35. dependent on external commands unique to Microsoft operating systems
  36. (such as `cls` to clear the console).
  37. McMackins decided he would rewrite the game using clean C code,
  38. require no outside dependencies (besides the standard C library), and
  39. allow a board of variable size. He achieved a program with significant
  40. improvements in runtime efficiency (measured with controlled tests and
  41. inputs on one machine) which could be recompiled to use different
  42. board sizes.
  43. McMackins is very pleased with the result, and he now uses this as a
  44. test program when developing on new systems.
  45. @* Usefulness
  46. This program makes for an advanced ``hello world'' program for aspiring hackers
  47. that want a good sample to study and change.
  48. The C code complies with GNU and C standards, and it can be compiled and run on
  49. any compliant system. It makes use of several standard library features and
  50. showcases their uses. Since the code is documented using a standard format,
  51. readers can understand a functions purpose before reading it, thus better
  52. understanding the code as a whole.
  53. I used GNU Make to automate compilation not because it is hard (I could easily
  54. have written the instructions in this README file) but as a "hello world" for
  55. Makefiles, since hackers will no doubt need build automation tools for their
  56. more significant software.
  57. Since the source is controlled using Git, I also provided a way for new hackers
  58. to practice using Git and learn the advantages to source control. It also
  59. allows them to easily submit their changes and improvements to me to benefit
  60. future hackers.
  61. Lastly, I included a license file which describes the core ideals of free
  62. (libre) software, which I find to be very important for both new and
  63. experienced computer users everywhere.
  64. @* Includes.
  65. This program includes seven (7) standard C header files for its
  66. functions. It uses |stdio.h|, the ``standard input/output'' header,
  67. which deals with basic interactions with a textual terminal; |time.h|,
  68. the ``[foo]'' header, which [foo]; |stdlib.h|, the ``standard
  69. library'' header, which [foo]; |string.h|, the ``string'' header,
  70. which [foo]; |stdbool.h|, the ``standard boolean'' header, which
  71. allows one to use words like |true| and |false|; |ctype.h|, the
  72. ``[foo]'' header, which [foo]; and finally, |stdint.h|, the ``[foo]''
  73. header, which [foo].
  74. @<includes@>=
  75. #include <stdio.h>
  76. #include <time.h>
  77. #include <stdlib.h>
  78. #include <string.h>
  79. #include <stdbool.h>
  80. #include <ctype.h>
  81. #include <stdint.h>
  82. #ifndef BOARD_SIZE
  83. /**
  84. * @brief The square dimensions of the game board (best when >=1 and <=26).
  85. */
  86. # define BOARD_SIZE 3
  87. #endif
  88. @* |get_bump| function
  89. The source code for |get_bump| is as follows.
  90. @<|get_bump| function@>=
  91. static uint8_t
  92. get_bump (uint8_t s)
  93. {
  94. uint8_t i = 1;
  95. while (s > 10)
  96. {
  97. ++i;
  98. s /= 10;
  99. }
  100. return i;
  101. }
  102. @* |find_winner| function
  103. The |find_winner| function is as follows.
  104. @<|find_winner| function@>=
  105. static char
  106. find_winner (void)
  107. {
  108. char players[] = {'X', 'O'};
  109. uint8_t i;
  110. for (i = 0; i < 2; ++i)
  111. if (is_winner (players[i]))
  112. return players[i];
  113. return 0;
  114. }
  115. @* |get_move| function
  116. The |get_move| function is as follows.
  117. @<|get_move| function@>=
  118. static struct move
  119. get_move (char player)
  120. {
  121. char h;
  122. struct move m = {
  123. .h = BOARD_SIZE,
  124. .v = BOARD_SIZE
  125. };
  126. printf ("%c's move: ", player);
  127. scanf ("%c%hhu", &h, &m.v);
  128. // discard extra input to prevent cheating
  129. while (getchar () != '\n')
  130. ;
  131. m.h = toupper (h) - 'A';
  132. return m;
  133. }
  134. @* |draw_board| function
  135. The |draw_board| function is as follows.
  136. @<|draw_board| function@>=
  137. static void
  138. draw_board (void)
  139. {
  140. uint8_t i, j, bump = get_bump (BOARD_SIZE);
  141. printf ("\n\n\n ");
  142. for (i = 0; i < bump; ++i)
  143. putchar (' ');
  144. for (i = 0; i < BOARD_SIZE; ++i)
  145. printf (" %c", i + 'A');
  146. putchar ('\n');
  147. for (i = 0; i < BOARD_SIZE; ++i)
  148. {
  149. printf ("%d", i);
  150. // make sure board lines up on all rows
  151. uint8_t b = bump - get_bump (i+1);
  152. for (j = 0; j < b; ++j)
  153. putchar (' ');
  154. printf (" |");
  155. for (j = 0; j < BOARD_SIZE; ++j)
  156. printf ("%c|", board[i][j]);
  157. putchar ('\n');
  158. }
  159. }
  160. @* |is_winner| function
  161. The |is_winner| function is as follows.
  162. @<|is_winner| function@>=
  163. static bool
  164. is_winner (char player)
  165. {
  166. int16_t i, j;
  167. // check rows
  168. for (i = 0; i < BOARD_SIZE; ++i)
  169. for (j = 0; j < BOARD_SIZE; ++j)
  170. {
  171. if (board[i][j] != player)
  172. break;
  173. if ((BOARD_SIZE - 1) == j)
  174. return true;
  175. }
  176. // check columns
  177. for (i = 0; i < BOARD_SIZE; ++i)
  178. for (j = 0; j < BOARD_SIZE; ++j)
  179. {
  180. if (board[j][i] != player)
  181. break;
  182. if ((BOARD_SIZE - 1) == j)
  183. return true;
  184. }
  185. // check diagonal from top-left to bottom-right
  186. for (i = 0, j = 0; i < BOARD_SIZE && j < BOARD_SIZE; ++i, ++j)
  187. {
  188. if (board[i][j] != player)
  189. break;
  190. if ((BOARD_SIZE - 1) == i)
  191. return true;
  192. }
  193. // check diagonal from top-right to bottom-left
  194. for (i = 0, j = BOARD_SIZE-1; i < BOARD_SIZE && j >= 0; ++i, --j)
  195. {
  196. if (board[i][j] != player)
  197. break;
  198. if (0 == j)
  199. return true;
  200. }
  201. return false;
  202. }