fork download
  1. /* -------------------------------------------------------------------------
  2.  * Title: Target Points v1.7
  3.  * From: migf1
  4.  * Description:
  5.  * a little gambling, board game in text mode, written in ANSI C (C99)
  6.  * see function: do_help() for details
  7.  * Change log:
  8.  * v1.7 - added "high-scores" support (playername, score, board size)
  9.  * - final score calculation now takes into account the board size too
  10.  * - game files saved with older versions are NOT compatible (delete them)
  11.  * v1.6: - added "reset game" functionality
  12.  * - better separation between user interface and lower level functions
  13.  * v1.5: - added "save game" and "load game" functionality
  14.  * - more compact code + better function names
  15.  * v1.0: original version
  16.  * -------------------------------------------------------------------------
  17.  */
  18.  
  19. #include <stdio.h>
  20. #include <string.h> // for strlen()
  21. #include <stdlib.h> // for srand(), atoi(), exit()
  22. #include <ctype.h> // for isdigit(), tolower(), toupper()
  23. #include <time.h> // for time() (used in srand())
  24.  
  25. #define MAXINBUF 255+1 // max chars we read in the input buffer
  26. #define MAXFNAME 255+1 // max length for any filename
  27. #define MAXPNAME 6+1 // max length for any playername
  28.  
  29. #define GM_DEF_FNAME "targetpoints.dat" // default filename for saved game
  30. #define GM_MAXROWS 7 // gameboard's max height
  31. #define GM_MAXCOLS 7 // gameboard's max width
  32.  
  33. #define HS_DEF_FNAME "tphigh.dat" // default filename for saved high-scores
  34. #define HS_MAXSLOTS 5 // max capacity of the high-scores array
  35. #define HS_DEF_PNAME "empty" // default playername for high-scores
  36. #define HS_DEFSCORE -1 // default high-score
  37.  
  38. #define CREDITS() printf("%76s\n", "\"Target Points\" by migf1");
  39.  
  40. #define PROMPT(plr, mov, maxmovs, pts, maxpts) \
  41. printf("[%s] M:%d/%d, P:%d/%d> ", (plr), (mov+1), (maxmovs), (pts), (maxpts) )
  42.  
  43. #define PAUSE() \
  44. do{ \
  45. char myinbufr[255]=""; \
  46. printf("\npress ENTER..."); \
  47. fgets(myinbufr, 255, stdin); \
  48. }while(0)
  49.  
  50. typedef enum { FALSE=0, TRUE } Bool; // our custom boolean data type
  51.  
  52. // our own data type for errors
  53. typedef enum { ERR_NOERROR=0, ERR_FNAME, ERR_FFILE, ERR_FREAD, ERR_FWRITE } ErrCode;
  54.  
  55. typedef struct cell { // structure of any individual cell
  56. Bool avail; // is it available for selection?
  57. int pos; // cell's position in the board
  58. int val; // cell's value
  59. }Cell;
  60.  
  61. typedef struct gamestatus { // structure of the game itself
  62. char fname[ MAXFNAME ]; // filename for saved game
  63. char player[ MAXPNAME ]; // player name
  64. int boardrows, boardcols; // max rows & max cols of board
  65. Cell board[ GM_MAXROWS ][ GM_MAXCOLS ]; // the board
  66. int move, maxmoves; // current & max number of moves
  67. int points, maxpoints; // current & max number of points
  68. int score; // final score
  69. }GameStatus;
  70.  
  71. typedef struct hs { // structure of one high-score slot
  72. int maxpname; // max length of playername
  73. char player[ MAXPNAME ]; // player name
  74. int score; // player score
  75. int nrows, ncols; // board size
  76. }HS;
  77.  
  78. typedef struct hscores { // structure of the high-score file
  79. char fname[ MAXFNAME ]; // filename
  80. int maxlen; // maximum capacity of slots
  81. int len; // current len of filled slots
  82. HS array[ HS_MAXSLOTS ]; // list of high-scores
  83. }HScores;
  84.  
  85. // ---------------------------------------------------------------------------------
  86. // # Helper Function #
  87. // Read s from standard input
  88. //
  89. char *s_get(char *s, size_t len)
  90. {
  91. char *cp;
  92.  
  93. for (cp=s; (*cp=getc(stdin)) != '\n' && (cp-s) < len-1; cp++ )
  94. ; // for-loop with empty body
  95. *cp = '\0'; // null-terminate last character
  96.  
  97. return s;
  98. }
  99.  
  100. // ---------------------------------------------------------------------------------
  101. // # Helper Function #
  102. // Convert string s to uppercase
  103. //
  104. char *s_toupper(char *s)
  105. {
  106. char *ret;
  107.  
  108. for ( ret=s; (*s=toupper(*s)); s++ );
  109. return ret;
  110. }
  111.  
  112. // ---------------------------------------------------------------------------------
  113. // # Helper Function #
  114. // Trim leading & trailing spaces from s
  115. //
  116. char *s_trim( char *s )
  117. {
  118. char *cp1; // for parsing the whole s
  119. char *cp2; // for shifting & padding
  120.  
  121. // trim leading & shift left remaining
  122. for (cp1=s; isspace(*cp1); cp1++ ) // skip leading spaces, via cp1
  123. ;
  124. for (cp2=s; *cp1; cp1++, cp2++) // shift left remaining chars, via cp2
  125. *cp2 = *cp1;
  126. *cp2-- = '\0'; // mark end of left trimmed s
  127.  
  128. // replace trailing spaces with '\0's
  129. while ( cp2 > s && isspace(*cp2) )
  130. *cp2-- = '\0'; // pad with '\0'
  131.  
  132. return s;
  133. }
  134.  
  135. // ------------------------------------------------------------------------------------
  136. // # Helper Function #
  137. // Copy null-terminated string src to string dst (up to n-1 chars + '\0')
  138. //
  139. char *s_ncopy( char *dst, const char *src, int n )
  140. {
  141. char *ret = dst;
  142.  
  143. while ( (dst-ret) < n-1 && (*dst=*src) != '\0' )
  144. dst++, src++;
  145.  
  146. if ( *dst )
  147. *dst = 0;
  148.  
  149. return ret;
  150. }
  151.  
  152. // ---------------------------------------------------------------------------------
  153. // Read the player name from the standard input
  154. // IMPORTANT:
  155. // this function is used INSIDE the function: init_game()
  156. //
  157. char *get_playername( char *player, int maxpname )
  158. {
  159. if ( !player )
  160. return NULL;
  161.  
  162. int temp;
  163. char dummy[MAXINBUF] = "";
  164.  
  165. do {
  166. printf("\nPlayer name (%d chars, extras will be ignored)? ", maxpname-1);
  167. s_get(dummy, MAXINBUF);
  168. s_trim(dummy);
  169. temp = strlen(dummy);
  170. if ( temp+1 > maxpname)
  171. dummy[maxpname-1] = '\0';
  172. strcpy(player, dummy);
  173. } while ( !*player );
  174.  
  175. return s_toupper(player);
  176. }
  177.  
  178. // ---------------------------------------------------------------------------------
  179. // # Helper Function #
  180. // Read inbuf form the standard input, trim leading & trailing spaces and convert
  181. // its 1st character to lowercase
  182. //
  183. char *get_command( char *inbuf, int maxinbuf )
  184. {
  185. if ( !inbuf )
  186. return NULL;
  187.  
  188. s_get(inbuf, maxinbuf); // read inbuf
  189. s_trim( inbuf ); // trim & trailing spaces
  190. *inbuf = tolower( *inbuf ); // convert 1st char to lowercase
  191.  
  192. return inbuf; // return inbuf
  193.  
  194. }
  195.  
  196. // ---------------------------------------------------------------------------------
  197. // Initialize a single high-score entry
  198. //
  199. Bool hs_init( int maxpname, char *player, int score, int nrows, int ncols, HS *hs )
  200. {
  201. if ( !hs || !player )
  202. return FALSE;
  203.  
  204. hs->maxpname = maxpname;
  205. s_ncopy( hs->player, player, maxpname );
  206. hs->score = score;
  207. hs->nrows = nrows;
  208. hs->ncols = ncols;
  209.  
  210. return TRUE;
  211.  
  212. }
  213.  
  214. // ---------------------------------------------------------------------------------
  215. // Update a single high-score entry
  216. //
  217. Bool hs_update( char *player, int score, int nrows, int ncols, HS *hs )
  218. {
  219. if ( !hs || !player )
  220. return FALSE;
  221.  
  222. s_ncopy( hs->player, player, hs->maxpname );
  223. hs->score = score;
  224. hs->nrows = nrows;
  225. hs->ncols = ncols;
  226.  
  227. return TRUE;
  228.  
  229. }
  230. // ---------------------------------------------------------------------------------
  231. // Copy a single hi-score entry: src to another single hi-score entry: dst
  232. //
  233. Bool hs_copy( HS *dst, HS *src )
  234. {
  235. if ( !src || !dst )
  236. return FALSE;
  237.  
  238. dst->maxpname = src->maxpname;
  239. s_ncopy( dst->player, src->player, dst->maxpname );
  240. dst->score = src->score;
  241. dst->nrows = src->nrows;
  242. dst->ncols = src->ncols;
  243.  
  244. return TRUE;
  245. }
  246.  
  247. // ---------------------------------------------------------------------------------
  248. // Initialize the whole high-scores structure
  249. //
  250. void hscores_init( int maxhiscores, const char *filename, int maxfname, int maxpname, int nrows, int ncols, HScores *hscores )
  251. {
  252. register int i;
  253.  
  254. s_ncopy( hscores->fname, filename, maxfname); // init filename
  255. hscores->maxlen = maxhiscores; // init maxlen
  256. hscores->len = 0; // init len
  257. for (i=0; i < maxhiscores; i++) // init all slots
  258. hs_init( maxpname, "empty", -1, nrows, ncols, &hscores->array[i] );
  259.  
  260. return;
  261. }
  262.  
  263. // ---------------------------------------------------------------------------------
  264. // Check if single high-score entry: hs should get inserted into the high-scores array
  265. // Return the array index hs should get inserted at, otherwise retrun -1
  266. //
  267. int hscores_slotfind( HS *hs, HScores *hscores )
  268. {
  269. register int i;
  270. for (i=0; i < hscores->maxlen && hs->score < hscores->array[i].score; i++)
  271. ;
  272. if ( i < hscores->maxlen
  273. && hs->score == hscores->array[i].score
  274. && !strcmp(hs->player, hscores->array[i].player)
  275. && hs->nrows == hscores->array[i].nrows
  276. && hs->ncols == hscores->array[i].ncols
  277. )
  278. return -1;
  279.  
  280. return (i < hscores->maxlen) ? i : -1;
  281. }
  282.  
  283. // ---------------------------------------------------------------------------------
  284. // Insert single high-score entry: hs into the high-scores array, at slot: pos
  285. // Return pos, or -1 on error
  286. //
  287. int hscores_slotput( int pos, HS *hs, HScores *hscores )
  288. {
  289. if (pos < 0 || pos > hscores->maxlen-1) // invalid position
  290. return -1;
  291. /* // array is already full
  292. if ( hscores->array[hscores->maxlen-1].score != -1 )
  293. return -1;
  294. */
  295. if ( hscores->array[0].score == -1 ) { // array is empty
  296. hs_copy( &hscores->array[0], hs );
  297. hscores->len = 1;
  298. return 0;
  299. }
  300.  
  301. if ( pos > hscores->len-1 ) { // pos beyond len
  302. hs_copy( &hscores->array[ hscores->len ], hs );
  303. (hscores->len++);
  304. return hscores->len-1;
  305. }
  306.  
  307. // move elems to the right, starting from pos
  308. memmove(&hscores->array[pos+1], // to
  309. &hscores->array[pos], // from
  310. (hscores->maxlen-pos-1) * sizeof(HS) // size in bytes
  311. );
  312.  
  313. hs_copy( &hscores->array[pos], hs );
  314. (hscores->len)++;
  315.  
  316. return pos;
  317. }
  318.  
  319. // ---------------------------------------------------------------------------------
  320. // Higher level function for inserting a single high-score: hs into high-scores
  321. //
  322. Bool hscores_insert( HS *hs, HScores *hscores )
  323. {
  324. int pos = hscores_slotfind( hs, hscores );
  325. if ( pos == -1 )
  326. return FALSE;
  327.  
  328. hscores_slotput( pos, hs, hscores );
  329. return TRUE;
  330. }
  331.  
  332. // ---------------------------------------------------------------------------------
  333. // Read high-scores from file to memory
  334. //
  335. ErrCode hscores_load( HScores *hscores )
  336. {
  337. if ( !hscores->fname )
  338. return ERR_FNAME;
  339.  
  340. FILE *fp = fopen( hscores->fname, "rb" );
  341. if ( !fp )
  342. return ERR_FFILE;
  343.  
  344. if ( fread( hscores, sizeof( HScores ), 1, fp ) != 1 )
  345. return ERR_FREAD;
  346.  
  347. fclose( fp );
  348.  
  349. return ERR_NOERROR;
  350.  
  351. }
  352.  
  353. // ---------------------------------------------------------------------------------
  354. // Write high-scores from memory to file
  355. //
  356. ErrCode hscores_save( HScores *hscores )
  357. {
  358. if ( !hscores->fname )
  359. return ERR_FNAME;
  360.  
  361. FILE *fp = fopen( hscores->fname, "wb" );
  362. if ( !fp )
  363. return ERR_FFILE;
  364.  
  365. if ( fwrite( hscores, sizeof( HScores ), 1, fp ) != 1 )
  366. return ERR_FREAD;
  367.  
  368. fclose( fp );
  369.  
  370. return ERR_NOERROR;
  371.  
  372. }
  373.  
  374. // ---------------------------------------------------------------------------------
  375. // Display the high-scores table on the screen
  376. //
  377. void show_hscores( HScores *hscores )
  378. {
  379. register int i;
  380.  
  381. puts("\n\t---------------------------");
  382. printf("\tHIGH SCORES (TOP-%d)\n", hscores->maxlen);
  383. puts("\t---------------------------");
  384.  
  385. for (i=0; i < hscores->maxlen; i++) {
  386. printf( "\t%s\t%4d points\t%dx%d\n",
  387. hscores->array[i].player, hscores->array[i].score,
  388. hscores->array[i].nrows, hscores->array[i].ncols
  389. );
  390. }
  391. puts("\t---------------------------");
  392.  
  393. return;
  394. }
  395.  
  396. // ---------------------------------------------------------------------------------
  397. // Higher level function to load high-scores from file to memory when the game starts
  398. // (if file does not exist, it is created with default values). In either case, the
  399. // high-scores table is displayed on the screen.
  400. //
  401. void intro_hscores( HScores *hscores )
  402. {
  403. if ( hscores_load( hscores ) != ERR_NOERROR )
  404. {
  405. printf("\n\thigh-scores file was not found, creating a fresh one... ");
  406. if ( hscores_save( hscores ) == ERR_NOERROR )
  407. puts("succeeded");
  408. else
  409. puts("failed\n\t( default values are displayed )");
  410. }
  411. show_hscores( hscores );
  412.  
  413. return;
  414. }
  415.  
  416. // ---------------------------------------------------------------------------------
  417. // Higher level function used before the game exits. If neccessary, it inserts into
  418. // the high-scores the player's score, infroms him and displays the high-scores on
  419. // the screen.
  420. //
  421. void outro_hscores( HS hs, GameStatus *game, HScores *hscores )
  422. {
  423. hs_update( game->player, game->score, game->boardrows, game->boardcols, &hs );
  424. if ( hscores_insert( &hs, hscores ) ) {
  425. puts("\n\tCONGRATULATIONS, you made it into the HIGH SCORES");
  426. hscores_save( hscores );
  427. }
  428. show_hscores( hscores );
  429.  
  430. return;
  431. }
  432.  
  433. // ---------------------------------------------------------------------------------
  434. // Initialize all cells of the board with default values (avail, pos, val).
  435. // Return the sum of all random generated cell-vallues
  436. //
  437. int init_board( int nrows, int ncols, Cell board[nrows][ncols] )
  438. {
  439. register int i,j;
  440. int valsum = 0;
  441.  
  442. for (i=0; i < nrows; i++)
  443. {
  444. for (j=0; j < ncols; j++) {
  445. board[i][j].avail = TRUE;
  446. board[i][j].pos = i * ncols + j;
  447. board[i][j].val = rand() % (nrows*ncols);
  448. valsum += board[i][j].val;
  449. }
  450. }
  451.  
  452. return valsum;
  453. }
  454.  
  455. // ---------------------------------------------------------------------------------
  456. // Initialize the game (note: high-scores are treated elsewhere)
  457. //
  458. void init_game( int nrows, int ncols, const char *filename, int maxfname, int maxpname, GameStatus *game )
  459. {
  460. s_ncopy( game->fname, filename, maxfname); // init filename
  461. get_playername( game->player, maxpname ); // read player name
  462. game->move = 0; // init current move
  463. game->maxmoves = (nrows * ncols) / 2; // init maxmoves
  464. game->points = 0; // init current points
  465.  
  466. // init board related fields
  467. game->boardrows = nrows; // init board rows
  468. game->boardcols = ncols; // init board cols
  469. // init both maxpoints and board cells
  470. game->maxpoints = init_board( nrows, ncols, game->board ) / 2;
  471.  
  472. game->score = 0; // init final score
  473.  
  474. return;
  475. }
  476.  
  477. // ---------------------------------------------------------------------------------
  478. // Reset the game
  479. // It differs than init_game() in that this one leaves intact the playername and the
  480. // filename. It resets all moves and points though, and it re-populates the cell values
  481. //
  482. void reset_game( GameStatus *game )
  483. {
  484. game->move = 0; // init curr move
  485. game->maxmoves = (game->boardrows * game->boardcols) / 2; // init maxmoves
  486. game->points = 0; // init curr pts
  487.  
  488. game->maxpoints = // init both maxpoints and board cells
  489. init_board( game->boardrows, game->boardcols, game->board ) / 2;
  490.  
  491. game->score = 0; // final score
  492.  
  493. return;
  494. }
  495.  
  496. // ---------------------------------------------------------------------------------
  497. // Save the game
  498. //
  499. ErrCode save_game( GameStatus *game )
  500. {
  501. if ( !game->fname )
  502. return ERR_FNAME;
  503.  
  504. FILE *fp = fopen(game->fname, "wb");
  505. if ( !fp )
  506. return ERR_FFILE;
  507.  
  508. if ( fwrite( game, sizeof( GameStatus ), 1, fp ) != 1 )
  509. return ERR_FWRITE;
  510.  
  511. fclose( fp );
  512.  
  513. return ERR_NOERROR;
  514. }
  515.  
  516. // ---------------------------------------------------------------------------------
  517. // Load a game
  518. //
  519. ErrCode load_game( GameStatus *game )
  520. {
  521. if ( !game->fname )
  522. return ERR_FNAME;
  523.  
  524. FILE *fp = fopen(game->fname, "rb");
  525. if ( !fp )
  526. return ERR_FFILE;
  527.  
  528. if ( fread( game, sizeof( GameStatus ), 1, fp ) != 1 )
  529. return ERR_FREAD;
  530.  
  531. fclose( fp );
  532.  
  533. return ERR_NOERROR;
  534. }
  535.  
  536. // ---------------------------------------------------------------------------------
  537. /*** DISABLED: UNUSED
  538.  
  539. void draw_cells( int nrows, int ncols, Cell board[nrows][ncols] )
  540. {
  541. register int i,j;
  542.  
  543. for (i=0; i<nrows; i++)
  544. {
  545. for (j=0; j < ncols; j++)
  546. printf("+---");
  547. puts("+");
  548. for (j=0; j < ncols; j++)
  549. printf("| %2d ", board[i][j].val);
  550. puts("|");
  551. }
  552. for (j=0; j < ncols; j++)
  553. printf("+---");
  554. puts("+");
  555.  
  556. return;
  557. }
  558. ***/
  559.  
  560. // ---------------------------------------------------------------------------------
  561. // Draw the board diagrams on the screen, the left one with available posistions,
  562. // the right one with already selected cell-values (if cheat is TRUE, the right
  563. // diagram shows ALL cell-values, instead).
  564. //
  565. void show_board( GameStatus *game, Bool cheat )
  566. {
  567. register int i,j;
  568.  
  569. for (i=0; i < game->boardrows; i++)
  570. {
  571. for (j=0; j < game->boardcols; j++)
  572. printf("|----");
  573. printf("|\t");
  574. for (j=0; j < game->boardcols; j++)
  575. printf("-----");
  576. puts("-");
  577.  
  578. for (j=0; j < game->boardcols; j++)
  579. {
  580. if ( game->board[i][j].avail )
  581. printf("| %2d ", game->board[i][j].pos);
  582. else
  583. printf("| ## ");
  584. }
  585. printf("|\t");
  586. for (j=0; j < game->boardcols; j++)
  587. {
  588. if ( game->board[i][j].avail && !cheat)
  589. printf("| ");
  590. else
  591. printf("| %2d ", game->board[i][j].val);
  592. }
  593. puts("|");
  594. }
  595. for (j=0; j < game->boardcols; j++)
  596. printf("|----");
  597. printf("|\t");
  598. for (j=0; j < game->boardcols; j++)
  599. printf("-----");
  600. puts("-");
  601.  
  602. return;
  603. }
  604.  
  605. // ---------------------------------------------------------------------------------
  606. // Handle the "help" command: h
  607. //
  608. void do_help( void )
  609. {
  610. puts("\n\tThis is a little gambling game written in ANSI C, by migf1.");
  611.  
  612. puts("\n\tYour task is to collect the target amount of points in as many");
  613. puts("\tmoves as the half of the total cells of the board.");
  614.  
  615. puts("\n\tCells are initially populated with random values ranging from");
  616. puts("\t0 to the total number of cells - 1 (e.g.: from 0 to 48 for a");
  617. puts("\t7x7 board). Duplicated values may appear in two or more cells.");
  618. puts("\tThe target amount of points you are after, equals to the half");
  619. puts("\tof the sum of all those values (sum of values / 2)");
  620.  
  621. puts("\n\tTo choose a cell you enter its positioning number, as shown");
  622. puts("\tin the left diagram. The value it holds will appear in the");
  623. puts("\tright diagram and it will be added to your current points.");
  624.  
  625. puts("\n\tIf you run out of moves before collecting the target amount");
  626. puts("\tof points, the game ends and you get 0 score. If you manage");
  627. puts("\tto collect the points before running out of moves, then the");
  628. puts("\tpoints collected beyond the targeted amount are multiplied");
  629. puts("\tby the moves you had left, and the result is your score");
  630.  
  631. puts("\n\tThe prompt always shows your current move and points, along");
  632.  
  633. PAUSE();
  634.  
  635. puts("\n\twith the moves you have left, and the targeted amount of");
  636. puts("\tpoints to be gathered. So make sure you check it regularly");
  637. puts("\t(M stands for move, P for points).");
  638.  
  639. puts("\n\tYou can also use the following commands at the prompt:");
  640. puts("");
  641. puts("\th\tthis help you are reading right now");
  642. puts("\ti\tshow high-scores");
  643. puts("\tt\tshow current stats");
  644. puts("\ts\tsave current game");
  645. puts("\tl\tload previously saved game (current game data get erased!)");
  646. puts("\tr\treset game (everything but the playername are reset)");
  647. puts("\tx\texit the game (note: you'll get 0 score!)");
  648.  
  649. puts("\n\tThe game ends either when you run out of moves, you enter");
  650. puts("\tx at the prompt, or you gather more points than the targeted");
  651. puts("\tamount (equal or more). In any case, all the cell-values will");
  652. puts("\tbe revealed in the right diagram, just before the termination");
  653. puts("\tof the program.");
  654.  
  655. puts("\n\tHave fun!");
  656.  
  657. PAUSE();
  658.  
  659. return;
  660. }
  661.  
  662. // ---------------------------------------------------------------------------------
  663. // Handle the "show high-scores" command: i
  664. //
  665. void do_hiscores( HScores *hscores )
  666. {
  667. show_hscores( hscores );
  668. return;
  669. }
  670.  
  671. // ---------------------------------------------------------------------------------
  672. // Handle the "stats" command: t
  673. //
  674. void do_stats( GameStatus *game )
  675. {
  676. printf( "\n\tyou've made %d move(s), having collected %d points\n",
  677. game->move, game->points );
  678. printf( "\tyou have %d move(s) left, to collect %d more point(s)\n\n",
  679. game->maxmoves - game->move, game->maxpoints - game->points
  680. );
  681.  
  682. return;
  683. }
  684.  
  685. // ---------------------------------------------------------------------------------
  686. // Handle the "save game" command: s
  687. //
  688. Bool do_savegame( GameStatus *game )
  689. {
  690. char inbuf[MAXINBUF] = "";
  691. ErrCode errcode;
  692.  
  693. printf("you are about to save the game, please confirm (y/) ");
  694. get_command(inbuf, MAXINBUF);
  695. if ( !*inbuf || *inbuf != 'y' ) {
  696. puts("\n\tsaving the game aborted by the user\n");
  697. return FALSE;
  698. }
  699.  
  700. printf("\n\tsaving the game... ");
  701.  
  702. errcode = save_game( game );
  703.  
  704. if ( errcode == ERR_NOERROR ) {
  705. printf("succeeded\n\n");
  706. return TRUE;
  707. }
  708.  
  709. if ( errcode == ERR_FNAME )
  710. printf("failed (internal error)\n\n");
  711. else if ( errcode == ERR_FFILE )
  712. printf("failed (file not found)\n\n");
  713. else if ( errcode == ERR_FWRITE)
  714. printf("failed (write error)\n\n");
  715. else
  716. printf("failed (uknown error)\n\n");
  717.  
  718. return FALSE;
  719. }
  720.  
  721. // ---------------------------------------------------------------------------------
  722. // Handle the "load game" command: l
  723. //
  724. Bool do_loadgame( GameStatus *game )
  725. {
  726. char inbuf[MAXINBUF] = "";
  727. ErrCode errcode;
  728.  
  729. printf("loading a previous game will delete this one, please confirm (y/) ");
  730. get_command(inbuf, MAXINBUF);
  731. if ( !*inbuf || *inbuf != 'y' ) {
  732. puts("\n\tloading a previously saved game aborted by the user\n");
  733. return FALSE;
  734. }
  735.  
  736. printf("\n\tloading game... ");
  737.  
  738. errcode = load_game( game );
  739.  
  740. if ( errcode == ERR_NOERROR ) {
  741. printf("succeeded\n\n");
  742. return TRUE;
  743. }
  744.  
  745. if ( errcode == ERR_FNAME )
  746. printf("failed (internal error)\n\n");
  747. else if ( errcode == ERR_FFILE )
  748. printf("failed (file not found)\n\n");
  749. else if ( errcode == ERR_FREAD)
  750. printf("failed (read error)\n\n");
  751. else
  752. printf("failed (uknown error)\n\n");
  753.  
  754. return FALSE;
  755. }
  756.  
  757. // ---------------------------------------------------------------------------------
  758. // Handle the "reset game" command: r
  759. //
  760. Bool do_resetgame( GameStatus *game )
  761. {
  762. char inbuf[MAXINBUF] = "";
  763.  
  764. printf("reset game will erase all moves & cell-values, please confirm (y/) ");
  765. get_command(inbuf, MAXINBUF);
  766. if ( !*inbuf || *inbuf != 'y' ) {
  767. puts("\n\treset game aborted by the user\n");
  768. return FALSE;
  769. }
  770.  
  771. reset_game( game );
  772. puts("\n\tgame was reset\n");
  773.  
  774. return TRUE;
  775. }
  776.  
  777. // ---------------------------------------------------------------------------------
  778. // Handle non-numerical commands
  779. //
  780. void handle_charcmd( char c, GameStatus *game, HScores *hscores )
  781. {
  782. switch ( c )
  783. {
  784. case 'x':
  785. case '\0':
  786. break;
  787.  
  788. case 'h':
  789. do_help();
  790. break;
  791.  
  792. case 'i':
  793. do_hiscores( hscores );
  794. PAUSE();
  795. break;
  796.  
  797. case 't':
  798. do_stats( game );
  799. break;
  800.  
  801. case 'r':
  802. do_resetgame( game );
  803. break;
  804. case 's':
  805. do_savegame( game );
  806. break;
  807.  
  808. case 'l':
  809. do_loadgame( game );
  810. break;
  811.  
  812. default:
  813. puts("\a\n\tinvalid command, type h for help\n");
  814. break;
  815. }
  816.  
  817. return;
  818. }
  819.  
  820. // ---------------------------------------------------------------------------------
  821. // Handle numerical commands (expecting them to be board positions)
  822. //
  823. Bool handle_poscmd( char *inbuf, GameStatus *game)
  824. {
  825. int i, j, pos;
  826.  
  827. pos = atoi( inbuf );
  828. if ( pos < 0 || pos > (game->boardrows * game->boardcols)-1 ) {
  829. puts("\a\n\tinvalid position\n");
  830. return FALSE;
  831. }
  832.  
  833. i = pos / game->boardcols;
  834. j = pos % game->boardcols;
  835. if ( !game->board[ i ][ j ].avail ) {
  836. puts("\a\n\tyou have already played that position\n");
  837. return FALSE;
  838. }
  839.  
  840. game->board[ i ][ j ].avail = FALSE;
  841. (game->move)++;
  842. game->points += game->board[ i ][ j ].val;
  843. printf("\n\t%d points added to your bucket!\n\n", game->board[ i ][ j ].val);
  844.  
  845. return TRUE;
  846. }
  847.  
  848. // ---------------------------------------------------------------------------------
  849. // Calculate and show the final score on the screen
  850. //
  851. void outro_score( GameStatus *game )
  852. {
  853. if ( game->points >= game->maxpoints ) {
  854. printf("\n\t\a\a*** YES, YOU MADE IT! You collected %d points in %d moves(s)\n", game->points, game->move);
  855. game->score = (game->points - game->maxpoints + 1) * (game->maxmoves - game->move + 1) * game->boardrows * game->boardcols;
  856. printf("\t*** YOUR SCORE IS: %d\n", game->score);
  857. }
  858. else {
  859. game->score = 0;
  860. puts("\n\tSORRY, YOU FAILED! NO SCORE THIS TIME!");
  861. }
  862.  
  863. return;
  864. }
  865.  
  866. // ---------------------------------------------------------------------------------
  867. int main( void )
  868. {
  869. char inbuf[MAXINBUF] = ""; // for reading commands
  870. HS hs; // temp high-score entry (will get inited later)
  871. HScores hscores; // high-scores struct (will get inited later)
  872. GameStatus game; // the game struct (will get inited later)
  873.  
  874. CREDITS(); // display the credits line
  875. srand( time(NULL) ); // init the random generator
  876.  
  877. // initialize high-scores in memory, load them from file and show them
  878. hscores_init( HS_MAXSLOTS, HS_DEF_FNAME, MAXFNAME, MAXPNAME,
  879. GM_MAXROWS, GM_MAXCOLS, &hscores );
  880. intro_hscores( &hscores );
  881.  
  882. // initialize the game (it also reads the player name)
  883. init_game( GM_MAXROWS, GM_MAXCOLS, GM_DEF_FNAME, MAXFNAME, MAXPNAME, &game );
  884. putchar('\n');
  885.  
  886. do // the main loop of the game
  887. {
  888. show_board( &game, FALSE ); // display the board diagrams
  889. CREDITS(); // display the credits line
  890. PROMPT( game.player, game.move, // display the prompt
  891. game.maxmoves, game.points, game.maxpoints );
  892.  
  893. get_command( inbuf, MAXINBUF ); // get user command
  894. if ( isdigit(*inbuf) ) // handle numerical command
  895. handle_poscmd( inbuf, &game );
  896. else // handle non-numerical command
  897. handle_charcmd(*inbuf, &game, &hscores);
  898.  
  899. } while( *inbuf != 'x' // game ends either when x
  900. && game.move < game.maxmoves // or run out of moves
  901. && game.points < game.maxpoints ); // or maxpoints have been reached
  902.  
  903. show_board( &game, FALSE ); // display the board diagrams
  904. CREDITS();
  905.  
  906. outro_score( &game ); // calc & display the final score
  907.  
  908. // check if player should get into the high-scores table & inform him if so
  909. hs_init( MAXPNAME, HS_DEF_PNAME, HS_DEFSCORE, GM_MAXROWS, GM_MAXCOLS, &hs );
  910. outro_hscores( hs, &game, &hscores );
  911.  
  912. // ask whether to reveal the whole board or not, before exiting the game
  913. printf("\nwould you like the whole board to get revealed? (y/)? ");
  914. if ( *get_command(inbuf, MAXINBUF) == 'y') {
  915. show_board( &game, TRUE ); // reveal all the board cells
  916. PAUSE();
  917. }
  918.  
  919. exit( EXIT_SUCCESS );
  920. }
  921.  
Not running #stdin #stdout 0s 0KB
stdin
Standard input is empty
stdout
Standard output is empty