三子棋
- 一、何為三子棋
- 二、解題思路
-
- 1.首先确定編寫形式
- 2.設計遊戲菜單頁面
- 3.列印棋盤
- 4.遊戲環節
- 5.判斷輸赢(遊戲狀态)
- 6.判斷平局
- 7.運作結果
一、何為三子棋
三子棋又稱為井字棋,相信大家都玩過這個小遊戲,其規則就是哪一方先将相鄰的的三枚棋子連在一起便獲得勝利,那麼今天就由我為大家講解如何使用C語言實作簡單的三子棋遊戲吧。
二、解題思路
1.首先确定編寫形式
多檔案形式實作無疑是最清晰、最直覺的編寫形式。
主函數(調用):test.c 測試三子棋遊戲(實作遊戲的大體邏輯和功能)
子產品(被調用):game.c 遊戲函數及其功能的實作
頭檔案(聲明):game.h 三子棋遊戲的函數聲明
我先将頭檔案展示出來,為大家下來的解題提供明确的思路:
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 3
#define COL 3
//初始化棋盤
void init_board(char board[ROW][COL], int row, int col);
//列印棋盤
void display_board(char board[ROW][COL], int row, int col);
//玩家下棋
void player_move(char board[ROW][COL], int row, int col);
//電腦下棋
void computer_move(char board[ROW][COL], int row, int col);
//判斷遊戲狀态
char is_win(char board[ROW][COL], int row, int col);
- 由圖可見,一共有三個庫函數所需要的頭檔案以及五個為實作遊戲功能而建立的函數;
- 我認為列印棋盤尤為重要,無論是在何種情況下,我們都需要在成功實作某些功能時列印棋盤檢驗功能的完整性。
2.設計遊戲菜單頁面
遊戲菜單必須出現在我們最終生成的結果當中,也就是需要“printf”将其列印出來,而main函數作為一個程式的入口,那麼下面這段代碼便是在test.c中實作的。
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
printf("***********************\n");
printf("------ 1. play ------\n");
printf("------ 0. exit ------\n");
printf("***********************\n");
}
int main()
{
int input = 0;
//設定時間戳建立随機數
srand((unsigned int)time(NULL));
do
{
//菜單函數調用
menu();
printf("請選擇:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出遊戲\n");
break;
default:
printf("選擇錯誤,重新選擇!\n");
break;
}
} while (input);
return 0;
}
- 使用do…while循環實作遊戲的重複可玩性;
- switch語句實作遊戲的菜單操作,為玩家提供選項;
- 這裡預處理操作中已經引入自定義函數(頭檔案内已經包含所需要的一切庫以及函數聲明);
3.列印棋盤
根據棋盤的樣式,我們可以聯想到三子棋棋盤應該有九個待輸入資料(可存儲),且形式為3*3,是以在這裡二維數組便是解題關鍵。 實作列印棋盤功能代碼可以放在game.c檔案中。
//初始化棋盤功能
void init_board(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 display_board(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
//資料
printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
//---|---|---
if(i<row-1)
printf("---|---|---\n");
}
}
//動态列印棋盤功能
void display_board(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
//資料
//printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
int j = 0;
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");
}
printf("\n");
//---|---|---
if (i < row - 1)
{
//printf("---|---|---\n");
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}
- 初始化棋盤應為空格,友善玩家資料的輸入。(注意:'\n’不會列印在結果裡,故而此處列印空格);
- 美化棋盤:待輸入資料兩端各一個空格;
- 此時棋盤可以分為n組列印(每組列印一行資料和一行分割線),n為二維數組的列。(注意:此處不使用行數為列印條件是因為在二維數組中,列數可以确定行數,而行數不能确定列數);
- 簡陋棋盤無法完成棋盤的形态轉換,是以此處不建議使用
4.遊戲環節
玩家下棋:輸入坐标(需要考慮坐标合法性,坐标是否被占用)
//玩家下棋功能
void player_move(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家下棋:>\n");
while (1)
{
printf("請輸入要下棋的坐标:>");
scanf("%d %d", &x, &y);
//1.坐标的合法性
//2.坐标是否被占用
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("該坐标被占用,請重新輸入\n");
}
}
else
{
printf("坐标非法,重新輸入\n");
}
}
}
- 作為玩家下棋環節應該做到正常坐标輸入,即第一行第一列坐标輸入應為(1,1),是以我們在判斷坐标時應該對其減一達到我們所要的效果。
簡單電腦下棋:随機下棋(利用時間戳)
//電腦随機下棋
void computer_move(char board[ROW][COL], int row, int col)
{
printf("電腦下棋:>\n");
//%3利用取模運算控制取值範圍
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
- 這裡電腦下棋我利用的是時間戳作為随機數,并且利用取模運算控制其數值範圍;
- 設定随機數需要用到srand(unsigned seed)以及time(NULL),是以我們還需要<stdlib.h>和<time.h>兩個頭檔案,為了友善管理,我已經将所需頭檔案以及其他預處理操作放入game.h檔案中。
5.判斷輸赢(遊戲狀态)
遊戲過程的功能實作
void game()
{
char ret = 0;
//資料的存儲需要的二維數組
char board[ROW][COL] = { 0 };
//這裡可以進行數組的初始化,防止'\n'等因素無法列印造成棋盤的錯誤
init_board(board, ROW, COL);
//列印棋盤
display_board(board, ROW, COL);
//玩遊戲
while (1)//死循環,直到結果跳出
{
player_move(board, ROW, COL);
display_board(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'R')
break;
computer_move(board, ROW, COL);
display_board(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'R')
break;
}
//定義特殊字元
if (ret == '*')
{
printf("恭喜你獲勝!\n");
}
else if (ret == '#')
{
printf("弱爆了,敗給了人機!\n");
}
else if (ret == 'P')
{
printf("打成平手,繼續訓練吧!\n");
}
display_board(board, ROW, COL);
}
//玩家赢 - '*'
//電腦赢 - '#'
//平局了 - 'P'
//遊戲繼續 - 'R'
- 該代碼是屬于test.c檔案中的函數實作,目的是為了将整個遊戲的過程以及遊戲最終結果列印出來,實作遊戲的實時互動及可見性。
判斷獲勝方的函數代碼實作
//簡陋判斷遊戲結果
char is_win(char board[ROW][COL], int row, int col)
{
int i = 0;
//橫行判斷
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
{
return board[i][0];
}
}
//縱行判斷
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
//對角線判斷
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
{
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
- 邏輯判斷的方式是分為三種狀态,第一種為橫行三個相連,第二種為縱行三個相連,第三種為兩條對角線的判斷;
- 這是一段針對三子棋判斷輸赢的簡陋方法,此處無法實作動态的判斷。等部落客空閑好好研究之後便會修改上傳。
6.判斷平局
平局的關鍵在于棋盤的空間狀态,即判斷棋盤是否滿了。
//如果棋盤滿了,傳回1
//不滿,傳回0
static int is_full(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
if (' ' == board[i][j])
{
return 0;
}
}
}
return 1;
}
//判斷平局 由判滿功能的傳回值操作
if (is_full(board, row, col) == 1)
{
return 'P';
}
//繼續
return 'R';
}
- 首先我們可以建立is_full函數對棋盤這個二維數組的是否含有空格判斷得出,棋盤此時的狀态;
- 然後我們就可以使用is_full函數的傳回值進行遊戲結果平局的判斷。
7.運作結果

總結:這是一個簡單的三子棋遊戲,還有部分功能可以實作,以及你自己的想法也可以添加進去;
關鍵在于基礎的函數應用和對二維數組的熟練使用。