一些C语言小游戏……
  • 板块灌水区
  • 楼主ENIAC_ming
  • 当前回复12
  • 已保存回复12
  • 发布时间2021/3/5 23:51
  • 上次更新2023/11/5 02:25:29
查看原帖
一些C语言小游戏……
472704
ENIAC_ming楼主2021/3/5 23:51

Cgame 原地址

彩色版五子棋

#include <windows.h>
#include <conio.h>
#include <stdio.h>
int W = 13, S, M = 0, *m, c = 1, r = 2, z, i, j, k, *p;
int *sum(int *v, int l) { return *v - v[l] ? v + l : sum(v + l, l); }
void down(int v) {
	for (m[v] = r ^= 3, i = 2; j = i % 3 - 1 + i / 3 * W, i < 6; ++i) {
		p = sum(m + v, j), k = (p - sum(m + v, -j)) / j;
		*p || (p[S * r] += 1 << k), p -= k * j, *p || (p[S * r] += 1 << k);
		m[v + S] = m[v + S * 2] = 0, k > 5 && (r ^= 3, r += 4, i = 8);
	}
}
void ai() {
	for (j = k = 0, i = S; i < 3 * S || (k = rand() % k, k || ++k, 0);)
		j == m[i] && ++k, j < m[i] && (j = m[i], k = 1), ++i;
	for (i = S; k && i < 3 * S || (down(i % S), 0);)m[++i] == j && --k;
}
int main() {
	for (W += 2, S = W * W, m = calloc(i = S * 3, 4), srand((int)m); i--;)
		i % W && -~i % W && !(i % S < W || (i + W) % S < W) || (m[i] = -1);
	SetConsoleCursorInfo(GetStdHandle((DWORD)-11), &(CONSOLE_CURSOR_INFO) { 25 });
	for (z = S / 2, system("cls"); r < 4 && c - 27; c = _getch() & 95) {
		c - 87 || m[z - W] + 1 && (z -= W), c - 68 || m[++z] + 1 || --z;
		c - 83 || m[z + W] + 1 && (z += W), c - 65 || m[--z] + 1 || ++z;
		if (!c)M - 2 ? !m[z] && (down(z), r < 4 && M && (ai(), 0)) : ai();
		SetConsoleCursorPosition(GetStdHandle((DWORD)-11), (COORD) { 0 });
		for (i = W; i < S - W; ++i % W || _cprintf("%d\n", i / W - 1))
			SetConsoleTextAttribute(GetStdHandle((DWORD)-11), i - z ? 15 : 175),
			m[i] + 1 && printf(". \0○\0●" + m[i] * 3);
		for (i = 1, c - 81 || ++M; ++i < W;)_cprintf(" %c", 95 + i);
		M %= 3, _cprintf("\n%s|", "PvP\0PvE\0EvE" + M * 4);
		_cputs(r & 1 ? "White" : "Black"), r < 4 || _cputs(" win!");
	}
}
/*
操作:adsw键移动,空格下子,q键切换模式,Esc退出。
1. 模式有三种:
  PvP(Player VS Player),玩家对战玩家,均由玩家自行下子
  PvE(Player VS Environment),玩家对战环境,玩家下子后自动再下一子
  EvE,不解释,按一下自动下一子,不受光标影响
2. '@'是白棋,'O'是黑棋(对应25行的64和79,可以自己改成自己喜欢的符号
3. 棋盘大小可以自己改(3行的W)(固定长宽比1:1)
*/

2048小游戏

#include <windows.h>
#include <conio.h>
int bg[] = {15, 240, 144, 160, 176, 192, 208, 224, 16, 32, 48, 64, 80};
int m[36] = { 0 }, score = 0, can = 0, air = 16, c = 0, i = 6, j, *p;
void move(int *q, int v) {
	if (*q < 1 ? 0 : q[v] || (q[v] = *q, move(q + v, v), *q = can = 0))
		q[v] - *q || (q[v] = ~*q, score += 1 << *q, *q = can = 0, ++air);
}
void order(int b, int v) { b - j && ((move(m + b, v), order(b + i, v), 0)); }
int main() {
	for (p = malloc(1); i--;)m[i] = m[35 - i] = m[i * 6] = m[35 - i * 6] = -1;
	for (srand(p), free(p); (air || can) && c - 27; c = _getch() & 95) {
		c - 'A' && c - 'W' || (j = 30, i = 1, order(6, c - 'A' ? -6 : -1), 0);
		c - 'D' && c - 'S' || (j = 6, i = -1, order(30, c - 'D' ? 6 : 1), 0);
		if (!air || can || (--air, (system("cls"))))continue;
		while (m[i = rand() % 30] || (m[i] = rand() % 5 ? 1 : 2, 0));
		for (p = m + 30; --p - m - 6; *p < -1 && (*p = -*p));
		for (; ++p - m - 31; *p + 1 && _cprintf("%5d", *p ? 1 << *p : 0))
			SetConsoleTextAttribute(GetStdHandle((DWORD)-11), bg[*p % 12 + 1]),
			*p + 1 && (*p ^ p[1] && *p ^ p[6] || ++can),
			(p - m) % 6 || _cputs("\n");
		air || can || _cputs("Game over!"), _cprintf("score:%d", score);
	}
}
//ADSW使所有数字移动, 相同数字合并, 每次行动后产生新数字,
//直到无法产生移动或按下Esc键时游戏结束。

贪吃蛇

#include <windows.h>
#include <conio.h>
int main() {
    int W = 20, S = W * W, * m, z[2] = { 0 }, l = 3, i, c = 'D', C, * p, f;
    SetConsoleCursorInfo(GetStdHandle((DWORD)-11), &(CONSOLE_CURSOR_INFO){25});
    for (srand(m = calloc(S, 4)), C = m[1] = -1; C - 27; Sleep(100)) {
        if (_kbhit())C = _getch() & 95, C - 65 && C - 68 &&
            C - 83 && C - 87 || (C ^ c) & 20 ^ 4 && (c = C);
        p = z + !!(c & 2), * p += c / 3 & 2, * p = (-- * p + W) % W;
        f = 1, * (p = m + *z + z[1] * W) > 0 && (C = 27);
        for (; *p && (m[i = rand() % S] || (--m[i], ++l, --f)););
        SetConsoleCursorPosition(GetStdHandle((DWORD)-11), (COORD){0});
        for (i = 0, *p = l; i < S; _cputs("  "), ++i % W || _cputs("\n"))
            SetConsoleTextAttribute(GetStdHandle((DWORD)-11),
                m[i] > 0 ? m[i] -= f, 192 : m[i] ? 160 : 240);
    }
}
//ADSW移动, 吃到食物成长, 可穿墙, 吃到自己身体或按下Esc键时游戏结束;
//可自定义蛇头位置(z[0], z[1]), 蛇长(l), 初始方向(c), 地图尺寸(W);

走迷宫

#include <stdlib.h>
#include <conio.h>
int W = 15, S, c = 81, i, j, k, *m, *L, l[4] = {1, -1};
void init(){
	for (i = S; i-- || (c = m[i = rand() % S] == 2, k = 0);)
		m[i] = 2 + ((i + 1) % W < 2) + (i % (S - W) < W);
	for (c && (L[k++] = i); k && (j = L[i = rand() % k], 1);)
		for (L[i] = L[--k], i = m[j] & 3 ? m[j] = 0 : 4; i < 4; ++i)
			c = j + l[i], m[c] & 3 && ++m[c], m[c] & 3 && (L[k++] = c);
	for (i = c ? W : S; i >= S ? init(), 0 : m[i - W]; i += W)
		m[i] & 3 | m[S - 1 - i] & 3 || (m[j = i] = m[k = S - 1 - i] = 0);
}
int main(){
	srand(m = calloc(S = W * W, 4)), L = calloc(S, 4), l[2] -= l[3] = W;
	for (; c - 81 && j - k ? 0 : init(), c - 27; c = _getch() & 95){
		c - 87 || m[j - W] || (j -= W), c - 68 || m[j + 1] || ++j;
		c - 83 || m[j + W] || (j += W), c - 65 || m[j - 1] || --j;
		for (i = system("cls"); i < S; ++i % W || _cputs("\n"))
			_cputs(i - j ? m[i] ? "[]" : "  " : "<>");
	}
}
//ADSW移动, 按下Q键或到达另一端自动刷新, 按下Esc键时游戏结束;
//可自定义地图尺寸(W), 这个尺寸包括边界的墙

俄罗斯方块

#include <windows.h>
#include <conio.h>
#define Get(C) for (C, i = n[T]; j = X + i % 4, k = Y + i / 4 % 4, i; i >>= 4)
int W = 10, H = 25, S, i, j, k, c, d = 9, X = 0, Y = 0, T = 0, *m, n[] = {
	51264, 12816, 21520, 21520, 25872, 34113, 21537, 38208, 25921, 38481,
	38484, 38209, 25922, 43345, 34388, 38160, 25920, 38177, 42580, 38993};
int move(int* v, int l) {
	Get (*v += l)(j < 0 || j >= W || k >= H || m[k * W + j]) && (c = 0);
	return c ? 1 : (*v -= l, v == &Y && (c = -1));
}
int main() {
	SetConsoleCursorInfo(GetStdHandle((DWORD)-11), &(CONSOLE_CURSOR_INFO){1});
	for (srand(m = calloc(S = W * H, 4)), system("cls"); c - 27; Sleep(50)) {
		Get(c = _kbhit() ? _getch() & 95 : 1) m[k * W + j] = 0;
		c ^ 65 || move(&X, -1), c ^ 68 || move(&X, 1), c ^ 83 || move(&Y, 1);
		c ^ 87 || (i = T < 8 ? 1 : 3, move(&T, T & i ^ i ? 1 : -i));
		Get(--d || (d = 9, move(&Y, c = 1))) m[k * W + j] = T / 4 * 16 + 154;
		if (c == -1 && !(Y || (c = 27), T = rand() % 20, Y = X = 0))
			for (j = W, i = S - 1; j -= !!m[i], i; i-- % W || (j = W))
				for (j || (k = i += W); !j && (--k >= W); m[k] = m[k - W]);
		SetConsoleCursorPosition(GetStdHandle((DWORD)-11), (COORD){0});
		for (; i < S; _cputs("  "), ++i % W || _cputs("\n"))
			SetConsoleTextAttribute(GetStdHandle((DWORD)-11), m[i]);
	}
}
//AD移动, S下坠, W旋转, 某一行填满方块则消行, 当方块堆到顶层或按下Esc键时游戏结束;
//可自定义地图尺寸(W, H)

扫雷

//简易版
#include <stdlib.h>
#include <conio.h>
int S, W = 9, H = 9, B = 10, s, p = 0, c = 1, i, *m, *M, (*f)(int, int);
int edge(int x, int y) { return x < 0 || W <= x || y < 0 || H <= y; }
void tmp(int x, int y) { edge(x, y) || m[x += W * y] - 9 && ++m[x]; }
void dig(int v, int l) {
	for (l = edge(v, l) || M[v += W * l] || (++M[v], --s, m[v]) ? 0 : 9; l;)
		--l - 4 || --l, f(v % W + l % 3 - 1, v / W + l / 3 - 1);
}
void set(int x, int y) {
	for (f = tmp; c++ < B; m[i] = 0, dig(i % W, i / W), m[i] = 9, M[i]--)
        while (m[i = rand() % S] > 8 || (abs(x - i % W) | abs(y - i / W)) < 2);
	f = dig, s += B, dig(x, y);
}
int main() {
	f = set, s = S = W * H, m = calloc(S * 2, 4), M = m + S, srand(m);
	for ( ; B % s && !system("cls"); c = _getch() & 95, c - 27 || (B = 0)) {
		c - 68 || ++p, c - 65 || --p, c - 83 || (p += W), c - 87 || (p -= W);
		p = (p + S) % S, c || (f(p % W, p / W), m[p] < 9 || (B = 0));
		for (i = 0; B || m[i] - 9 || ++M[i], i < S; ++i % W || _cputs("\n"))
			_cprintf("%c%c", " >"[p == i], " 12345678@*"[M[i] ? m[i] : 10]);
	}
	_cputs(B ? "You win!" : "Game over!"), _getch();
}
//ADSW移动光标, 空格挖开对应格子, 剩余格子等于雷的数量或挖到雷或按下Esc键时游戏结束;
//可自定义地图尺寸(W, H), 雷的数量(B), 地图尺寸不要太小或太大
//完整版
#include<windows.h>
#include<stdio.h>
#include<time.h>
#define turn(x, y) (mapSize.X * (y) + (x))
#define Outside(x, y) (x < 0 || mapSize.X - 1 < x || y < 0 || mapSize.Y - 1 < y)
int *map, *mark, count, bomb, firstOpen, game, bombCount, baginTime;
int node[8][2] = { 1,0,-1,0,0,1,0,-1,-1,-1,-1,1,1,-1,1,1 };
char *num[10] = { "  ", "①", "②", "③", "④", "⑤", "⑥", "⑦", "⑧", "●" };
COORD size = { 18,11 }, origin = { 0,0 }, mapSize = { 0,0 }, pos = { 0,0 };
HANDLE hOut, hIn;
INPUT_RECORD Buf;
int *color[10] = { 0,11,10,12,14,1,2,6,4,4 };
//光标定位
void gotoxy(int x,int y)
{
	COORD pos;
	pos.X = x;
	pos.Y = y;
	SetConsoleCursorPosition(hOut, pos);
}
//设置窗口大小
void setScreenSize(int lines, int cols)
{
	COORD size = { lines,cols };
	SMALL_RECT rect = { 0,0,size.X - 1,size.Y - 1 };
	SetConsoleWindowInfo(hOut, 1, &rect);
	SetConsoleScreenBufferSize(hOut, size);
	SetConsoleWindowInfo(hOut, 1, &rect);
}
//隐藏光标
void hideCursor()
{
	CONSOLE_CURSOR_INFO CursorInfo;
	GetConsoleCursorInfo(hOut, &CursorInfo);
	CursorInfo.bVisible = 0;
	SetConsoleCursorInfo(hOut, &CursorInfo);
}
//精准延时
void delay(int ms)
{
	static clock_t oldtime = 0;
	while (clock() - ms < oldtime)
		Sleep(1);
	oldtime = clock();
}
//翻开一个位置
void open(int x,int y)
{
	if (Outside(x,y))return;
	if (!mark[turn(x,y)])return;
	mark[turn(x, y)] = 0;
	gotoxy(x * 2, y);
	SetConsoleTextAttribute(hOut, color[map[turn(x, y)]]);
	printf(num[map[turn(x, y)]]);
	count--;
	if (map[turn(x, y)] > 0)return;
	for (int i = 0; i < 8; i++)
		open(x + node[i][0], y + node[i][1]);
}
//标记一个位置
void sign(int x, int y)
{
	if (Outside(x, y))return;
	int *temp = &mark[turn(x, y)];
	if (!*temp)return;
	gotoxy(x * 2, y);
	if (*temp == 1)
	{
		*temp = 2;
		SetConsoleTextAttribute(hOut, 4);
		printf("★");
		bombCount--;
	}
	else
	{
		*temp = 1;
		SetConsoleTextAttribute(hOut, 15);
		printf("■");
		bombCount++;
	}
}
//设置炸弹
void setBomb(int x, int y)
{
	for (int i = 0,j,k; i < bomb;)
	{
		j = rand() % mapSize.X, k = rand() % mapSize.Y;
		if ((-2 < x - j && x - j < 2) && (-2 < y - k && y - k < 2))continue;
		if (map[turn(j, k)] == 9)continue;
		map[turn(j, k)] = 9, i++;
		for (int i = 0,m,n; i < 8; i++)
		{
			m = j + node[i][0], n = k + node[i][1];
			if (!Outside(m, n) && map[turn(m, n)] - 9)map[turn(m, n)]++;
		}
	}
}
//展开
void fun(int x,int y)
{
	int num = 0;
	for (int i = 0,j,k; i < 8; i++)
	{
		j = x + node[i][0], k = y + node[i][1];
		if (!Outside(j, k) && mark[turn(j, k)] == 2)num++;
	}
	if (map[turn(x, y)] == num)
	{
		for (int i = 0,j,k; i < 8; i++)
		{
			j = x + node[i][0], k = y + node[i][1];
			if (Outside(j, k) || mark[turn(j, k)] - 1)continue;
			if (open(j, k), map[turn(j, k)] == 9)game = 0;
		}
	}
}

int main()
{
	int Result, i = 0, fps = 10;
	hIn = GetStdHandle(STD_INPUT_HANDLE);
	hOut = GetStdHandle(STD_OUTPUT_HANDLE);
	hideCursor();
back:;
	setScreenSize(18, 11);
	FillConsoleOutputCharacter(hOut, ' ', (size.X - 1)*(size.Y + 1), origin, &i);
	SetConsoleCursorPosition(hOut, origin);
	SetConsoleTextAttribute(hOut, 15), printf("   Minesweeper!  \n\n");
	SetConsoleTextAttribute(hOut, 10), printf("       Easy      \n");
	SetConsoleTextAttribute(hOut, 14), printf("      Medium     \n");
	SetConsoleTextAttribute(hOut, 13), printf("       Hard      \n");
	SetConsoleTextAttribute(hOut, 12), printf("      Custom     \n\n\n");
	SetConsoleTextAttribute(hOut, 11), printf(" by:RainbowRoad1");
	SetConsoleTextAttribute(hOut, 15);
	while (1)
	{
		ReadConsoleInput(hIn, &Buf, 1, &Result);
		pos = Buf.Event.MouseEvent.dwMousePosition;
		if (Buf.Event.MouseEvent.dwButtonState)
		{
			if (pos.Y == 2)mapSize.X = mapSize.Y = 9, bomb = 10;
			else if (pos.Y == 3)mapSize.X = mapSize.Y = 16, bomb = 40;
			else if (pos.Y == 4)mapSize.X = 30, mapSize.Y = 16, bomb = 99;
			else if (pos.Y == 5)
			{
				gotoxy(0, 6);
				printf("input:");
				scanf_s("%d,%d,%d", &mapSize.X, &mapSize.Y, &bomb);
				num[0] = "  ";
			}
			else continue;
			break;
		}
		if (GetAsyncKeyState(' ') & 0x8000)exit(0);
	}
	size.X = mapSize.X * 2, size.Y = mapSize.Y + 2;
	setScreenSize(size.X, size.Y);
	Sleep(100);
	FlushConsoleInputBuffer(hIn);
restart:;
	srand((unsigned)time(0));
	if (map)free(map);
	if (mark)free(mark);
	map = (int*)calloc(mapSize.X*mapSize.Y, sizeof(int));
	mark = (int*)calloc(mapSize.X*mapSize.Y, sizeof(int));
	count = mapSize.X*mapSize.Y, bombCount = bomb;
	firstOpen = 1, game = 1, baginTime = clock();
	SetConsoleTextAttribute(hOut, 15);
	SetConsoleCursorPosition(hOut, origin);
	for (i = 0; i < mapSize.X*mapSize.Y;i++)printf("■");
	for (i = 0; i < mapSize.X*mapSize.Y; i++)mark[i] = 1;
	gotoxy(mapSize.X * 2 - 7, mapSize.Y);
	printf("restart");
	gotoxy(mapSize.X * 2 - 5, mapSize.Y + 1);
	printf("back");
	while (1)
	{
		if (GetNumberOfConsoleInputEvents(hIn, &i));
		if (i)
		{
			while (i--)
			{
				ReadConsoleInput(hIn, &Buf, 1, &Result);
				pos = Buf.Event.MouseEvent.dwMousePosition;
				if (Buf.Event.MouseEvent.dwButtonState)
				{
					pos.X = pos.X / 2;
					switch (Buf.Event.MouseEvent.dwButtonState)
					{
					case FROM_LEFT_1ST_BUTTON_PRESSED:
						if (firstOpen)setBomb(pos.X, pos.Y), firstOpen = 0;
						open(pos.X, pos.Y);
						if (map[turn(pos.X, pos.Y)] == 9)game = 0;
						if (pos.Y == mapSize.Y)goto restart;
						if (pos.Y == mapSize.Y + 1)goto back;
						break;
					case RIGHTMOST_BUTTON_PRESSED:
						if (!Outside(pos.X, pos.Y))sign(pos.X, pos.Y); break;
					case FROM_LEFT_2ND_BUTTON_PRESSED:
						if (!Outside(pos.X, pos.Y))fun(pos.X, pos.Y); break;
					}
				}
			}
		}
		gotoxy(0, mapSize.Y);
		SetConsoleTextAttribute(hOut, 1);
		if (count <= bomb && printf("\nyou win!     "))break;
		if (!game)
		{
			printf("\nGame over!   ");
			SetConsoleTextAttribute(hOut, 4);
			for (i=0; i < mapSize.X*mapSize.Y; i++)
				if (map[i] == 9 && mark[i])
				{
					gotoxy(i%mapSize.X * 2, i / mapSize.X);
					printf("●");
				}
			break;
		}
		SetConsoleTextAttribute(hOut, 15);
		printf("time:%-5d\nresidue:%-5d", (clock() - baginTime) / 1000, bombCount);
		delay(1000 / fps);
	}
	while (1)
	{
		ReadConsoleInput(hIn, &Buf, 1, &Result);
		pos = Buf.Event.MouseEvent.dwMousePosition;
		if (Buf.Event.MouseEvent.dwButtonState)
		{
			if (pos.Y == mapSize.Y)goto restart;
			if (pos.Y == mapSize.Y + 1)goto back;
		}
		if (GetAsyncKeyState(' ') & 0x8000)break;
		Sleep(1000 / fps);
	}
}
//交互更加友好: 鼠标左键点击, 右键标记, 中键展开
//增加一个难度选择的主菜单, 可自定义难度
//界面更加直观, 有剩余雷数和用时显示
//游戏时增加了重置和返回菜单的选项
2021/3/5 23:51
加载中...