技术宅的结界

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

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 207|回复: 2
收起左侧

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

[复制链接]

7

主题

11

帖子

261

积分

用户组: 中·技术宅

UID
6266
精华
5
威望
37 点
宅币
121 个
贡献
30 次
宅之契约
0 份
在线时间
5 小时
注册时间
2020-9-26
发表于 2020-10-31 23:08:34 | 显示全部楼层 |阅读模式

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

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

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

发一个基于控制台的拼图小游戏。
这个游戏来源于 StoneValley源码.
这个游戏需要StoneValley库的支持,它用到了栈和矩阵。
[C] 纯文本查看 复制代码
#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里的矩阵:
[C] 纯文本查看 复制代码
#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;
}

评分

参与人数 1威望 +10 宅币 +10 贡献 +5 收起 理由
0xAA55 + 10 + 10 + 5 不喜欢StoneValley的代码风格,如果是我去.

查看全部评分

本帖被以下淘专辑推荐:

回复

使用道具 举报

1072

主题

2492

帖子

6万

积分

用户组: 管理员

一只技术宅

UID
1
精华
223
威望
420 点
宅币
20164 个
贡献
41913 次
宅之契约
0 份
在线时间
1908 小时
注册时间
2014-1-26
发表于 2020-11-2 22:10:41 | 显示全部楼层
不喜欢StoneValley的代码风格,如果是我去用,我可能会写一个针对代码风格的Wrapper

7

主题

11

帖子

261

积分

用户组: 中·技术宅

UID
6266
精华
5
威望
37 点
宅币
121 个
贡献
30 次
宅之契约
0 份
在线时间
5 小时
注册时间
2020-9-26
 楼主| 发表于 2020-11-2 22:30:57 | 显示全部楼层
0xAA55 发表于 2020-11-2 22:10
不喜欢StoneValley的代码风格,如果是我去用,我可能会写一个针对代码风格的Wrapper ...

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

本版积分规则

QQ|申请友链||Archiver|手机版|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图  

GMT+8, 2020-11-28 04:24 , Processed in 0.103781 second(s), 33 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

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