C語(yǔ)言實(shí)現(xiàn)井字棋(三子棋)
本文實(shí)例為大家分享了C語(yǔ)言實(shí)現(xiàn)井字棋的具體代碼,供大家參考,具體內(nèi)容如下
一、實(shí)現(xiàn)思路
1、初始化數(shù)組
三子棋是九宮格的格式,所以用二維數(shù)組接收數(shù)據(jù)。用‘O'代表電腦下的子,‘X'代表玩家下的子。未下子的時(shí)候初始化 ' ‘(space)。則二維數(shù)組為“char”類型,大小為char board[3][3]。
2、打印棋盤
打印出井字的棋盤,同時(shí)為了將數(shù)據(jù)顯示在每格的中間,用空格隔開(kāi)(“ %c |”)的格式設(shè)置棋盤“|”用來(lái)形成豎,接著打印“- - -|”用來(lái)形成行。將兩部用for循環(huán)按照邏輯鏈接起來(lái),即可打印出“井”。同時(shí)“%c”處初始化為‘ '(space)
3、玩家下子
<1> 玩家下的子用數(shù)組的坐標(biāo)表示,輸入提示:(請(qǐng)輸入坐標(biāo):),輸入格式為(1 1),范圍為1~3。
<2> 玩家下子的時(shí)候,如果遇到已經(jīng)下過(guò)子的坐標(biāo),返回并提示錯(cuò)誤,重新輸入。
<3> 如果輸入的坐標(biāo)超過(guò)范圍,提示錯(cuò)誤,重新輸入。
<4> 打印棋盤,將玩家下子的坐標(biāo)處用'X'替換。
4、電腦下子
<1> 電腦下子,利用范圍為1~3,隨機(jī)產(chǎn)生條件下的坐標(biāo),如果遇到已經(jīng)下過(guò)子的坐標(biāo),就重新產(chǎn)生條件下的坐標(biāo),這里利用循環(huán)進(jìn)行調(diào)試。
<2> 有一個(gè)電腦下子優(yōu)先規(guī)則:
a、電腦下子的第一個(gè)是隨機(jī)產(chǎn)生,在電腦先手的時(shí)候,第二個(gè)也是隨機(jī)產(chǎn)生。
b、判斷是否有兩個(gè) ‘O”O(jiān)' 在行、列或者斜對(duì)角,如果有,就將第三個(gè)子下在可以連成一直線的空白處(即三點(diǎn)成線,贏得比賽)。如果有連成線但是沒(méi)用空白處,進(jìn)行 c 步驟。
c、判斷是不是有兩個(gè) ‘X”X' 在行、列或者斜對(duì)角練成線,并且第三個(gè)空為空白。如果有就將子下在該空白處(即對(duì)玩家進(jìn)行堵截)。如果沒(méi)用,進(jìn)行 d 步驟。
d、在范圍內(nèi)隨機(jī)下子?! ?br />
<3> 打印棋盤,將電腦下子的坐標(biāo)處用'O'代替。
5、輸贏判斷
當(dāng)判斷出有行、列或者斜對(duì)角出現(xiàn) ‘X' ‘O' 三點(diǎn)成線,輸出判斷(恭喜你,你贏了)(很遺憾,你輸了)并退出游戲,如果遍歷數(shù)組發(fā)現(xiàn)不符合上述要求,而且沒(méi)有數(shù)據(jù) ' ‘(space)(即棋盤下滿),輸出(和棋)并退出游戲。
6、邏輯關(guān)系
開(kāi)始游戲——選擇電腦先手——(ComputerGo——PrintfGame——IsWin——PlayGo——PrintfGame——IsWin)(循環(huán)實(shí)現(xiàn))
開(kāi)始游戲——選擇玩家先手——PrintfGame——(PlayGo——PrintfGame——IsWin——ComputerGo——PrintfGame——IsWin)(循環(huán)實(shí)現(xiàn))
二、源代碼
1、game.h(頭文件)
#ifndef __game_h__ #define __game_h__ #define ROW 3 //標(biāo)識(shí)符定義行ROW = 3 #define COL 3//標(biāo)識(shí)符定義列COL = 3 void InitGame(char arr[ROW][COL], int row, int col);//初始化 void PrintfGame(char arr[ROW][COL], int row, int col);//打印 void Menu();//菜單 void ComputerGo(char arr[ROW][COL], int row, int col);//電腦走 void PlayGo(char arr[ROW][COL], int row, int col);//玩家走 char IsWin(char arr[ROW][COL], int row, int col);//輸、贏、和局 #endif //__game_h__
2、game.c(函數(shù)定義)
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h" //引用自定義頭文件
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
void Menu()
{
printf("**********************************\n");
printf("********* 1.paly *********\n");
printf("********* 0.exit *********\n");
printf("**********************************\n");
}
void InitGame(char arr[ROW][COL],int row, int col)//初始化數(shù)組
{
int i = 0;
int j = 0;
for (i = 0; i < ROW; i++)
{
for (j = 0; j < COL; j++)
{
arr[i][j] = ' '; // 利用循環(huán)將數(shù)組元素初始化為' '(space)
}
}
}
void PrintfGame(char arr[ROW][COL], int row, int col)//打印棋盤
{
//利用循環(huán)打印棋盤
int i = 0;
int j = 0;
for (i = 0; i < ROW; i++)//限定范圍,不超過(guò)ROW
{
if (i < ROW - 1) //打印前兩行
{
for (j = 0; j < COL; j++)
{
if (j < COL - 1) //打印前兩列
{
printf(" %c |", arr[i][j]);
}
else
{
printf(" %c ",arr[i][j]); //打印第三列
}
}
printf("\n"); //輸出形式為" %c | %c | %c "
for (j = 0; j < COL; j++)
{
if (j < COL - 1)
{
printf("---|"); //打印前兩列
}
else
{
printf("---"); //打印第三列
}
}
printf("\n"); //輸出形式為"---|---|---"
}
else //打印第三行
{
for (j = 0; j < COL; j++)
{
if (j < COL - 1)
{
printf(" %c |",arr[i][j]);
}
else
{
printf(" %c ",arr[i][j]);
}
}
printf("\n"); //輸出形式為 " %c | %c | %c "
}
}
}
void PlayGo(char arr[ROW][COL], int row, int col)//玩家走
{
int i = 0;
int j = 0;
int set = 0;
do
{
printf("\n");
printf("請(qǐng)輸入坐標(biāo):>");
scanf("%d %d", &i, &j);
printf("\n");
//對(duì)輸入的i,j減1,用戶輸入的時(shí)候就可以直接以(1 1)為第一個(gè)輸入點(diǎn)
i--;
j--;
if ((i<0) || (i>=row) || (j<0) || (j>=col) || (arr[i][j] != ' '))
{//輸入超出了范圍或者輸入坐標(biāo)處已經(jīng)有棋子
printf("輸入有誤!\n");
set = 1;
}
else
{
arr[i][j] = 'X';//玩家下子
set = 0;
}
} while (set);//沒(méi)有下子成功就循環(huán)到輸入成功
}
char IsWin(char arr[ROW][COL], int row, int col)//判斷輸贏
{
int i = 0;
int j = 0;
int count = 0;
for (i = 0; i < ROW; i++)
{
if ((arr[i][0] == arr[i][1]) && (arr[i][1] == arr[i][2]) && (arr[i][0] != ' '))
{
return 'X';//產(chǎn)生有行成線,返回'X'
}
}
for (i = 0; i < ROW; i++)
{
if ((arr[0][i] == arr[1][i]) && (arr[1][i] == arr[2][i]) && (arr[0][i] != ' '))
{
return ' ';//產(chǎn)生列成線,返回' '
}
}
if ((arr[0][0] == arr[1][1]) && (arr[1][1] == arr[2][2]) && (arr[1][1] != ' ') ||
(arr[2][0] == arr[1][1]) && (arr[1][1] == arr[0][2])&&(arr[1][1]!=' '))
{
return 'O';//產(chǎn)生斜對(duì)角成線,返回'O'
}
if ((arr[0][0] != ' ') && (arr[0][1] != ' ') && (arr[0][2] != ' ') &&
(arr[1][0] != ' ') && (arr[1][1] != ' ') && (arr[1][2] != ' ') &&
(arr[2][0] != ' ') && (arr[2][1] != ' ') && (arr[2][2] != ' '))
{
return 'H';//棋盤已經(jīng)下滿卻還沒(méi)有勝負(fù)產(chǎn)生,返回'H'
}
return 0;
}
void ComputerGo(char arr[ROW][COL], int row, int col)//電腦走
{
int i = 0;
int j = 0;
int flag0 = 0;//flage0 用于限制一旦有一種判斷成功,就不再進(jìn)行其他判斷
int flag2 = 0;//flage2 用于對(duì)電腦即將贏的時(shí)候,不同判斷產(chǎn)生后,進(jìn)入不同的case
int flag3 = 0;//flage3 用于對(duì)玩家即將贏的時(shí)候,不同判斷產(chǎn)生后,進(jìn)入不同的case
//電腦還差一子就贏得比賽的情況
if (flag0 == 0)
{
for (i = 0; i < ROW; i++)//每行有兩個(gè)‘O'‘O'連在一起,就在第三個(gè)空格處下子
{
if ((arr[i][0] == arr[i][1] && arr[i][0] == 'O'&&arr[i][2] != 'X')
|| (arr[i][1] == arr[i][2] && arr[i][1] == 'O'&&arr[i][0] != 'X')
|| (arr[i][0] == arr[i][2] && arr[i][0] == 'O'&&arr[i][1] != 'X'))
{
flag0 = 1;
flag2 = 1;
break;
}
}
}
if (flag0 == 0)
{
for (j = 0; j < ROW; j++)//每列有兩個(gè)‘O'‘O'連在一起,就在第三個(gè)空格處下子
{
if ((arr[0][j] == arr[1][j] && arr[0][j] == 'O'&&arr[2][j] != 'X')
|| (arr[1][j] == arr[2][j] && arr[1][j] == 'O'&&arr[0][j] != 'X')
|| (arr[0][j] == arr[2][j] && arr[0][j] == 'O'&&arr[1][j] != 'X'))
{
flag2 = 2;
flag0 = 1;
break;
}
}
}
if ((arr[0][0] == arr[1][1] && arr[0][0] == 'O'&&arr[2][2] != 'X')//第一條斜對(duì)角
|| (arr[1][1] == arr[2][2] && arr[1][1] == 'O'&&arr[0][0] != 'X')
|| (arr[0][0] == arr[2][2] && arr[0][0] == 'O'&&arr[1][1] != 'X')
&&(flag0 == 0))
{
flag2 = 3;
flag0 = 1;
}
if ((arr[0][2] == arr[1][1] && arr[0][2] == 'O'&&arr[2][0] != 'X')//第二條斜對(duì)角
|| (arr[1][1] == arr[2][0] && arr[1][1] == 'O'&&arr[0][2] != 'X')
|| (arr[0][2] == arr[2][0] && arr[0][2] == 'O'&&arr[1][1] != 'X')
&& (flag0 == 0))
{
flag2 = 4;
flag0 = 1;
}
switch (flag2)
{
case 1:
do
{
j = rand() % 3;//固定行不變,改變列,讓棋子進(jìn)入空白處
if (arr[i][j] == ' ')
{
arr[i][j] = 'O';
break;
}
} while (1);
break;
case 2:
do
{//rand()%3 產(chǎn)生0 1 2 之間的隨機(jī)數(shù)
i = rand() % 3;//固定列不變,改變行,讓棋子進(jìn)入空白處
if (arr[i][j] == ' ')
{
arr[i][j] = 'O';
break;
}
} while (1);
break;
case 3:
do
{//改變行列,但是限制(行數(shù)=列數(shù)),使其在第一條斜對(duì)角空白處下子
i = rand() % 3;
j = rand() % 3;
if ((i == j) && (arr[i][j] == ' '))
{
arr[i][j] = 'O';
break;
}
} while (1);
break;
case 4:
do
{//改變行列,但是限制行數(shù)和列數(shù),使其在第二條斜對(duì)角空白處下子
i = rand() % 3;
j = rand() % 3;
if ((i == j) && (arr[i][j] == ' ') && (i == 1) ||
(i == j + 2) && (arr[i][j] == ' ') ||
(j == i + 2) && (arr[i][j] == ' '))
{
arr[i][j] = 'O';
break;
}
} while (1);
break;
}
//玩家還差一子就贏得比賽的時(shí)候,電腦進(jìn)行堵截
if (flag0 == 0)
{
for (i = 0; i < ROW; i++)//每行有兩個(gè)‘X'‘X'連在一起,就在第三個(gè)空格處下子
{
if ((arr[i][0] == arr[i][1] && arr[i][0] == 'X'&&arr[i][2] != 'O')
|| (arr[i][1] == arr[i][2] && arr[i][1] == 'X'&&arr[i][0] != 'O')
|| (arr[i][0] == arr[i][2] && arr[i][0] == 'X'&&arr[i][1] != 'O'))
{
flag3 = 1;
flag0 = 1;
break;
}
}
}
if (flag0 == 0)
{
for (j = 0; j < ROW; j++)//每列有兩個(gè)‘X'‘X'連在一起,就在第三個(gè)空格處下子
{
if ((arr[0][j] == arr[1][j] && arr[0][j] == 'X'&&arr[2][j] != 'O')
|| (arr[1][j] == arr[2][j] && arr[1][j] == 'X'&&arr[0][j] != 'O')
|| (arr[0][j] == arr[2][j] && arr[0][j] == 'X'&&arr[1][j] != 'O'))
{
flag3 = 2;
flag0 = 1;
break;
}
}
}
if ((arr[0][0] == arr[1][1] && arr[0][0] == 'X'&&arr[2][2] != 'O')//斜對(duì)角
|| (arr[1][1] == arr[2][2] && arr[1][1] == 'X'&&arr[0][0] != 'O')
|| (arr[0][0] == arr[2][2] && arr[0][0] == 'X'&&arr[1][1] != 'O')
&& (flag0 == 0))
{
flag3 = 3;
flag0 = 1;
}
if ((arr[0][2] == arr[1][1] && arr[0][2] == 'X'&&arr[2][0] != 'O')//斜對(duì)角
|| (arr[1][1] == arr[2][0] && arr[1][1] == 'X'&&arr[0][2] != 'O')
|| (arr[0][2] == arr[2][0] && arr[0][2] == 'X'&&arr[1][1] != 'O')
&& (flag0 == 0))
{
flag3 = 4;
flag0 = 1;
}
switch (flag3)
{
case 1:
do
{
j = rand() % 3;
if (arr[i][j] == ' ')
{
arr[i][j] = 'O';
break;
}
} while (1);
break;
case 2:
do
{
i = rand() % 3;
if (arr[i][j] == ' ')
{
arr[i][j] = 'O';
break;
}
} while (1);
break;
case 3:
do
{
i = rand() % 3;
j = rand() % 3;
if ((i == j) && (arr[i][j] == ' '))
{
arr[i][j] = 'O';
break;
}
} while (1);
break;
case 4:
do
{
i = rand() % 3;
j = rand() % 3;
if ((i == j) && (arr[i][j] == ' ') && (i == 1) ||
(i == j + 2) && (arr[i][j] == ' ') ||
(j == i + 2) && (arr[i][j] == ' '))
{
arr[i][j] = 'O';
break;
}
} while (1);
break;
}
//無(wú)論是玩家還是電腦,沒(méi)有即將三子成線的情況,電腦隨機(jī)產(chǎn)生一個(gè)棋子
if (flag0 == 0)
{
do
{
i = rand() % 3;
j = rand() % 3;
if (arr[i][j] == ' ')
{
arr[i][j] = 'O';
break;
}
} while (1);
}
}
3、text.c(邏輯及調(diào)用)
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void game1(char arr[ROW][COL], int row, int col)//電腦先手
{
char i = 0;
while (1)//只有玩家贏或者電腦贏或者棋盤滿了才退出循環(huán)
{
printf("\n");
ComputerGo(arr, row, col);//電腦走
PrintfGame(arr, row, col);//打印棋盤
i = IsWin(arr, row, col);//判斷是否有輸贏
if ((i == 'X') || (i == 'O') || (i == ' '))
{//電腦下子之后,滿足有三子成線,一定是電腦贏
printf("電腦贏!\n");
printf("\n");
break;
}
else if (i == 'H')//棋盤已滿
{
printf("和局!\n");
printf("\n");
break;
}
PlayGo(arr, row, col);//玩家走
PrintfGame(arr, row, col);//打印棋盤
i = IsWin(arr, row, col);//判斷輸贏
if ((i == 'X') || (i == 'O') || (i == ' '))
{//玩家下子之后,滿足有三子成線,一定是玩家贏
printf("玩家贏!\n");
printf("\n");
break;
}
else if (i == 'H')//棋盤已滿
{
printf("和局!\n");
printf("\n");
break;
}
}
}
void game2(char arr[ROW][COL], int row, int col)//玩家先手
{
char i = 0;
int tmp = 0;
while (1)
{
if (tmp == 0)//玩家下棋之前打印一個(gè)空白棋盤,只執(zhí)行一次
{
printf("\n");
PrintfGame(arr, row, col);
tmp = 1;
}
PlayGo(arr, row, col);
PrintfGame(arr, row, col);
printf("\n");
i = IsWin(arr, row, col);
if ((i == 'X') || (i == 'O') || (i == ' '))
{
printf("玩家贏!\n");
printf("\n");
break;
}
else if (i == 'H')
{
printf("和局!\n");
printf("\n");
break;
}
ComputerGo(arr, row, col);
PrintfGame(arr, row, col);
i = IsWin(arr, row, col);
if ((i == 'X') || (i == 'O') || (i == ' '))
{
printf("電腦贏!\n");
printf("\n");
break;
}
else if (i == 'H')
{
printf("和局!\n");
printf("\n");
break;
}
}
}
//main函數(shù)
int main()
{
int i = 0;
int j = 0;
int input = 0;
int tmp = 0;
int row = 3;
int col = 3;
char arr[3][3];
srand((unsigned int)time(NULL));//隨機(jī)數(shù)發(fā)生器,用于產(chǎn)生隨機(jī)數(shù)的時(shí)候,每次都不一樣
do
{
Menu();//打印
printf("請(qǐng)選擇:>\n");
scanf("%d", &input);
printf("\n");
switch (input)
{
case 1:
InitGame(arr, row, col);//初始化函數(shù)
do
{
printf("請(qǐng)選擇:>\n1.電腦先手 2.玩家先手\n");
scanf("%d", &tmp);
switch (tmp)
{
case 1:
game1(arr, row, col);//電腦先手
tmp = 0;
break;
case 2:
game2(arr, row, col);//玩家先手
tmp = 0;
break;
default:
printf("輸入有誤! 請(qǐng)重新輸入:>\n\n");
break;
}
} while (tmp);
break;
case 0:
printf("游戲退出!\n");
break;
default:
printf("輸入有誤!\n");
break;
}
} while (input);
system("pause");
return 0;
}
三、程序截圖



以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C++ BloomFilter布隆過(guò)濾器應(yīng)用及概念詳解
布隆過(guò)濾器是由布?。˙urton Howard Bloom)在1970年提出的 一種緊湊型的、比較巧妙的概率型數(shù)據(jù)結(jié)構(gòu),特點(diǎn)是高效地插入和查詢,可以用來(lái)告訴你 “某樣?xùn)|西一定不存在或者可能存在”,它是用多個(gè)哈希函數(shù),將一個(gè)數(shù)據(jù)映射到位圖結(jié)構(gòu)中2023-03-03
VC中LINK 2001 和 LINK 2009 的錯(cuò)誤的解決方法
最近將兩個(gè)開(kāi)源C++項(xiàng)目編譯成windows版本的時(shí)候遇到很多問(wèn)題,編譯的時(shí)候總是報(bào)錯(cuò),報(bào)的最多的是無(wú)法解析的外部符號(hào)”,經(jīng)過(guò)近3天的折騰總算都通過(guò)了,這里是一些總結(jié)2020-10-10
在C++中關(guān)于友元函數(shù)的進(jìn)一步理解
今天小編就為大家分享一篇關(guān)于在C++中關(guān)于友元函數(shù)的進(jìn)一步理解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12
C++中關(guān)于=default和=delete問(wèn)題
這篇文章主要介紹了C++中關(guān)于=default和=delete問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
C++詳解使用floor&ceil&round實(shí)現(xiàn)保留小數(shù)點(diǎn)后兩位
這篇文章主要介紹了C++使用floor&ceil&round實(shí)現(xiàn)保留小數(shù)點(diǎn)后兩位的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
C++中構(gòu)造函數(shù)與析構(gòu)函數(shù)的調(diào)用順序詳解
C++ 語(yǔ)言一直被批評(píng)太復(fù)雜了,很多細(xì)節(jié)的地方需要仔細(xì)推敲,甚至其構(gòu)造函數(shù)和析構(gòu)的調(diào)用順序也成為了一個(gè)讓人迷惑的問(wèn)題,在此我做了簡(jiǎn)單的總結(jié)。這篇文章主要介紹了C++中構(gòu)造函數(shù)與析構(gòu)函數(shù)的調(diào)用順序,需要的朋友可以參考借鑒。2017-01-01
Java?C++題解leetcode1598文件夾操作日志搜集器
這篇文章主要為大家介紹了Java?C++題解leetcode1598文件夾操作日志搜集器示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09

