三子棋
多文件實現,分裝成三個模塊。
聲明部分 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(); 語句後面的分號也常常被我遺漏。
大家彼此學習,相互參照!