UID 6266
精华
积分 794
威望 点
宅币 个
贡献 次
宅之契约 份
最后登录 1970-1-1
在线时间 小时
本帖最后由 new_starter 于 2020-10-31 23:24 编辑
发一个基于控制台的拼图小游戏。
这个游戏来源于 StoneValley 源码.
这个游戏需要StoneValley库的支持,它用到了栈和矩阵。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include <math.h>
#include "../src/svstring.h"
#include "../src/svstack.h"
/* The following structure defines game actions in undo list. */
typedef struct st_Action {
size_t x;
size_t y;
} ACTION;
/* Strings that consist squares in a puzzle. */
const static char * const pAlphabet = " ABCDEFGHIJKLMNOPQRSTUVWX";
const static char * const pInscription = " nullum_numen_abest_si_sit_prudentia";
const static char * const pValleyMap = " Librarysss_ALGs___ORIsss_THM__stonesss_\\_/yellaV";
static const char * pAnswer = NULL;
static STACK_L stkAction = NULL; /* Action list. */
static volatile size_t gCtrMove = 0; /* Number of times of movements. */
// Function: PrintMatrixInMat
// Desc: Both print the matrix presented puzzle and its contour.
// Param: pmtx: Pointer to a matrix presented puzzle.
// Return: N/A.
void PrintMatrixInMat(P_MATRIX pmtx)
{
register char * pc = (char *)(pAnswer + 1);
register size_t i, j;
/* Print header. */
printf(" ");
for (i = 0; i < pmtx->col; ++i)
putc(i + 'a', stdout);
printf(" Move: %d.\n +", gCtrMove);
for (i = 0; i < pmtx->col; ++i)
putc('-', stdout);
printf("+\n");
/* Print puzzle body. */
for (i = 0; i < pmtx->ln; ++i)
{
printf("%c|", i + 'a');
for (j = 0; j < pmtx->col; ++j)
printf("%c", *(char *)strGetValueMatrix(NULL, pmtx, i, j, sizeof(char)));
printf("| ");
for (j = 0; j < pmtx->col; ++j)
if (!(i == pmtx->ln - 1 && j == pmtx->col - 1))
putc(*pc++, stdout);
printf(" \n");
}
/* Print tail. */
printf(" +");
for (i = 0; i < pmtx->col; ++i)
putc('-', stdout);
printf("+\n");
}
// Function: ValidateMatrix
// Desc: Validate a puzzle to check whether it has been finished.
// Param: pmtx: Pointer to a matrix presented puzzle.
// Return: TRUE: Solved; FALSE Not solved.
BOOL ValidateMatrix(P_MATRIX pmtx)
{
if (*(char *)strGetValueMatrix(NULL, pmtx, pmtx->ln - 1, pmtx->col - 1, sizeof(char)) == 32)
{ /* Only the last square in the puzzle is a space can indicate that the puzzle might be solved. */
if (0 == memcmp(pAnswer + 1, pmtx->arrz.pdata, strLevelArrayZ(&pmtx->arrz) - 1))
{ /* Good job. */
printf(":) CONGRATULATIONS! You win the game in %d movement%c!\n\n", gCtrMove, gCtrMove > 1 ? 's' : '!');
return TRUE;
}
}
return FALSE;
}
// Function: MoveMatrix
// Desc: Take an action on a matrix presented puzzle.
// Param: pmtx: Pointer to a matrix presented puzzle.
// x: Line that uses want to hit.
// y: Column that uses want to hit.
// bundo:TRUE Undoing movement; FALSE Normal movement.
// Return: N/A.
void MoveMatrix(P_MATRIX pmtx, size_t x, size_t y, BOOL bundo)
{
register char * pchar = (char *)strGetValueMatrix(NULL, pmtx, x, y, sizeof(char));
if (NULL != pchar)
{ /* x and y are in range. */
if (! isspace(*pchar))
{ /* If the current hit square is not a space,
* then take it as the center of a crucifix,
* check whether there is a space in the line of the crucifix
* or on the column of the crucifix. If it does,
* move squares toward the space.
*/
ACTION act;
auto char c;
register size_t i, j;
/* Check current column. */
for (i = 0; i < pmtx->col; ++i)
{
if (isspace(*(char *)strGetValueMatrix(NULL, pmtx, i, y, sizeof(char))))
{
if (! bundo)
{
act.x = i;
act.y = y;
stkPushL(&stkAction, &act, sizeof(ACTION));
++gCtrMove;
}
/* Move bricks toward the space. */
if (i < x)
for (j = i; j < x; ++j)
svSwap(strGetValueMatrix(NULL, pmtx, j, y, sizeof(char)),
strGetValueMatrix(NULL, pmtx, j + 1, y, sizeof(char)), &c, sizeof(char));
else
for (j = i; j > x; --j)
svSwap(strGetValueMatrix(NULL, pmtx, j, y, sizeof(char)),
strGetValueMatrix(NULL, pmtx, j - 1, y, sizeof(char)), &c, sizeof(char));
return;
}
}
/* Check current line. */
for (i = 0; i < pmtx->ln; ++i)
{
if (isspace(*(char *)strGetValueMatrix(NULL, pmtx, x, i, sizeof(char))))
{
if (! bundo)
{
act.x = x;
act.y = i;
stkPushL(&stkAction, &act, sizeof(ACTION));
++gCtrMove;
}
/* Move bricks toward the space. */
if (i < y)
for (j = i; j < y; ++j)
svSwap(strGetValueMatrix(NULL, pmtx, x, j, sizeof(char)),
strGetValueMatrix(NULL, pmtx, x, j + 1, sizeof(char)), &c, sizeof(char));
else
for (j = i; j > y; --j)
svSwap(strGetValueMatrix(NULL, pmtx, x, j, sizeof(char)),
strGetValueMatrix(NULL, pmtx, x, j - 1, sizeof(char)), &c, sizeof(char));
return;
}
}
}
}
printf(":( You have hit the wrong place at (%c,%c).\n", x <= 26 ? x + 'a' : '?', y <= 26 ? y + 'a' : '?');
}
// Function: UndoMoving
// Desc: Undo an action on a puzzle.
// Param: pmtx: Pointer to a matrix presented puzzle.
// Return: N/A.
void UndoMoving(P_MATRIX pmtx)
{
if (! stkIsEmptyL(&stkAction))
{
ACTION act;
stkPopL(&act, sizeof(ACTION), &stkAction);
MoveMatrix(pmtx, act.x, act.y, TRUE); /* Restore previous status. */
--gCtrMove;
}
else
printf("Undo list is empty.\n");
}
// Function: ShowHelp
// Desc: Show help information.
// Param: b: TRUE Show welcome text; FALSE Show usage.
// Return: N/A.
void ShowHelp(BOOL b)
{
switch (b)
{
case FALSE:
printf("Welcome to Puzzle at ");
svPrintVersion();
printf(".\n\tPlease input:\n\t16: playing a 4*4 puzzle. (Alphabet)\n\t25: playing a 5*5 puzzle. (Alphabet)\n\
\t36: playing a 6*6 puzzle. (Inscription)\n\t49: playing a 7*7 puzzle. (Map)\n\t 0: Exit.\n?> ");
break;
case TRUE:
printf("\tInput 'xy' to hit a square in the puzzle,\n\
\twhereas x denotes line, y denotes column.\n\tInput 'z' to undo.\n\
\tInput '0' or 'q' to quit.\n\tInput 'h' or \'?\' for help.\n\
\tA sequence of actions is allowed to input, such that \'aadaq?dd\'.\n");
}
}
// Function: CommandParser
// Desc: Parse a string of command sequence.
// Param: pmtx: Pointer to a matrix presented puzzle.
// pcmd: A string that contains commands.
// Return: 0: Command parsed succeeded. 1: Escaping required.
int CommandParser(P_MATRIX pmtx, char * pcmd)
{
int i = 0, r = 0;
BOOL bhelp = FALSE;
do
{
if ('\0' == pcmd[0] || '\n' == pcmd[0]) /* Buffer end. */
{
if (1 != r)
r = 0;
break;
}
if ('0' == pcmd[0] || 'q' == pcmd[0]) /* Quit. */
{
r = 1;
++pcmd;
continue;
}
pcmd[0] = tolower(pcmd[0]);
pcmd[1] = tolower(pcmd[1]);
if ('z' == pcmd[0])
{ /* Undo. */
UndoMoving(pmtx);
++pcmd;
continue;
}
if (('h' == pcmd[0]) || ('?' == pcmd[0]))
{ /* Help. */
if (FALSE == bhelp)
ShowHelp(bhelp = TRUE);
++pcmd;
continue;
}
/* Translate the current command. */
MoveMatrix(pmtx, pcmd[0] - 'a', pcmd[1] - 'a', FALSE);
pcmd += 2;
++i;
}
while (i < BUFSIZ);
PrintMatrixInMat(pmtx);
return r;
}
// Function: main
// Desc: Program entry.
// Param: N/A.
// Return: 0 only.
signed int main(void)
{
MATRIX mtxPuzzle;
auto char t, ipb[BUFSIZ] = { 0 }; /* Input buffer. */
stkInitL(&stkAction);
Lbl_Again:
for (gCtrMove = 0; ; )
{ /* Select a mode to play or quit game. */
ShowHelp(FALSE);
fgets(ipb, BUFSIZ, stdin);
t = atoi(ipb);
switch (t)
{
case 0:
exit(0);
case 16:
case 25: pAnswer = pAlphabet; break;
case 36: pAnswer = pInscription; break;
case 49: pAnswer = pValleyMap; break;
default: pAnswer = NULL;
}
if (NULL != pAnswer)
{
t = (char)pow(t, 0.5);
break;
}
}
strInitMatrix(&mtxPuzzle, t, t, sizeof(char));
memcpy(mtxPuzzle.arrz.pdata, pAnswer, mtxPuzzle.ln * mtxPuzzle.col);
strShuffleArrayZ(&mtxPuzzle.arrz, &t, sizeof(char), (unsigned int) time(NULL));
PrintMatrixInMat(&mtxPuzzle);
do
{
Lbl_Resume:
fflush(stdin);
memset(ipb, 0, BUFSIZ);
printf("Location h/?> ");
fgets(ipb, BUFSIZ, stdin);
if (1 == CommandParser(&mtxPuzzle, ipb))
{
int i;
do
{ /* Query users to ensure their choices correct. */
printf("?Are you sure to exit?Y/n/r?> ");
i = strlen(fgets(ipb, BUFSIZ, stdin));
if (i > 1)
i -= 2;
ipb[i] = tolower(ipb[i]);
if ('r' == ipb[i])
goto Lbl_Restart;
if ('n' == ipb[i])
{
printf("Resume...\n");
PrintMatrixInMat(&mtxPuzzle);
goto Lbl_Resume;
}
putc('\n', stdin);
}
while (ipb[i] != 'y');
stkFreeL(&stkAction);
strFreeMatrix(&mtxPuzzle);
return 0;
}
}
while (TRUE != ValidateMatrix(&mtxPuzzle));
Lbl_Restart:
stkFreeL(&stkAction);
strFreeMatrix(&mtxPuzzle);
goto Lbl_Again;
return 0;
}
复制代码
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里的矩阵:
#include <stdio.h>
#include <string.h>
#include "../src/svstring.h"
// Function: Plus
// Desc: Addition.
// Please refer to the definition of callback function CBF_ALGEBRA.
// Return: CBF_CONTINUE only.
int Plus(const void * pa, const void * pb)
{
*(char *)pa += *(char *)pb;
return CBF_CONTINUE;
}
// Function: Minus
// Desc: Subtraction.
// Please refer to the definition of callback function CBF_ALGEBRA.
// Return: CBF_CONTINUE only.
int Minus(const void * pa, const void * pb)
{
*(char *)pa -= *(char *)pb;
return CBF_CONTINUE;
}
// Function: Times
// Desc: Multiplication.
// Please refer to the definition of callback function CBF_ALGEBRA.
// Return: CBF_CONTINUE only.
int Times(const void * pa, const void * pb)
{
*(char *)pa *= *(char *)pb;
return CBF_CONTINUE;
}
// Function: PrintMatrix
// Desc: Print a matrix.
// Param: pmat: pointer to a matrix you want to print. width: Print matrix in a width * width area.
// Return: N/A.
void PrintMatrix(P_MATRIX pmat, const char width)
{
char i, j, k, b, m, n;
for (i = 0; i < width; ++i)
{
for (j = 0; j < width; ++j)
{
for (k = 0, b = FALSE; k < (const char) pmat->col; ++k)
{
if (NULL != strGetValueMatrix(&m, pmat, 0, k, sizeof(char)) && m == i &&
NULL != strGetValueMatrix(&n, pmat, 1, k, sizeof(char)) && n == j
) b = TRUE;
}
if (b)
printf("E");
else
printf(" ");
}
printf("\n");
}
}
// Function: main
// Desc: Program entry.
// Param: N/A.
// Return: 0: no error. NOT 0: allocation failure.
int main(void)
{
const char data[] = { // Stores a big letter E.
// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*1*/ 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, // Y.
/*2*/ 0, 1, 2, 3, 4, 0, 0, 1, 2, 3, 0, 0, 1, 2, 3, 4 // X.
};
const char conv[] = { -1, 0, 0, 1 };
char c = 5;
MATRIX mat; // A matrix header.
P_MATRIX pmword, pmimage, pmtemp, pmconv, ppmat[3]; // Matrix pointers.
CBF_ALGEBRA cbfalg[2];
if (NULL == (pmword = strCreateMatrix(2, 16, sizeof(char)))) {
c = 4; goto Lbl_Clr;
}
if (NULL == (pmimage = strCreateMatrix(2, 16, sizeof(char)))) {
c = 3; goto Lbl_Clr;
}
if (NULL == (pmtemp = strCreateMatrix(2, 16, sizeof(char)))) {
c = 2; goto Lbl_Clr;
}
if (NULL == (pmconv = strCreateMatrix(2, 2, sizeof(char)))) {
c = 1; goto Lbl_Clr;
}
// Assemble cbfalg array for strM3Matrix.
cbfalg[0] = Plus;
cbfalg[1] = Times;
// Assemble ppmat for strM3Matrix.
ppmat[0] = pmtemp; // Matrix C.
ppmat[1] = pmconv; // Matrix A.
ppmat[2] = pmword; // Matrix B.
// Copy original data.
memcpy(pmword->arrz.pdata, data, sizeof(data));
memcpy(pmconv->arrz.pdata, conv, sizeof(conv));
// Fill pmimage with x=5, y=5.
strSetMatrix(pmimage, &c, sizeof(char));
// Print big letter 'E'.
PrintMatrix(pmword, 5);
printf("\nAfter converting:\n\n");
strM3Matrix(ppmat, &c, sizeof(char), cbfalg); // Flip.
strM2Matrix(pmimage, pmtemp, sizeof(char), Minus); // Move right down.
// Assemble matrix header. Subtract every y by 5.
mat.arrz.pdata = pmimage->arrz.pdata;
mat.arrz.num = pmimage->arrz.num;
mat.ln = 1;
mat.col = pmimage->col;
c = 5; strM1Matrix(&mat, &c, sizeof(char), Minus); // Move up.
PrintMatrix(pmimage, 6); // Print converted 'E'mage.
c = 0;
Lbl_Clr:
switch(c)
{
case 0: strDeleteMatrix(pmconv);
case 1: strDeleteMatrix(pmtemp);
case 2: strDeleteMatrix(pmimage);
case 3: strDeleteMatrix(pmword);
default: break;
}
return (int)c;
}
复制代码