多文件實現三子棋

三子棋

多文件實現,分裝成三個模塊。
聲明部分 game.h

#ifndef _GAME_H_
#define _GAME_H_

#include<stdio.h>
#include<windows.h>
#pragma warning(disable:4996)
#include<string.h>

#include<stdlib.h>
#include<time.h>


#define ROW 3
#define COL 3


void game();
void InitBoard(char Board[][COL],int row,int col);
void ShowBoard(char Board[][COL], int row, int col);
void Player(char Board[][COL], int row, int col);
char Judge(char Board[][COL], int row, int col);
void Computer(char Board[][COL], int row, int col);
//player--0
//computer--x
//‘e’平局
// ‘n'--next
#endif

主架構邏輯
main.c

#include"game.h"
void menu()
{
	printf("歡迎遊戲參與三子棋遊戲!\n");
	printf("1--玩遊戲  2--退出遊戲\n");
	printf("請輸入你的選項:>\n");
}
int main()
{
	int intput = 0;
	srand((unsigned int)time(NULL));
  do{
	menu();
	scanf("%d", &intput);
	switch (intput)
	{
	case 1:
		game();
		break;
	case 2:
		intput = 0;
		printf("成功退出遊戲\n");
		break;
	default:
		printf("輸入有誤,請重新輸入\n");
	}
  }while (intput);

	

	system("pause");
	return 0;
}

遊戲具體的實現部分
game.c

#include"game.h"
void InitBoard(char Board[][COL], int row, int col)
{
	//memset函數
	//memset(void*dest,int c,size_t count)
	memset(Board, ' ', row*col*(sizeof(Board[0][0])));


	//int i = 0;
	//for (; i < row; i++)
	//{
	//	int j = 0;
	//	for (; j < col; j++)
	//	{
	//		 Board[i][j]=' '  ;
	//	}
	//}
}
void ShowBoard(char Board[][COL], int row, int col)
{
	//列號
	int j = 0;
	{
		for (j=0; j < col+1; j++)
		{
			printf(" %d  ", j);
		}
	}
	printf("\n");
	
	int i = 0;
	for (; i < row; i++)
	{
		printf(" %d |", i + 1);
		int j = 0;
		for (; j < col; j++)
		{

			printf(" %c |",Board[i][j]);
		}
		printf("\n");
		if (i < row )
		{
			for (j = 0; j <= col; j++)
			{
				printf("___|");
			}
			printf("\n");
		}
	}
	
}

void Player(char Board[][COL], int row, int col)
{
	printf("請輸入你所選擇位置對應的座標\n");
	int x = 0;
	int y = 0;
	while (1){
		scanf("%d %d", &x, &y);
		//判斷座標合法性
		//1不被佔用
		if (x > 0 && x <= row  && y > 0 && y <= col )
		{
			if (Board[x - 1][y - 1] ==' ')
			{
				Board[x - 1][y - 1] = '0';
				break;
			}
			else
			{
				printf("座標被佔用,請重新輸入\n");
				continue;
			}
		}
		//2沒有出界
		else
		{
			printf("輸入座標不合法,請重新輸入!\n");
		}
	}

}
char Judge(char Board[][COL], int row, int col)
{
	//任何一方贏的情況
	int i = 0;
		//判斷一行
	for (; i < row; i++)
	{
		if (Board[i][0] != ' ' && Board[i][0] == Board[i][1] && Board[i][1] == Board[i][2]){
			return Board[i][0];
		}
	}
	   //判斷一列
	int j = 0;
	for (j = 0; j < col; j++)
	{
		if (Board[0][j] != ' ' && Board[0][j] == Board[1][j] && Board[1][j] == Board[2][j])
		{
			return Board[0][j];
		}
	}
	   //主對角線
	if (Board[0][0] != ' ' && Board[0][0] == Board[1][1] && Board[1][1] == Board[2][2])
	{
		return Board[0][0];
	}
	   //副對角線
	if (Board[0][2] != ' ' && Board[0][2] == Board[1][1] && Board[1][1] == Board[2][0])
	{
		return Board[1][1];
	}

    //還有空位置--繼續
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (Board[i][j] == ' ')
			{
				return 'n';
			}
		}
	}
     //平局
		return 'e';
}

void Computer(char Board[][COL], int row, int col)
{
	do
	{
		int x = rand() % row;
		int y = rand() % col;
		//座標一定是合法的,關鍵看有沒有被佔用
		if (Board[x][y] == ' ')
		{
			Board[x][y] = 'x';
			break;
		}
		//被佔用的話就重新生成座標
	} while (1);//注意語法 do while 語句後有;
	printf("電腦已運行完畢!\n");
}

void game()
{
     
	//建立棋盤 賦值爲空字符 注意類型
	char Board[ROW][COL];
	//初始化棋盤
	InitBoard(Board, ROW, COL);//meyset 初始化另一種方式
    ShowBoard(Board, ROW, COL);
	printf("請玩家先走!\n");
	//玩遊戲階段
	char result = 'n';
	while (1)
	{
	 
	  Player(Board, ROW, COL);
	  ShowBoard(Board, ROW, COL);

	  Judge(Board, ROW, COL);
	  result = Judge(Board, ROW, COL);
	  if (result != 'n')
	  {
		  break;
	  }
	  
	  printf("輪到電腦下棋了!\n");
	  Sleep(1000);
	  Computer(Board, ROW, COL);
	  ShowBoard(Board, ROW, COL);

	  Judge(Board, ROW, COL);
	  result = Judge(Board, ROW, COL);
	  if (result != 'n')
	  {
		  break;
	  }

    }
	switch (result)
	{
	case'x':
		printf("電腦贏!\n");
		break;
	case'0':
		printf("玩家贏!\n");
		break;
	case'e':
		printf("平局,沒有一方贏得本次遊戲!\n");
		break;
	default:
		printf("hhh\n");
		break;
	}
	system("pause");
	
}

代碼解釋

=每一個部分開始會先解釋這一個部分的功能(或者說邏輯思維關係)之後會具體解釋一些函數、語句的用法。
聲明部分
主要爲整個工程裏面需要引用的頭文件、定義的宏以及函數的聲明。

1.//player–0
//computer–x
//‘e’平局
// ‘n’–next
不同字符所對應的意思
2.#define ROW 3
#define COL 3
動態實現棋盤的變化,代碼可維護性比較高
3.在聲明函數的部分,請注意是否需要返回值和傳什麼參。
(二維數組傳參本質也是一個指針,故而傳遞的本質是傳址調用)因此通過函數傳遞數組名—傳地址——就可以給數組賦值。
主要框架邏輯

始終要注意的一點就是,系統要上,流程先行
主要框架要有一個流程圖在心裏,這要代碼邏輯性纔會強。(故而這也是此遊戲最先搭建的部分)

1.do循環讓用戶自己選擇是否進行下一次遊戲,而不是一次遊戲就結束。
2.用switch case 語句來實現分支選擇的功能。
遊戲具體的實現部分

寫具體遊戲之前,要先明白有這個遊戲真正在幹什麼,有哪些需求
整理遊戲需求如下:
實現讓玩家一步電腦一步在棋盤裏下棋並且判斷每一步的運行結果。
此代碼以玩家先行爲例子:
----玩家通過座標輸入,選擇下棋的位置(判斷座標輸入)
----判斷這一步棋對整個遊戲的結果(贏了,輸了,還是怎麼樣?當然下的第一步不存在這個問題)
-----電腦通過事先種好的隨機種子生成隨機數,生成座標,下棋
-----判斷運行結果

1.InitBoard 初始化棋盤部分

建議使用memset 函數,兩個for循環也不是不可以,只是memset 一行就會解決。
循環部分不多介紹,主要來談一下
Memset 函數

memset(void*dest,int c,size_t count)

voiddest 表示指針 ,從哪開始賦值
int c 把它們賦值成什麼以及什麼類型
size_t count 賦值的字節大小 ==元素個數
每一個元素的字節 rowcol(sizeof(Board[0][0])))

2.ShowBoard 打印棋盤部分

高能預警!!!

先看一個圖(因爲我畫圖板技能爲0,甚至爲負數,所以諒解手畫一個棋盤,方便且快速)
在這裏插入圖片描述
如下我把每一行這樣的棋盤樣式分解爲下圖(現在問題就分解爲先打印下圖這一部分,然後循環就行了)
在這裏插入圖片描述

實際上打印上圖這樣的棋盤
先打印空格 然後放字符 再打空格 再一次打印| 對應語句:printf(" %c |",Board[i][j]); 循環三次
換行打印
換行打印三個_一個 | 對應語句:printf(" ___|"); 循環三次

希望我蒼白的語言能讓你理解(哈哈哈哈哈)

3.Player 玩家下棋部分
判斷座標輸入的合法性,以及是否此座標被佔用。若以上情況看都不滿足則纔可以對此位置賦值。
4.Judge 判斷遊戲結果部分
主要是
一贏 : ①一行三子連線
②一列三子連線
③主副對角線三子連線
二.無任何一方贏,並且仍有空位置,遊戲繼續
三.以上均不滿足:平局(即棋盤被下完,沒有一方勝利)

5.Computer 電腦下棋部分
主要是需要電腦隨機生成座標,並且此座標沒有被佔用
在開始時,用時間作爲隨機數的種子
srand((unsigned int)time(NULL));
用生成隨機數函數 注意:生成的隨機數是有要求的,保證不會出界。(即必須保證數字 x的範圍在0—row-1 ,y的範圍在0—col-1。否則你生成任意一個大數字作爲座標,就數組出界)
int x = rand() % row;)
int y = rand() % col;

乾貨內容已經結束,下面部分可忽略不看

覆盤

我不是一個邏輯思維特別強的人,所以以後會特別注重在寫這種比較複雜的工程之前,先理清邏輯框架
即使這樣會花費很長時間。做不到邊敲代碼邊能理清思路就一點點來!

在這種行數兩三百行的代碼中,細節真的非常重要,還是有發現一些平常學習不細緻的地方。
比如關於任何一方下完棋之後,都要重新賦值rusult 。do{} while(); 語句後面的分號也常常被我遺漏。

大家彼此學習,相互參照!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章