找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 3692|回复: 2

【C】基于控制台的拼图小游戏

[复制链接]
发表于 2020-10-31 23:08:34 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
本帖最后由 new_starter 于 2020-10-31 23:24 编辑

发一个基于控制台的拼图小游戏。
这个游戏来源于 StoneValley源码.
这个游戏需要StoneValley库的支持,它用到了栈和矩阵。
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <ctype.h>
  5. #include <time.h>
  6. #include <math.h>
  7. #include "../src/svstring.h"
  8. #include "../src/svstack.h"

  9. /* The following structure defines game actions in undo list. */
  10. typedef struct st_Action {
  11.         size_t x;
  12.         size_t y;
  13. } ACTION;

  14. /* Strings that consist squares in a puzzle. */
  15. const static char * const pAlphabet    = " ABCDEFGHIJKLMNOPQRSTUVWX";
  16. const static char * const pInscription = " nullum_numen_abest_si_sit_prudentia";
  17. const static char * const pValleyMap   = " Librarysss_ALGs___ORIsss_THM__stonesss_\\_/yellaV";
  18. static const char * pAnswer = NULL;

  19. static STACK_L stkAction = NULL; /* Action list. */
  20. static volatile size_t gCtrMove = 0; /* Number of times of movements. */

  21. // Function: PrintMatrixInMat
  22. // Desc:     Both print the matrix presented puzzle and its contour.
  23. // Param:    pmtx: Pointer to a matrix presented puzzle.
  24. // Return:   N/A.
  25. void PrintMatrixInMat(P_MATRIX pmtx)
  26. {
  27.         register char * pc = (char *)(pAnswer + 1);
  28.         register size_t i, j;
  29.         /* Print header. */
  30.         printf("  ");
  31.         for (i = 0; i < pmtx->col; ++i)
  32.                 putc(i + 'a', stdout);
  33.         printf("  Move: %d.\n +", gCtrMove);
  34.         for (i = 0; i < pmtx->col; ++i)
  35.                 putc('-', stdout);
  36.         printf("+\n");
  37.         /* Print puzzle body. */
  38.         for (i = 0; i < pmtx->ln; ++i)
  39.         {
  40.                 printf("%c|", i + 'a');
  41.                 for (j = 0; j < pmtx->col; ++j)
  42.                         printf("%c", *(char *)strGetValueMatrix(NULL, pmtx, i, j, sizeof(char)));
  43.                 printf("| ");
  44.                 for (j = 0; j < pmtx->col; ++j)
  45.                         if (!(i == pmtx->ln - 1 && j == pmtx->col - 1))
  46.                                 putc(*pc++, stdout);
  47.                 printf(" \n");
  48.         }
  49.         /* Print tail. */
  50.         printf(" +");
  51.         for (i = 0; i < pmtx->col; ++i)
  52.                 putc('-', stdout);
  53.         printf("+\n");
  54. }

  55. // Function: ValidateMatrix
  56. // Desc:     Validate a puzzle to check whether it has been finished.
  57. // Param:    pmtx: Pointer to a matrix presented puzzle.
  58. // Return:   TRUE: Solved; FALSE Not solved.
  59. BOOL ValidateMatrix(P_MATRIX pmtx)
  60. {
  61.         if (*(char *)strGetValueMatrix(NULL, pmtx, pmtx->ln - 1, pmtx->col - 1, sizeof(char)) == 32)
  62.         {        /* Only the last square in the puzzle is a space can indicate that the puzzle might be solved. */
  63.                 if (0 == memcmp(pAnswer + 1, pmtx->arrz.pdata, strLevelArrayZ(&pmtx->arrz) - 1))
  64.                 {        /* Good job. */
  65.                         printf(":) CONGRATULATIONS! You win the game in %d movement%c!\n\n", gCtrMove, gCtrMove > 1 ? 's' : '!');
  66.                         return TRUE;
  67.                 }
  68.         }
  69.         return FALSE;
  70. }

  71. // Function: MoveMatrix
  72. // Desc:     Take an action on a matrix presented puzzle.
  73. // Param:    pmtx: Pointer to a matrix presented puzzle.
  74. //           x:    Line that uses want to hit.
  75. //           y:    Column that uses want to hit.
  76. //           bundo:TRUE Undoing movement; FALSE Normal movement.
  77. // Return:   N/A.
  78. void MoveMatrix(P_MATRIX pmtx, size_t x, size_t y, BOOL bundo)
  79. {
  80.         register char * pchar = (char *)strGetValueMatrix(NULL, pmtx, x, y, sizeof(char));
  81.         if (NULL != pchar)
  82.         {        /* x and y are in range. */
  83.                 if (! isspace(*pchar))
  84.                 {        /* If the current hit square is not a space,
  85.                          * then take it as the center of a crucifix,
  86.                          * check whether there is a space in the line of the crucifix
  87.                          * or on the column of the crucifix. If it does,
  88.                          * move squares toward the space.
  89.                          */
  90.                         ACTION act;
  91.                         auto char c;
  92.                         register size_t i, j;
  93.                         /* Check current column. */
  94.                         for (i = 0; i < pmtx->col; ++i)
  95.                         {
  96.                                 if (isspace(*(char *)strGetValueMatrix(NULL, pmtx, i, y, sizeof(char))))
  97.                                 {
  98.                                         if (! bundo)
  99.                                         {
  100.                                                 act.x = i;
  101.                                                 act.y = y;
  102.                                                 stkPushL(&stkAction, &act, sizeof(ACTION));
  103.                                                 ++gCtrMove;
  104.                                         }
  105.                                         /* Move bricks toward the space. */
  106.                                         if (i < x)
  107.                                                 for (j = i; j < x; ++j)
  108.                                                         svSwap(strGetValueMatrix(NULL, pmtx, j, y, sizeof(char)),
  109.                                                         strGetValueMatrix(NULL, pmtx, j + 1, y, sizeof(char)), &c, sizeof(char));
  110.                                         else
  111.                                                 for (j = i; j > x; --j)
  112.                                                         svSwap(strGetValueMatrix(NULL, pmtx, j, y, sizeof(char)),
  113.                                                         strGetValueMatrix(NULL, pmtx, j - 1, y, sizeof(char)), &c, sizeof(char));
  114.                                         return;
  115.                                 }
  116.                         }
  117.                         /* Check current line. */
  118.                         for (i = 0; i < pmtx->ln; ++i)
  119.                         {
  120.                                 if (isspace(*(char *)strGetValueMatrix(NULL, pmtx, x, i, sizeof(char))))
  121.                                 {
  122.                                         if (! bundo)
  123.                                         {
  124.                                                 act.x = x;
  125.                                                 act.y = i;
  126.                                                 stkPushL(&stkAction, &act, sizeof(ACTION));
  127.                                                 ++gCtrMove;
  128.                                         }
  129.                                         /* Move bricks toward the space. */
  130.                                         if (i < y)
  131.                                                 for (j = i; j < y; ++j)
  132.                                                         svSwap(strGetValueMatrix(NULL, pmtx, x, j, sizeof(char)),
  133.                                                         strGetValueMatrix(NULL, pmtx, x, j + 1, sizeof(char)), &c, sizeof(char));
  134.                                         else
  135.                                                 for (j = i; j > y; --j)
  136.                                                         svSwap(strGetValueMatrix(NULL, pmtx, x, j, sizeof(char)),
  137.                                                         strGetValueMatrix(NULL, pmtx, x, j - 1, sizeof(char)), &c, sizeof(char));
  138.                                         return;
  139.                                 }
  140.                         }
  141.                 }
  142.         }
  143.         printf(":( You have hit the wrong place at (%c,%c).\n", x <= 26 ? x + 'a' : '?', y <= 26 ? y + 'a' : '?');
  144. }

  145. // Function: UndoMoving
  146. // Desc:     Undo an action on a puzzle.
  147. // Param:    pmtx: Pointer to a matrix presented puzzle.
  148. // Return:   N/A.
  149. void UndoMoving(P_MATRIX pmtx)
  150. {
  151.         if (! stkIsEmptyL(&stkAction))
  152.         {
  153.                 ACTION act;
  154.                 stkPopL(&act, sizeof(ACTION), &stkAction);
  155.                 MoveMatrix(pmtx, act.x, act.y, TRUE); /* Restore previous status. */
  156.                 --gCtrMove;
  157.         }
  158.         else
  159.                 printf("Undo list is empty.\n");
  160. }

  161. // Function: ShowHelp
  162. // Desc:     Show help information.
  163. // Param:    b: TRUE Show welcome text; FALSE Show usage.
  164. // Return:   N/A.
  165. void ShowHelp(BOOL b)
  166. {
  167.         switch (b)
  168.         {
  169.         case FALSE:
  170.                 printf("Welcome to Puzzle at ");
  171.                 svPrintVersion();
  172.                 printf(".\n\tPlease input:\n\t16: playing a 4*4 puzzle. (Alphabet)\n\t25: playing a 5*5 puzzle. (Alphabet)\n\
  173. \t36: playing a 6*6 puzzle. (Inscription)\n\t49: playing a 7*7 puzzle. (Map)\n\t 0: Exit.\n?> ");
  174.                 break;
  175.         case TRUE:
  176.                 printf("\tInput 'xy' to hit a square in the puzzle,\n\
  177. \twhereas x denotes line, y denotes column.\n\tInput 'z' to undo.\n\
  178. \tInput '0' or 'q' to quit.\n\tInput 'h' or \'?\' for help.\n\
  179. \tA sequence of actions is allowed to input, such that \'aadaq?dd\'.\n");
  180.         }
  181. }

  182. // Function: CommandParser
  183. // Desc:     Parse a string of command sequence.
  184. // Param:    pmtx: Pointer to a matrix presented puzzle.
  185. //           pcmd: A string that contains commands.
  186. // Return:   0: Command parsed succeeded. 1: Escaping required.
  187. int CommandParser(P_MATRIX pmtx, char * pcmd)
  188. {
  189.         int i = 0, r = 0;
  190.         BOOL bhelp = FALSE;
  191.         do
  192.         {
  193.                 if ('\0' == pcmd[0] || '\n' == pcmd[0]) /* Buffer end. */
  194.                 {
  195.                         if (1 != r)
  196.                                 r = 0;
  197.                         break;
  198.                 }
  199.                 if ('0' == pcmd[0] || 'q' == pcmd[0]) /* Quit. */
  200.                 {
  201.                         r = 1;
  202.                         ++pcmd;
  203.                         continue;
  204.                 }
  205.                 pcmd[0] = tolower(pcmd[0]);
  206.                 pcmd[1] = tolower(pcmd[1]);
  207.                 if ('z' == pcmd[0])
  208.                 {        /* Undo. */
  209.                         UndoMoving(pmtx);
  210.                         ++pcmd;
  211.                         continue;
  212.                 }
  213.                 if (('h' == pcmd[0]) || ('?' == pcmd[0]))
  214.                 {        /* Help. */
  215.                         if (FALSE == bhelp)
  216.                                 ShowHelp(bhelp = TRUE);
  217.                         ++pcmd;
  218.                         continue;
  219.                 }
  220.                 /* Translate the current command. */
  221.                 MoveMatrix(pmtx, pcmd[0] - 'a', pcmd[1] - 'a', FALSE);
  222.                 pcmd += 2;
  223.                 ++i;
  224.         }
  225.         while (i < BUFSIZ);
  226.         PrintMatrixInMat(pmtx);
  227.         return r;
  228. }

  229. // Function: main
  230. // Desc:     Program entry.
  231. // Param:    N/A.
  232. // Return:   0 only.
  233. signed int main(void)
  234. {
  235.         MATRIX mtxPuzzle;
  236.         auto char t, ipb[BUFSIZ] = { 0 }; /* Input buffer. */
  237.         stkInitL(&stkAction);
  238. Lbl_Again:
  239.         for (gCtrMove = 0; ; )
  240.         {        /* Select a mode to play or quit game. */
  241.                 ShowHelp(FALSE);
  242.                 fgets(ipb, BUFSIZ, stdin);
  243.                 t = atoi(ipb);
  244.                 switch (t)
  245.                 {
  246.                 case 0:
  247.                         exit(0);
  248.                 case 16:
  249.                 case 25: pAnswer = pAlphabet;    break;
  250.                 case 36: pAnswer = pInscription; break;
  251.                 case 49: pAnswer = pValleyMap;   break;
  252.                 default: pAnswer = NULL;
  253.                 }
  254.                 if (NULL != pAnswer)
  255.                 {
  256.                         t = (char)pow(t, 0.5);
  257.                         break;
  258.                 }
  259.         }
  260.         strInitMatrix(&mtxPuzzle, t, t, sizeof(char));
  261.         memcpy(mtxPuzzle.arrz.pdata, pAnswer, mtxPuzzle.ln * mtxPuzzle.col);
  262.         strShuffleArrayZ(&mtxPuzzle.arrz, &t, sizeof(char), (unsigned int) time(NULL));
  263.         PrintMatrixInMat(&mtxPuzzle);
  264.         do
  265.         {
  266. Lbl_Resume:
  267.                 fflush(stdin);
  268.                 memset(ipb, 0, BUFSIZ);
  269.                 printf("Location h/?> ");
  270.                 fgets(ipb, BUFSIZ, stdin);
  271.                 if (1 == CommandParser(&mtxPuzzle, ipb))
  272.                 {
  273.                         int i;
  274.                         do
  275.                         {        /* Query users to ensure their choices correct. */
  276.                                 printf("?Are you sure to exit?Y/n/r?> ");
  277.                                 i = strlen(fgets(ipb, BUFSIZ, stdin));
  278.                                 if (i > 1)
  279.                                         i -= 2;
  280.                                 ipb[i] = tolower(ipb[i]);
  281.                                 if ('r' == ipb[i])
  282.                                         goto Lbl_Restart;
  283.                                 if ('n' == ipb[i])
  284.                                 {
  285.                                         printf("Resume...\n");
  286.                                         PrintMatrixInMat(&mtxPuzzle);
  287.                                         goto Lbl_Resume;
  288.                                 }
  289.                                 putc('\n', stdin);
  290.                         }
  291.                         while (ipb[i] != 'y');
  292.                         stkFreeL(&stkAction);
  293.                         strFreeMatrix(&mtxPuzzle);
  294.                         return 0;
  295.                 }
  296.         }
  297.         while (TRUE != ValidateMatrix(&mtxPuzzle));
  298. Lbl_Restart:
  299.         stkFreeL(&stkAction);
  300.         strFreeMatrix(&mtxPuzzle);
  301. goto Lbl_Again;
  302.         return 0;
  303. }
复制代码


Welcome to Puzzle at StoneValley 1.1.7.9.
        Please input:
        16: playing a 4*4 puzzle. (Alphabet)
        25: playing a 5*5 puzzle. (Alphabet)
        36: playing a 6*6 puzzle. (Inscription)
        49: playing a 7*7 puzzle. (Map)
         0: Exit.
?> 16
  abcd  Move: 0.
+----+
a|JAFD| ABCD
b|EIBN| EFGH
c| OKM| IJKL
d|HGCL| MNO
+----+
Location h/?> aaad
  abcd  Move: 2.
+----+
a|AFD | ABCD
b|JIBN| EFGH
c|EOKM| IJKL
d|HGCL| MNO
+----+
Location h/?> ?
        Input 'xy' to hit a square in the puzzle,
        whereas x denotes line, y denotes column.
        Input 'z' to undo.
        Input '0' or 'q' to quit.
        Input 'h' or '?' for help.
        A sequence of actions is allowed to input, such that 'aadaq?dd'.
  abcd  Move: 2.
+----+
a|AFD | ABCD
b|JIBN| EFGH
c|EOKM| IJKL
d|HGCL| MNO
+----+
Location h/?>

玩法如上所示,输入要点击的方块的坐标来移动方块,将方块完全排序完成后游戏成功。





以下是一段关于矩阵用法的程序,它能帮助读者更进一步了解StoneValley里的矩阵:
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include "../src/svstring.h"

  4. // Function: Plus
  5. // Desc:     Addition.
  6. //           Please refer to the definition of callback function CBF_ALGEBRA.
  7. // Return:   CBF_CONTINUE only.
  8. int Plus(const void * pa, const void * pb)
  9. {
  10.         *(char *)pa += *(char *)pb;
  11.         return CBF_CONTINUE;
  12. }

  13. // Function: Minus
  14. // Desc:     Subtraction.
  15. //           Please refer to the definition of callback function CBF_ALGEBRA.
  16. // Return:   CBF_CONTINUE only.
  17. int Minus(const void * pa, const void * pb)
  18. {
  19.         *(char *)pa -= *(char *)pb;
  20.         return CBF_CONTINUE;
  21. }

  22. // Function: Times
  23. // Desc:     Multiplication.
  24. //           Please refer to the definition of callback function CBF_ALGEBRA.
  25. // Return:   CBF_CONTINUE only.
  26. int Times(const void * pa, const void * pb)
  27. {
  28.         *(char *)pa *= *(char *)pb;
  29.         return CBF_CONTINUE;
  30. }

  31. // Function: PrintMatrix
  32. // Desc:     Print a matrix.
  33. // Param:    pmat: pointer to a matrix you want to print. width: Print matrix in a width * width area.
  34. // Return:   N/A.
  35. void PrintMatrix(P_MATRIX pmat, const char width)
  36. {
  37.         char i, j, k, b, m, n;
  38.         for (i = 0; i < width; ++i)
  39.         {
  40.                 for (j = 0; j < width; ++j)
  41.                 {
  42.                         for (k = 0, b = FALSE; k < (const char) pmat->col; ++k)
  43.                         {
  44.                                 if (NULL != strGetValueMatrix(&m, pmat, 0, k, sizeof(char)) && m == i &&
  45.                                         NULL != strGetValueMatrix(&n, pmat, 1, k, sizeof(char)) && n == j
  46.                                         ) b = TRUE;
  47.                         }
  48.                         if (b)
  49.                                 printf("E");
  50.                         else
  51.                                 printf(" ");
  52.                 }
  53.                 printf("\n");
  54.         }
  55. }

  56. // Function: main
  57. // Desc:     Program entry.
  58. // Param:    N/A.
  59. // Return:   0: no error. NOT 0: allocation failure.
  60. int main(void)
  61. {
  62.         const char data[] = { // Stores a big letter E.
  63.         //    1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16
  64.         /*1*/ 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, // Y.
  65.         /*2*/ 0, 1, 2, 3, 4, 0, 0, 1, 2, 3, 0, 0, 1, 2, 3, 4  // X.
  66.         };
  67.         const char conv[] = { -1, 0, 0, 1 };
  68.         char c = 5;
  69.         MATRIX mat; // A matrix header.
  70.         P_MATRIX pmword, pmimage, pmtemp, pmconv, ppmat[3]; // Matrix pointers.
  71.         CBF_ALGEBRA cbfalg[2];
  72.         if (NULL == (pmword  = strCreateMatrix(2, 16, sizeof(char)))) {
  73.                 c = 4; goto Lbl_Clr;
  74.         }
  75.         if (NULL == (pmimage = strCreateMatrix(2, 16, sizeof(char)))) {
  76.                 c = 3; goto Lbl_Clr;
  77.         }
  78.         if (NULL == (pmtemp  = strCreateMatrix(2, 16, sizeof(char)))) {
  79.                 c = 2; goto Lbl_Clr;
  80.         }
  81.         if (NULL == (pmconv  = strCreateMatrix(2,  2, sizeof(char)))) {
  82.                 c = 1; goto Lbl_Clr;
  83.         }
  84.         // Assemble cbfalg array for strM3Matrix.
  85.         cbfalg[0] = Plus;
  86.         cbfalg[1] = Times;
  87.         // Assemble ppmat for strM3Matrix.
  88.         ppmat[0] = pmtemp; // Matrix C.
  89.         ppmat[1] = pmconv; // Matrix A.
  90.         ppmat[2] = pmword; // Matrix B.
  91.         // Copy original data.
  92.         memcpy(pmword->arrz.pdata, data, sizeof(data));
  93.         memcpy(pmconv->arrz.pdata, conv, sizeof(conv));
  94.         // Fill pmimage with x=5, y=5.
  95.         strSetMatrix(pmimage, &c, sizeof(char));
  96.         // Print big letter 'E'.
  97.         PrintMatrix(pmword, 5);
  98.         printf("\nAfter converting:\n\n");
  99.         strM3Matrix(ppmat, &c, sizeof(char), cbfalg); // Flip.
  100.         strM2Matrix(pmimage, pmtemp, sizeof(char), Minus); // Move right down.
  101.         // Assemble matrix header. Subtract every y by 5.
  102.         mat.arrz.pdata = pmimage->arrz.pdata;
  103.         mat.arrz.num = pmimage->arrz.num;
  104.         mat.ln = 1;
  105.         mat.col = pmimage->col;
  106.         c = 5; strM1Matrix(&mat, &c, sizeof(char), Minus); // Move up.
  107.         PrintMatrix(pmimage, 6); // Print converted 'E'mage.
  108.         c = 0;
  109. Lbl_Clr:
  110.         switch(c)
  111.         {
  112.         case 0: strDeleteMatrix(pmconv);
  113.         case 1: strDeleteMatrix(pmtemp);
  114.         case 2: strDeleteMatrix(pmimage);
  115.         case 3: strDeleteMatrix(pmword);
  116.         default: break;
  117.         }
  118.         return (int)c;
  119. }
复制代码

本帖被以下淘专辑推荐:

回复

使用道具 举报

发表于 2020-11-2 22:10:41 | 显示全部楼层
不喜欢StoneValley的代码风格,如果是我去用,我可能会写一个针对代码风格的Wrapper
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2020-11-2 22:30:57 | 显示全部楼层
0xAA55 发表于 2020-11-2 22:10
不喜欢StoneValley的代码风格,如果是我去用,我可能会写一个针对代码风格的Wrapper ...

在/Samples/下提供了一个lex文件,可以用来转换命名方式
回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-21 18:03 , Processed in 0.033125 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表