天天看點

c語言——五子棋遊戲一、前言二、頭檔案三、menu菜單函數四、初始化棋盤Initboard函數五、顯示棋盤Displayboard函數六、落子函數七、判斷輸赢ifwin八、人機、人人模式的選擇九、作者遇到的坑點十、完整的代碼

目錄

一、前言

二、頭檔案

三、menu菜單函數

四、初始化棋盤Initboard函數

五、顯示棋盤Displayboard函數

六、落子函數

七、判斷輸赢ifwin

八、人機、人人模式的選擇

九、作者遇到的坑點

十、完整的代碼

一、前言

本文将先介紹五子棋運作所需要的函數,最後串聯成完整代碼。

我們需要實作的功能有:1.菜單menu函數 

                                        2.初始化棋盤Initboard函數

                                        3.顯示棋盤Displayboard函數

                                        4.實作人機、人人模式的選擇

                                        5.落子函數 playermove  computermove

                                        6.判斷輸赢ifwin函數

 先來看看運作效果吧!

c語言——五子棋遊戲一、前言二、頭檔案三、menu菜單函數四、初始化棋盤Initboard函數五、顯示棋盤Displayboard函數六、落子函數七、判斷輸赢ifwin八、人機、人人模式的選擇九、作者遇到的坑點十、完整的代碼

二、頭檔案

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include<time.h>
#include<stdlib.h>
#include<windows.h>
#define	ROW 10  //定義棋盤的寬
#define COL 10  //定義棋盤的長
                //定義常量友善全局的修改
void Initboard(char board[ROW][COL], int row, int col);
//初始化棋盤
void Displayboard(char board[ROW][COL], int row, int col);
//展示棋盤
void Playermove_1(char board[ROW][COL], int row, int col,int*px,int *py);
//玩家一下棋
void Playermove_2(char board[ROW][COL], int row, int col,int*px, int *py);
//玩家二下棋
void computermove(char board[ROW][COL], int row, int col);
//電腦下棋
void game1(char board[ROW][COL], int row, int col);
//人機模式
void game2(char board[ROW][COL], int row, int col);
//人人模式
int Ifwin(char board[ROW][COL], int row, int col, int x, int y);
//判斷輸赢
int check_x(char board[ROW][COL], int row, int col, int x, int y);
//判斷豎直五子
int check_y(char board[ROW][COL], int row, int col, int x, int y);
//判斷水準五子
int check_xy_up(char board[ROW][COL], int row, int col, int x, int y);
//判斷斜上五子
int check_xy_down(char board[ROW][COL], int row, int col, int x, int y);
//判斷斜下五子
           

三、menu菜單函數

void menu()
{   //完成菜單的初始化
	printf("***********************\n");
	printf("***********************\n");
	printf("*****1.play  0.exit****\n");
	printf("***********************\n");
	printf("***********************\n");
	printf("請輸入:");
}
           

很簡單,就不多說了

四、初始化棋盤Initboard函數

初始化棋盤,為數組一一存入空格

void Initboard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}
}
           

五、顯示棋盤Displayboard函數

列印簡單的方格線,并列印資料内容

void Displayboard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (j = 0; j < col; j++)//列印橫向y坐标
	{
		if (j == 0)//考慮到x軸所占的一格
		{
			printf("  %d  ", j + 1);
			
		}
		else
		{
			printf(" %d  ", j + 1);
			
		}
	}
	printf("\n");
	for (i = 0; i < row; i++)//列印資料
	{

		for (j = 0; j < col; j++)
		{
			
			if (j == 0)//順帶列印豎向x坐标
			{
				printf("%2d",i+1);//%md表示域寬為m
				printf("  %c ",board[i][j]);
				
			}
			else
			{
				printf(" %c ", board[i][j]);
			}
			
			if (j < col - 1)
				printf("|");
		}
		printf("\n");

		//列印分割行
		if (i < row - 1)
		{
			for (j = 0; j < col; j++)
			{
				if (j == 0)//同樣考慮到y軸
					printf("   ---");
				else
					printf("---");


				if (j < col - 1)
					printf("|");

			}
			printf("\n");

		}
	}

}
           

六、落子函數

玩家一落子——playermove_1

void Playermove_1(char board[ROW][COL], int row, int col, int *px, int*py)//ROW可以省,COL不行
{
	int x = *px;
	int y = *py;
	while (1)
	{
		
		if (x >= 1 && x <= row && y >= 1 && y <= col)//判斷輸入坐标的合法性
		{
			if (board[x -1][y- 1] == ' ')//保證落子點為空
			{							 
				board[x-1 ][y -1] = '*';
				*px = x; *py = y;//如果開始xy輸入不合法,則要對外部xy修改,是以選擇傳址操作
				break;
			}
			else
			{
				printf("你不能在此處落子\n");
				printf("玩家1落子,請重新輸入x y坐标: ");
				scanf("%d%d", &x, &y);
			}
		}
		else
		{
			printf("輸入坐标不合法\n");
			printf("玩家落子,請重新輸入x y坐标: ");
			scanf("%d%d", &x, &y);
		}
	}

}
           

玩家2落子完全相同,就不贅叙了

電腦落子

void computermove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	
    //rand函數的使用需要srand函數的初始化,但srand不可以被重複調用,是以放在外部
	while (1)
	{
		x = rand() % ROW;
		y = rand() % COL;
		if (board[x][y] == ' ')//x的範圍在0~row-1,是以這裡x不用-1了
		{
			board[x][y] = '#';
			break;
		}
	}

}
           

七、判斷輸赢ifwin

根據我們下五子棋的經驗,能獲勝的地方必定是最後落子的水準線、豎直線、和兩個斜對角線,我們隻需對其進行檢索即可。ifwin的傳回值決定之後的switch語句

弱弱的說一句,雖然看起來多,但很多都是重複的。若要優化就使用函數指針

int Ifwin(char board[ROW][COL], int row, int col, int x, int y)
{
	int ret;
	{
		ret = check_x(board, row, col, x, y);
		if (ret >= 5)
			return 0;

		ret = check_y(board, row, col, x, y);
		if (ret >= 5)
			return 0;
		ret = check_xy_up(board, row, col, x, y);
		if (ret >= 5)
			return 0;
		ret = check_xy_down(board, row, col, x, y);
		if (ret >= 5)
			return 0;
	}

		return 3;
}



int check_x(char board[ROW][COL], int row, int col, int x, int y)//檢查x軸豎直方向
{
	int sum = 1;
	int old_x = x;
	while (x < row  && board[x - 1][y - 1] == board[x][y - 1])
	{
		sum++;
		x++;
	}
	x = old_x;
	while (x-2>= 0 && board[x - 1][y - 1] == board[x - 2][y - 1] )
	{
		sum++;
		x--;
	}
	return sum;
}



int check_y(char board[ROW][COL], int row, int col, int x, int y)//檢查y軸水準方向
{
	int sum = 1;
	int old_y = y;
	while (y<col && board[x-1][y-1] == board[x-1][y]  )
	{
		sum++;
		y++;
	}
	y = old_y;
	while (y-2 >= 0 && board[x-1][y-1] == board[x-1][y -2]  )
	{
		sum++;
		y--;
	}
	return sum;
}



int check_xy_up(char board[ROW][COL], int row, int col, int x, int y)//檢查斜上45度
{
	int sum = 1;
	int old_x = x;
	int old_y = y;
	while (x<row &&  y - 2 >= 0 && board[x - 1][y - 1] == board[x][y - 2])
	{
		sum++;
		x++;
		y--;
	}
	x = old_x;
	y = old_y;
	while (x - 2 >= 0 && y <col && board[x - 1][y - 1] == board[x - 2][y])
	{
		sum++;
		x--;
		y++;
	}
	return sum;
}



int check_xy_down(char board[ROW][COL], int row, int col, int x, int y)//檢查斜下45度
{
	int sum = 1;
	int old_x = x;
	int old_y = y;
	while (x<row && y <col && board[x - 1][y - 1] == board[x][y])
	{
		sum++;
		x++;
		y++;
	}
	x = old_x;
	y = old_y;
	while (board[x-1][y-1] == board[x -2][y-2 ] && x-2>=0  && y-2 >=0)
	{
		sum++;
		x--;
		y--;
	}
	return sum;
}
           

八、人機、人人模式的選擇

初始選擇界面

void game()
{
	int input;
	char board[ROW][COL] = { 0 };
	Initboard(board, ROW, COL);
	//初始化棋盤
	Displayboard(board, ROW, COL);
	//展示棋盤
	printf("請選擇模式:1.人機;2.玩家對戰\n");
	printf("請選擇:");
	

	do{
		scanf("%d", &input);
		printf("\n");
		switch (input)
		{
		case 1:printf("遊戲模式1開始!(注意:豎為x軸,橫為y軸)\n");  game1(board, ROW, COL); break;
		case 2:printf("遊戲模式2開始!(注意:豎為x軸,橫為y軸)\n"); ; game2(board, ROW, COL); break;
		default:printf("請重新輸入\n"); break;
		}
	} while (input != 1 && input != 2);//do while語句在輸入錯誤時反複輸入
}
           

game1的具體實作

void game1(char board[ROW][COL], int row, int col)
{
	srand((unsigned int)time(NULL));//srand隻要設定一次就可以,是以要放在while循環外
	while (1)
	{
		int ret;
		int count = 0;
		int flag = 0;
		//判讀玩家的下棋
		int x; int y;
		printf("玩家落子,請依次輸入x y坐标: ");
		scanf("%d%d", &x, &y);
		Playermove_1(board, row, col,&x, &y);
		count++;
		Displayboard(board, ROW, COL);
		if (count == ROW*COL)//全下滿則認為平局
			ret = 1;
		else 
		    ret = Ifwin(board, ROW, COL, x, y);
		switch (ret)
		{
		case 0:printf("玩家獲勝\n"); flag = 1; break;
		case	 1:printf("平局\n"); flag = 1; break;
		default: break;
		}
		if (flag == 1)//用flag跳出while循環
			break;


		//判斷計算機的下棋
		computermove(board, row, col);
		count++;
		Displayboard(board, ROW, COL);
		if (count == ROW*COL)
			ret = 1;
		else
			ret = Ifwin(board, ROW, COL, x, y);
		switch (ret)
		{
		case 0:printf("電腦獲勝\n"); flag = 1; break;
		case	 1:printf("平局\n"); flag = 1; break;
		default: break;

		}
		if (flag == 1)
			break;

	}


}

           

作者覺得寫的是挺啰嗦,歡迎留言建議。game2和game1玩家一的内容很相近,就不贅述

九、作者遇到的坑點

1.輸入的坐标和存在數組裡的下标有減一的關系,在寫的時候不要寫忘記了

2.傳址操作才能改變函數外的變量值

十、完整的代碼

頭檔案就省了

int main()
{
	int input;
	do{
		system("cls");//清屏
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("遊戲開始\n\n");  game(); break;
		case 0:
			printf("退出遊戲\n"); break;
		default:
			printf("請重新輸入\n"); break;
		}
		
		Sleep(3000);//暫停3秒
	} while (input);//do while語句實作可以反複玩


	return 0;
}





void menu()
{   //完成菜單的初始化
	printf("***********************\n");
	printf("***********************\n");
	printf("*****1.play  0.exit****\n");
	printf("***********************\n");
	printf("***********************\n");
	printf("請輸入:");
}





void Initboard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}
}





void Displayboard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (j = 0; j < col; j++)//列印橫向y坐标
	{
		if (j == 0)//考慮到x軸所占的一格
		{
			printf("  %d  ", j + 1);
			
		}
		else
		{
			printf(" %d  ", j + 1);
			
		}
	}
	printf("\n");
	for (i = 0; i < row; i++)//列印資料
	{

		for (j = 0; j < col; j++)
		{
			
			if (j == 0)//順帶列印豎向x坐标
			{
				printf("%2d",i+1);//%md表示域寬為m
				printf("  %c ",board[i][j]);
				
			}
			else
			{
				printf(" %c ", board[i][j]);
			}
			//數字表示坐标
			if (j < col - 1)
				printf("|");
		}
		printf("\n");
		//列印分割行
		if (i < row - 1)
		{
			for (j = 0; j < col; j++)
			{
				if (j == 0)//同樣考慮到y軸
					printf("   ---");
				else
					printf("---");


				if (j < col - 1)
					printf("|");

			}
			printf("\n");//别忘記這裡也要換行

		}
	}

}





void game()
{
	int input;
	char board[ROW][COL] = { 0 };
	Initboard(board, ROW, COL);
	//初始化棋盤
	Displayboard(board, ROW, COL);
	//展示棋盤
	printf("請選擇模式:1.人機;2.玩家對戰\n");
	printf("請選擇:");
	

	do{
		scanf("%d", &input);
		printf("\n");
		switch (input)
		{
		case 1:printf("遊戲模式1開始!(注意:豎為x軸,橫為y軸)\n");  game1(board, ROW, COL); break;
		case 2:printf("遊戲模式2開始!(注意:豎為x軸,橫為y軸)\n"); ; game2(board, ROW, COL); break;
		default:printf("請重新輸入\n"); break;
		}
	} while (input != 1 && input != 2);//do while語句在輸入錯誤時反複輸入
}




void game1(char board[ROW][COL], int row, int col)
{
	srand((unsigned int)time(NULL));//srand隻要設定一次就可以,是以要放在while循環外
	while (1)
	{
		int ret;
		int count = 0;
		int flag = 0;
		//判讀玩家的下棋
		int x; int y;
		printf("玩家落子,請依次輸入x y坐标: ");
		scanf("%d%d", &x, &y);
		Playermove_1(board, row, col,&x, &y);
		count++;
		Displayboard(board, ROW, COL);
		if (count == ROW*COL)//全下滿則認為平局
			ret = 1;
		else 
		    ret = Ifwin(board, ROW, COL, x, y);
		switch (ret)
		{
		case 0:printf("玩家獲勝\n"); flag = 1; break;
		case	 1:printf("平局\n"); flag = 1; break;
		default: break;
		}
		if (flag == 1)//用flag跳出while循環
			break;


		//判斷計算機的下棋
		computermove(board, row, col);
		count++;
		Displayboard(board, ROW, COL);
		if (count == ROW*COL)
			ret = 1;
		else
			ret = Ifwin(board, ROW, COL, x, y);
		switch (ret)
		{
		case 0:printf("電腦獲勝\n"); flag = 1; break;
		case	 1:printf("平局\n"); flag = 1; break;
		default: break;

		}
		if (flag == 1)
			break;

	}


}






void game2(char board[ROW][COL], int row, int col)
{
	while (1)
	{
		int ret;
		int count = 0;
		int flag = 0;
		int x; int y;
		//判讀玩家1的下棋
		printf("玩家1落子,請輸入坐标:(注意:豎為x軸,橫為y軸)");
		scanf("%d%d", &x, &y);
		Playermove_1(board, row, col, &x, &y);
		count++;
		Displayboard(board, ROW, COL);
		if (count == ROW*COL)
			ret = 1;
		else
			ret = Ifwin(board, ROW, COL, x, y);
		switch (ret)
		{
		case 0:printf("玩家1獲勝\n"); flag = 1; break;
		case	 1:printf("平局\n"); flag = 1; break;
		default: break;
		}
		if (flag == 1)
			break;


		//判斷玩家2的下棋
		printf("玩家2落子,請輸入坐标:(注意:豎為x軸,橫為y軸)");
		scanf("%d%d", &x, &y);
		Playermove_2(board, row, col, &x, &y);
		count++;
		Displayboard(board, ROW, COL);
		if (count == ROW*COL)
			ret = 1;
		else
			ret = Ifwin(board, ROW, COL, x, y);
		switch (ret)
		{
		case 0:printf("玩家2獲勝\n"); flag = 1; break;
		case	 1:printf("平局\n"); flag = 1; break;
		default: break;
		}
		if (flag == 1)
			break;
		
	}


}





void Playermove_1(char board[ROW][COL], int row, int col, int *px, int*py)//ROW可以省,COL不行
{
	int x = *px;
	int y = *py;
	while (1)
	{
		
		if (x >= 1 && x <= row && y >= 1 && y <= col)//判斷輸入坐标的合法性
		{
			if (board[x -1][y- 1] == ' ')//保證落子點為空
			{							 
				board[x-1 ][y -1] = '*';
				*px = x; *py = y;//如果開始xy輸入不合法,要對外部xy修改,是以要傳址操作
				break;
			}
			else
			{
				printf("你不能在此處落子\n");
				printf("玩家1落子,請重新輸入x y坐标: ");
				scanf("%d%d", &x, &y);
			}
		}
		else
		{
			printf("輸入坐标不合法\n");
			printf("玩家落子,請重新輸入x y坐标: ");
			scanf("%d%d", &x, &y);
		}
	}

}





void Playermove_2(char board[ROW][COL], int row, int col, int *px, int*py)
{
	int x = *px;
	int y = *py;
	while (1)
	{
		
		if (x >= 1 && x <= row && y >= 1 && y <= col)//判斷輸入坐标的合法性
		{
			if (board[x - 1][y - 1] == ' ')//保證落子點為空
			{
				board[x - 1][y - 1] = '#';
				*px = x; *py = y;
				break;
			}
			else
			{
				printf("你不能在此處落子\n");
				printf("玩家2落子,請重新輸入x y坐标: ");
				scanf("%d%d", &x, &y);
			}
		}
		else
		{
			printf("輸入坐标不合法\n");
			printf("玩家落子,請重新輸入x y坐标: ");
			scanf("%d%d", &x, &y);
		}
	}

}






void computermove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	

	while (1)
	{
		x = rand() % ROW;
		y = rand() % COL;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}

}




int Ifwin(char board[ROW][COL], int row, int col, int x, int y)
{
	int ret;
	{
		ret = check_x(board, row, col, x, y);
		if (ret >= 5)
			return 0;

		ret = check_y(board, row, col, x, y);
		if (ret >= 5)
			return 0;
		ret = check_xy_up(board, row, col, x, y);
		if (ret >= 5)
			return 0;
		ret = check_xy_down(board, row, col, x, y);
		if (ret >= 5)
			return 0;
	}

		return 3;
}



int check_x(char board[ROW][COL], int row, int col, int x, int y)//檢查x軸豎直方向
{
	int sum = 1;
	int old_x = x;
	while (x < row  && board[x - 1][y - 1] == board[x][y - 1])
	{
		sum++;
		x++;
	}
	x = old_x;
	while (x-2>= 0 && board[x - 1][y - 1] == board[x - 2][y - 1] )
	{
		sum++;
		x--;
	}
	return sum;
}



int check_y(char board[ROW][COL], int row, int col, int x, int y)//檢查y軸水準方向
{
	int sum = 1;
	int old_y = y;
	while (y<col && board[x-1][y-1] == board[x-1][y]  )
	{
		sum++;
		y++;
	}
	y = old_y;
	while (y-2 >= 0 && board[x-1][y-1] == board[x-1][y -2]  )
	{
		sum++;
		y--;
	}
	return sum;
}



int check_xy_up(char board[ROW][COL], int row, int col, int x, int y)//檢查斜上45度
{
	int sum = 1;
	int old_x = x;
	int old_y = y;
	while (x<row &&  y - 2 >= 0 && board[x - 1][y - 1] == board[x][y - 2])
	{
		sum++;
		x++;
		y--;
	}
	x = old_x;
	y = old_y;
	while (x - 2 >= 0 && y <col && board[x - 1][y - 1] == board[x - 2][y])
	{
		sum++;
		x--;
		y++;
	}
	return sum;
}



int check_xy_down(char board[ROW][COL], int row, int col, int x, int y)//檢查斜下45度
{
	int sum = 1;
	int old_x = x;
	int old_y = y;
	while (x<row && y <col && board[x - 1][y - 1] == board[x][y])
	{
		sum++;
		x++;
		y++;
	}
	x = old_x;
	y = old_y;
	while (board[x-1][y-1] == board[x -2][y-2 ] && x-2>=0  && y-2 >=0)
	{
		sum++;
		x--;
		y--;
	}
	return sum;
}
           

如果對你有幫助和啟發,作者感到很高興。如果有好的建議,歡迎留言。如果發現錯誤,歡迎指正。新手上路,多多指點 

c語言——五子棋遊戲一、前言二、頭檔案三、menu菜單函數四、初始化棋盤Initboard函數五、顯示棋盤Displayboard函數六、落子函數七、判斷輸赢ifwin八、人機、人人模式的選擇九、作者遇到的坑點十、完整的代碼

繼續閱讀