C語言實現的簡易五子棋

#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
#define MAXIMUS 15 ///定義棋盤大小
int p[MAXIMUS][MAXIMUS];///存儲對局信息
char buff[MAXIMUS*2+1][MAXIMUS*4+3];///輸出緩衝器
int Cx,Cy;///當前光標位置
int Now;///當前走子的玩家,1代表黑,2代表白
int wl,wp;///當前寫入緩衝器的列數和行數位置
char* showText;///在棋盤中央顯示的文字信息
int count;//回合數
char* Copy(char* strDest,const char* strSrc)///修改過的字符串複製函數,會忽略末端的\0
{
    char* strDestCopy = strDest;
    while (*strSrc!='\0')
    {
        *strDest++=*strSrc++;
    }
    return strDestCopy;
}
void Initialize()///初始化一個對局函數
{
    int i,j;///循環變量
    showText="";///重置顯示信息
    count=0;///回合數歸零
    for(i=0; i<MAXIMUS; i++) ///重置對局數據
    {
        for(j=0; j<MAXIMUS; j++)
        {
            p[i][j]=0;
        }
    }
    Cx=Cy=MAXIMUS/2;///重置光標到中央
    Now=1;///重置當前爲黑方
}
char* getStyle(int i,int j)///獲得棋盤中指定座標交點位置的字符,通過製表符拼成棋盤
{
    if(p[i][j]==1)///1爲黑子
        return "●";
    else if(p[i][j]==2)///2爲白子
        return "○";
    else if(i==0&&j==0)///以下爲邊緣棋盤樣式
        return "┏";
    else if(i==MAXIMUS-1&&j==0)
        return "┓";
    else if(i==MAXIMUS-1&&j==MAXIMUS-1)
        return "┛";
    else if(i==0&&j==MAXIMUS-1)
        return "┗";
    else if(i==0)
        return "┠";
    else if(i==MAXIMUS-1)
        return "┨";
    else if(j==0)
        return "┯";
    else if(j==MAXIMUS-1)
        return "┷";
    return "┼";///中間的空位
}
char* getCurse(int i,int j) ///獲得指定座標交點位置左上格的樣式,通過製表符來模擬光標的顯示
{
    if(i==Cx)
    {
        if(j==Cy)
            return "┏";
        else if (j==Cy+1)
            return "┗";
    }
    else if(i==Cx+1)
    {
        if(j==Cy)
            return "┓";
        else if (j==Cy+1)
            return "┛";
    }
    return " ";///如果不在光標附近則爲空
}
void write(char* c)///向緩衝器寫入字符串
{
    Copy(buff[wl]+wp,c);
    wp+=strlen(c);
}
void ln()///緩衝器寫入位置提行
{
    wl+=1;
    wp=0;
}
void Display()///將緩衝器內容輸出到屏幕
{
    int i,l=strlen(showText);///循環變量,中間文字信息的長度
    int Offset=MAXIMUS*2+2-l/2;///算出中間文字信息居中顯示所在的橫座標位置
    if(Offset%2==1)///如果位置爲奇數,則移動到偶數,避免混亂
    {
        Offset--;
    }
    Copy(buff[MAXIMUS]+Offset,showText);///講中間文字信息複製到緩衝器
    if(l%2==1)///如果中間文字長度爲半角奇數,則補上空格,避免混亂
    {
        *(buff[MAXIMUS]+Offset+l)=0x20;
    }
    system("cls");///清理屏幕,準備寫入
    for(i=0; i<MAXIMUS*2+1; i++) ///循環寫入每一行
    {
        printf("%s",buff[i]);
        if(i<MAXIMUS*2)///寫入完每一行需要換行
            printf("\n");
    }
}
void Print()///將整個棋盤算出並儲存到緩衝器,然後調用Display函數顯示出來
{
    int i,j;///循環變量
    wl=0;
    wp=0;
    for(j=0; j<=MAXIMUS; j++) ///寫入出交點左上角的字符,因爲需要打印棋盤右下角,所以很以橫縱各多一次循環
    {
        for(i=0; i<=MAXIMUS; i++)
        {
            write(getCurse(i,j));///寫入左上角字符
            if(j==0||j==MAXIMUS)///如果是棋上下盤邊緣則沒有連接的豎線,用空格填充位置
            {
                if(i!=MAXIMUS)
                    write(" ");
            }
            else///如果在棋盤中間則用豎線承接上下
            {
                if(i==0||i==MAXIMUS-1)///左右邊緣的豎線更粗
                    write("┃");
                else if(i!=MAXIMUS)///中間的豎線
                    write("│");
            }
        }
        if(j==MAXIMUS)///如果是最後一次循環,則只需要處理邊側字符,交點要少一排
        {
            break;
        }
        ln();///提行開始打印交點內容
        write(" ");///用空位補齊位置
        for(i=0; i<MAXIMUS; i++) ///按橫座標循環正常的次數
        {
            write(getStyle(i,j));///寫入交點字符
            if(i!=MAXIMUS-1)///如果不在最右側則補充一個橫線承接左右
            {
                if(j==0||j==MAXIMUS-1)
                {
                    write("━");///上下邊緣的橫線更粗
                }
                else
                {
                    write("—");///中間的橫線
                }
            }
        }
        ln();///寫完一行後提行
    }
    Display();///將緩衝器內容輸出到屏幕
}
int Put() ///在當前光標位置走子,如果非空,則返回0表示失敗
{
    if(p[Cx][Cy]==0)
    {
        p[Cx][Cy]=Now;///改變該位置數據
        return 1;///返回1表示成功
    }
    else
    {
        return 0;
    }
}
int Check()///勝負檢查,即判斷當前走子位置有沒有造成五連珠的情況
{
    int w=1,x=1,y=1,z=1,i;//計橫豎正斜反邪四個方向的連續相同棋子數目
    for(i=1; i<5; i++)if(Cy+i<MAXIMUS&&p[Cx][Cy+i]==Now)w++;
        else break;///向下檢查
    for(i=1; i<5; i++)if(Cy-i>0&&p[Cx][Cy-i]==Now)w++;
        else break;///向上檢查
    if(w>=5)return Now;///若果達到5個則判斷當前走子玩家爲贏家
    for(i=1; i<5; i++)if(Cx+i<MAXIMUS&&p[Cx+i][Cy]==Now)x++;
        else break;///向右檢查
    for(i=1; i<5; i++)if(Cx-i>0&&p[Cx-i][Cy]==Now)x++;
        else break;///向左檢查
    if(x>=5)return Now;///若果達到5個則判斷當前走子玩家爲贏家
    for(i=1; i<5; i++)if(Cx+i<MAXIMUS&&Cy+i<MAXIMUS&&p[Cx+i][Cy+i]==Now)y++;
        else break;///向右下檢查
    for(i=1; i<5; i++)if(Cx-i>0&&Cy-i>0&&p[Cx-i][Cy-i]==Now)y++;
        else break;///向左上檢查
    if(y>=5)return Now;///若果達到5個則判斷當前走子玩家爲贏家
    for(i=1; i<5; i++)if(Cx+i<MAXIMUS&&Cy-i>0&&p[Cx+i][Cy-i]==Now)z++;
        else break;///向右上檢查
    for(i=1; i<5; i++)if(Cx-i>0&&Cy+i<MAXIMUS&&p[Cx-i][Cy+i]==Now)z++;
        else break;///向左下檢查
    if(z>=5)return Now;///若果達到5個則判斷當前走子玩家爲贏家
    return 0;///若沒有檢查到五連珠,則返回0表示還沒有玩家達成勝利
}
int RunGame()///進行整個對局,返回贏家信息(雖然有用上)
{
    int input;///輸入變量
    int victor;///贏家信息
    Initialize();///初始化對局
    while(1) ///開始無限回合的死循環,直到出現勝利跳出
    {
        Print();///打印棋盤
        input=getch();///等待鍵盤按下一個字符
        if(input==27)///如果是ESC則退出程序
        {
            exit(0);
        }
        else if(input==0x20)///如果是空格則開始走子
        {
            if(Put())///如果走子成功則判斷勝負
            {
                victor=Check();
                Now=3-Now;///輪換當前走子玩家
                count++;
                if(victor==1)///如果黑方達到勝利,顯示提示文字並等待一次按鍵,返回勝利信息
                {
                    showText="黑方獲得了勝利!";
                    Print();
                    if(getch()==0xE0)
                    {
                        getch();
                    }
                    return Now;
                }
                else if(victor==2)///如果白方達到勝利,顯示提示文字並等待一次按鍵,返回勝利信息
                {
                    showText="白方獲得了勝利!";
                    Display();
                    if(getch()==0xE0)
                    {
                        getch();
                    }
                    return Now;
                }
                else if(count==MAXIMUS*MAXIMUS) ///如果回合數達到了棋盤總量,即棋盤充滿,即爲平局
                {
                    showText="平局!";
                    Display();
                    if(getch()==0xE0)
                    {
                        getch();
                    }
                    return 0;
                }
            }
        }
        else if(input==0xE0)///如果按下的是方向鍵,會填充兩次輸入,第一次爲0xE0表示按下的是控制鍵
        {
            input=getch();///獲得第二次輸入信息
            ///對XT鍵盤以及之後的兼容鍵盤而言,
            ///0x48,0x4b,0x4d,0x50分別是上、左、右、下方向鍵的鍵盤掃描碼(在早期linux內核程序中可以看到)。
            ///該值與具體的硬件設備相關,例如XT機鍵盤與AT機鍵盤的差異就很大;
            switch(input)///判斷方向鍵方向並移動光標位置
            {
            case 0x4B:
                Cx--;
                break;
            case 0x48:
                Cy--;
                break;
            case 0x4D:
                Cx++;
                break;
            case 0x50:
                Cy++;
                break;
            }
            if(Cx<0) Cx=MAXIMUS-1;///如果光標位置越界則移動到對側
            if(Cy<0) Cy=MAXIMUS-1;
            if(Cx>MAXIMUS-1) Cx=0;
            if(Cy>MAXIMUS-1) Cy=0;
        }
    }
}
int main()///主函數
{
    system("title 簡易五子棋 ——Etsnarl製作");///設置標題
    system("mode con cols=63 lines=32");///設置窗口大小,寬度63字符,高度32字符
    system("color E0");///設置顏色
    while(1) ///循環執行遊戲
    {
        RunGame();
    }
}
 ///調用system("color ac");
///設置默認的控制檯前景和背景顏色。
 ///COLOR [attr] attr 指定控制檯輸出的顏色屬性
///顏色屬性由兩個十六進制數字指定 -- 第一個爲背景,
 ///第二個則爲 前景。
 ///每個數字可以爲以下任何值之一:
 ///0 = 黑色    8 = 灰色
/// 1 = 藍色    9 = 淡藍色
 ///2 = 綠色    A = 淡綠色
 ///3 = 淺綠色  B = 淡淺綠色
 ///4 = 紅色    C = 淡紅色
 ///5 = 紫色    D = 淡紫色
 ///6 = 黃色    E = 淡黃色
 ///7 = 白色    F = 亮白色

 

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