1. 程式人生 > >五子棋的c語言原始碼

五子棋的c語言原始碼

這是實現五子棋落子和判斷勝負的原始碼,電腦落子涉及的人工智慧演算法(目前AI屬於弱智的隨機落子)暫時沒有實現。本文重點講一下勝負判斷功能的實現,我們都知道五子棋中獲勝的條件就是五聯子,而五聯子的方向有四種:水平、豎直和兩個對角線方向。掃描的思想是在每個落子的位置判斷各個方向能掃描的次數(最多為5)。以水平方向為例,陣列下標為【5】【5】的從【5】【0】開始判斷連往右的五個座標(即陣列元素)的值是否相等,如果是則表明獲勝。

#include <stdio.h>

#include <stdlib.h>

#define NO_CHESS    ""

#define RED_CHESS   "

❤️"

#define BLACK_CHESS "♠️"

#define BOARD_SIZE  15 //定義棋盤的大小

typedef int DataType;

struct Stack

{

DataType arr[BOARD_SIZE][BOARD_SIZE];

    int top;

};

//定義一個二維陣列來充當棋盤

constchar *Chesses[BOARD_SIZE][BOARD_SIZE];

//----函式的宣告-----

//初始化棋盤

void initChess(void);

//輸出棋盤

void prChess(void);

//判斷輸贏

void winJudge(char* corlor,int x,int y);

//提示獲得勝利

void printWin(char* color);

//橫向掃描函式

void horizonScan(char* color,int x,int y);

//縱向掃描函式

void verticalScan(char* color,int x,int y);

//正對角線掃描函式

void diagonalScan(char* color,int x,int y);

//反對角線掃描函式

void opposeDiagonalScan(char* color,int x,int y);

//悔棋函式

void retract();

//-----函式的實現-----

//初始化棋盤

void initChess(void)

{

//把每一個元素賦值為 "用於控制檯畫出棋盤

    for (int i =0; i<BOARD_SIZE; i++)

    {

        for (int k =0; k<BOARD_SIZE; k++)

        {

            Chesses[i][k] = NO_CHESS;

        }

    }

}

//輸出棋盤

void prChess(void)

{

printf("  00 01 02 03 04 05 06 07 08 09 10 11 12 13 14\n");

//列印每個陣列元素的值

    for (int i =0; i<BOARD_SIZE; i++)//

    {

        printf("%02d ",i);

        for (int k =0; k<BOARD_SIZE; k++)//

        {

            printf("%s ",Chesses[i][k]);

        }

        //換行

        printf("\n");

    }

}

//判斷輸贏

void winJudge(char* color,int x,int y)

{

//橫向掃描

    horizonScan(color, x, y);

//縱向掃描

    verticalScan(color, x, y);

//對角線方向掃描

    diagonalScan(color, x, y);

//反對角線方向掃描

    opposeDiagonalScan(color, x, y);

}

//橫向掃描函式

void horizonScan(char* color,int x,int y)

{

//count儲存掃描的次數

    int count;

//儲存變數

    int sign;

    if((8-abs(y-7))>4)

    {

        count=4;

    }else{

        count=7-abs(y-7);

    }

//4-10列掃描五次,014列掃描一次;其中0列從當前位置開始掃描,而14列從10列掃描;其他列類似

    for (int i=count; i>=0; i--)

    {

//4列只能掃描到第0列,不能越界

        if (y>7)

        {

            sign=i-4;

        }else

        {

            sign=0-i;

        }

//掃描是否五聯子

        if ((*Chesses[x][y+sign]==*color)&&(*Chesses[x][y+sign+1]==*color)&&(*Chesses[x][y+sign+2]==*color)&&(*Chesses[x][y+sign+3]==*color)&&(*Chesses[x][y+sign+4]==*color))

                printWin(color);

    }

}

//縱向掃描函式

void verticalScan(char* color,int x,int y)

{

//count儲存掃描的次數

    int count;

//儲存變數

    int sign;

    if((8-abs(x-7))>4)

    {

        count=4;

    }else

    {

        count=7-abs(x-7);

    }

//4-10行掃描五次,014行掃描一次;其中0行從當前位置開始掃描,而14行列從10行掃描;其他行類似

    for (int i=count; i>=0; i--)

    {

//4行只能掃描到第0行,不能越界

        if (x>7)

        {

            sign=i-4;

        }else

        {

            sign=0-i;

        }

//掃描是否五聯子

        if ((*Chesses[x+sign][y]==*color)&&(*Chesses[x+sign+1][y]==*color)&&(*Chesses[x+sign+2][y]==*color)&&(*Chesses[x+sign+3][y]==*color)&&(*Chesses[x+sign+4][y]==*color))

            printWin(color);

    }

}

//對角線掃描函式/Users/tarena0036/Desktop/螢幕快照 2016-05-04下午2.16.17.png

void diagonalScan(char* color,int x,int y)

{

//count用於儲存掃描的次數

    int count;

//儲存變數

    int sign;

//用於儲存臨時資料

    int temp;

    if((8-abs(x-7))>4&&(8-abs(y-7))>4)

    {

        count=4;

    }

    else if(x<11&&y<11)

    {

        temp=x<=y?x:y;

        count=7-abs(temp-7);

    }

    else if (x>3&&y>3)

    {

        temp=x>=y?x:y;

        count=7-abs(temp-7);

    }

    else if (abs(x-y)==10)

    {

        count=0;

    }

    else if (abs(x-y)==9)

    {

        count=1;

    }

    else if (abs(x-y)==8)

    {

        count=2;

    }

    else

    {

//其他情況無需掃描

        count=-1;

    }

//(4-10)*(4-10)區域掃描五次,014/列掃描一次;其中0/列從當前位置開始掃描,而14/列從10/列掃描;其他行類似

    for (int i=count; i>=0; i--)

    {

//4行只能掃描到第0行,不能越界

        if (x+y<14)

        {

            if (x==11||y==11)

            {

                sign=-(i+1);

            }

            else

            sign=-i;

        }else

        {

            if (x==2||y==2)

            {

                sign=i-2;

            }

            else if (x==3||y==3)

            {

                sign=i-3;

            }

            else

            sign=i-4;

        }

//掃描是否五聯子

        if ((*Chesses[x+sign][y+sign]==*color)&&(*Chesses[x+sign+1][y+sign+1]==*color)&&(*Chesses[x+sign+2][y+sign+2]==*color)&&(*Chesses[x+sign+3][y+sign+3]==*color)&&(*Chesses[x+sign+4][y+sign+4]==*color))

            printWin(color);

    }

}

//反對角線掃描

void opposeDiagonalScan(char* color,int x,int y)

{

//count用於儲存掃描的次數

    int count;

//儲存變數

    int sign;

//用於儲存臨時資料

    int temp;

    if((8-abs(x-7))>4&&(8-abs(y-7))>4)

    {

        count=4;

    }

    else if(x<11&&y>3)

    {

        temp=(abs(x-7))>=(abs(y-7))?x:y;

        count=7-abs(temp-7);

    }

    else if (x>3&&y<11)

    {

        temp=(abs(x-7))>=(abs(y-7))?x:y;

        count=7-abs(temp-7);

    }

    else if ((x+y)==4||(x+y)==24)

    {

        count=0;

    }

    else if ((x+y)==5||(x+y)==23)

    {

        count=1;

    }

    else if ((x+y)==6||(x+y)==22)

    {

        count=2;

    }

    else

    {

//其他情況無需掃描

        count=-1;

    }

//(4-10)*(4-10)區域掃描五次,014/列掃描一次;其中0/列從當前位置開始掃描,而14/列從10/列掃描;其他行類似

    for (int i=count; i>=0; i--)

    {

//4行只能掃描到第0行,不能越界

        if (x>y)

        {

            if (x==3||y==11)

            {

                sign=i+1;

            }

            else

                sign=i;

        }else

        {

            if (x==12||y==2)

            {

                sign=i+2;

            }

            else if (x==11||y==3)

            {

                sign=i+3;

            }

            else

                sign=i+4;

        }

//掃描是否五聯子

        if ((*Chesses[x+sign][y-sign]==*color)&&(*Chesses[x+sign-1][y-sign+1]==*color)&&(*Chesses[x+sign-2][y-sign+2]==*color)&&(*Chesses[x+sign-3][y-sign+3]==*color)&&(*Chesses[x+sign-4][y-sign+4]==*color))

            printWin(color);

    }

}

//悔棋功能

void retract()

{

}

//輸出獲勝資訊

void printWin(char* color)

{

    printf("%s Win!\n",color);

//結束程式

    exit(1);

}

//主函式

int main(int argc,const char * argv[])

{

//初始化二維陣列,儲存棋盤座標點的是否已經有棋子資訊

int info1[BOARD_SIZE][BOARD_SIZE]={0};

//定義棧,用於儲存座標,悔棋時取出棧頂元素將對應位置的點復位

//呼叫函式

initChess();

    prChess();

//開始迴圈下棋

    while (1)

    {

        int xPos;

        int yPos;

    menu:

printf("請輸入您下棋的座標,x y(輸入15 15為悔棋) \n");

        scanf("%d %d",&xPos,&yPos);

        if (xPos>BOARD_SIZE||yPos>BOARD_SIZE)

        {

printf("請在邊界內輸入有效數字!\n");

            goto menu;

        }

        else if(xPos==BOARD_SIZE&&yPos==BOARD_SIZE)

        {

            retract();

        }

        if (1==info1[xPos][yPos])

        {

printf("您輸入的位置已經有棋子,請重新輸入:\n");

            goto menu;

        }

//將已經落子的點標記為1

        info1[xPos][yPos]=1;

//把對應的陣列元素賦值成紅棋

        Chesses[xPos][yPos] = RED_CHESS;

        //重新整理棋盤

        prChess();

        //判斷是否獲勝

        winJudge(Chesses[xPos][yPos],xPos,yPos);

        int macXPos,macYPos;

    macPosition:

//隨機生成2 0~15之間的數作為電腦下棋的座標

        macXPos = arc4random()%BOARD_SIZE;

        macYPos = arc4random()%BOARD_SIZE;

//判斷生成的座標的對應的點是否已經有棋子了

        if (1==info1[macXPos][macYPos])

        {

            goto macPosition;

        }

//將電腦下棋的座標賦值 黑旗

        Chesses[macXPos][macYPos] = BLACK_CHESS;

//將已經落子的點標記為1

        info1[macXPos][macYPos]=1;

        //重新整理棋盤

        prChess();

//判斷黑棋是否獲勝

        winJudge(Chesses[macXPos][macYPos],macXPos,macYPos);

    }

    /*

上面的程式碼還涉及到如下需要改進的地方

     1、使用者輸入座標的有效性,只能是數字,不能超出棋盤的範圍(暫時沒有對整個棋盤是否落滿子進行判斷)

     2、如果是已經下棋的點,不能重複下棋(實現)

     3、每次下棋後,需要掃描誰贏了

     4、悔棋功能

     */

    return 0;

}