日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C语言实现中国象棋(Qt实现界面,源码下载,详细注释,易移植)

發(fā)布時(shí)間:2024/10/14 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言实现中国象棋(Qt实现界面,源码下载,详细注释,易移植) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言:中國象棋的規(guī)則很多人都懂,用C語言做一個(gè)中國象棋游戲,其要點(diǎn)是怎么把抽象的規(guī)則變成形象、具體的代碼。本項(xiàng)目提供詳細(xì)的實(shí)現(xiàn)思路,源碼附帶大量的注釋說明,源碼逐步地實(shí)現(xiàn)了每一種棋類的走棋規(guī)則、吃棋規(guī)則,將每一條細(xì)化的規(guī)則整合起來也就實(shí)現(xiàn)了一個(gè)完整的游戲規(guī)則。

本項(xiàng)目提供兩種調(diào)試方式,一種是帶界面操控(QT實(shí)現(xiàn)),一種是終端輸入操控。本項(xiàng)目非常適合初學(xué)者用以參考學(xué)習(xí)。

Qt 5.14完整源碼下載,點(diǎn)擊鏈接。效果預(yù)覽:

下載源碼:

? ? 源碼下載解壓后有兩個(gè)文件夾,分別是QT工程和Dev-C++工程,前者帶界面后者是終端輸入方式調(diào)試。

代碼設(shè)計(jì):

???? 兩個(gè)工程的源碼都包含了chess.cpp和chess.h兩個(gè)文件,這兩個(gè)文件實(shí)現(xiàn)了象棋的游戲規(guī)則,將一盤象棋游戲的所有操作通過接口來實(shí)現(xiàn),非常方便移植到其他的嵌入式平臺(tái)。下面先對(duì)這兩個(gè)源碼文件的部分內(nèi)容作說明。

typedef struct{eChessColour Colour:4;eChessClass Class:4; }ChessPiecesStr;//裝載棋子的容器,攜帶棋子顏色、棋子種類信息/*由多個(gè)棋子容器組成的虛擬棋盤 10(row)*9(col)*/ static ChessPiecesStr CheckerBoard[10][9];

ChessPiecesStr結(jié)構(gòu)體表示一個(gè)象棋包含的信息(顏色、棋類),那么可以定義這樣一個(gè)數(shù)組ChessPiecesStr ?CheckerBoard[10][9],它代表整個(gè)棋盤,10行,9列,每個(gè)數(shù)組元素代表棋盤的每一個(gè)位置上的棋子,如果某個(gè)元素的信息是NULL,則代表該位置上沒有棋子。我們?cè)谟螒蜻^程的走棋、吃棋、悔棋等操作,其實(shí)是對(duì)數(shù)組CheckerBoard里的數(shù)據(jù)進(jìn)行操作,然后將操作完的棋盤更新顯示出來。

typedef struct{ChessPiecesStr ChPs;uchar col,row;//位置:列、行 }PickUpChessStruct;//被選中的棋子,攜帶棋子所在的位置、棋子容器里的信息

PickUpChessStruct結(jié)構(gòu)體表示游戲者當(dāng)前要操作的棋子,它包含了該棋子的坐標(biāo)信息、棋色、棋類,這么封裝是為了方便實(shí)現(xiàn)每一種棋類的走棋規(guī)則、吃起規(guī)則,下面以炮的走棋規(guī)則為例:

bool MovemenRules_PAO(PickUpChessStruct* pActiveChess,uchar row,uchar col)//【炮】走棋規(guī)則 {int i,col_min,col_max,row_min,row_max;//【炮】走棋規(guī)則:走直線,不能跨越棋子//窮舉法+假設(shè)法 要么橫著走,要么豎著走,其他都是違規(guī);假設(shè)成功了,那么起點(diǎn)到終點(diǎn)之間不能有其他棋子if(pActiveChess->row == row){//橫著走if(pActiveChess->col > col){col_min = col;col_max = pActiveChess->col;}else{col_min = pActiveChess->col;col_max = col;}for(i = col_min+1;i < col_max; i++ ){if(CheckerBoard[row][i].Class != 0) return false;//假設(shè)不成立}return true;//假設(shè)成立}else if(pActiveChess->col == col){//豎著走if(pActiveChess->row > row){row_min = row;row_max = pActiveChess->row;}else{row_min = pActiveChess->row;row_max = row;}for(i = row_min+1;i < row_max; i++ ){if(CheckerBoard[i][col].Class != 0) return false;//假設(shè)不成立}return true;//假設(shè)成立}else{return false;} }

函數(shù)傳入的參數(shù)包括了一個(gè)類型PickUpChessStruct的結(jié)構(gòu)體代表拿起來將要操作的棋子,row、col代表落棋的位置,將這些信息傳入MovemenRules_PAO函數(shù)就能判斷是否滿足炮的走棋規(guī)則,注意這里僅僅是判斷,CheckerBoard數(shù)組也就是棋盤,并沒有發(fā)送發(fā)生任何變化。

bool MoveChess(char Operator,uchar start_row,uchar start_col,uchar end_row,uchar end_col)//將start_row,start_col處的棋子,移到end_row,end_col位置上 {bool ret = false;PickUpChessStruct ActiveChess;/*判斷游戲是否結(jié)束*/if(Winner != Cc_NULL) return ret;/*判斷選中的起始坐標(biāo)上是否有棋,若無棋返回*/if(CheckerBoard[start_row][start_col].Class == Cn_NULL){return ret;}/*判斷是否允許該操作者走棋*/if(CurOperator != Operator){return ret;}/*將選中的棋子信息復(fù)制到ActiveChess結(jié)構(gòu)體里*/ActiveChess.col = start_col;ActiveChess.row = start_row;ActiveChess.ChPs.Class = CheckerBoard[start_row][start_col].Class;ActiveChess.ChPs.Colour = CheckerBoard[start_row][start_col].Colour;//判斷落在位置是否有棋子if(CheckerBoard[end_row][end_col].Class != Cn_NULL){//落的位置有棋//1.判斷是否是己方棋子if(ActiveChess.ChPs.Colour == CheckerBoard[end_row][end_col].Colour){return false;}//2.判斷是否能吃ret = (*ChessEatRulesArry[(unsigned char)ActiveChess.ChPs.Class-1])(&ActiveChess,end_row,end_col);//該棋類的吃棋規(guī)則,將選中的棋子和要落得位置傳入if(ret == false){return ret;//不能吃,返回是失敗}else{//能吃,判斷被吃的是否是”將/帥“if(CheckerBoard[end_row][end_col].Class == Cn_JIANG){//游戲結(jié)束Winner = CheckerBoard[end_row][end_col].Colour==Cc_BLACK?Cc_RED:Cc_BLACK;}}}else{//落的位置沒棋,判斷是否能走ret = (*ChessMovemenRulesArry[(unsigned char)ActiveChess.ChPs.Class-1])(&ActiveChess,end_row,end_col);//該棋類的走棋規(guī)則,將選中的棋子,要落得位置傳入if(ret == false){return false;}}//能到這里說明符合走棋、吃棋規(guī)則,接下來進(jìn)行棋子移動(dòng)//切換操作者CurOperator = (CurOperator==Cc_BLACK)?Cc_RED:Cc_BLACK;//備份,實(shí)現(xiàn)悔棋功能pushStack(&CheckerBoard[ActiveChess.row][ActiveChess.col],ActiveChess.row,ActiveChess.col);pushStack(&CheckerBoard[end_row][end_col],end_row,end_col);//1.先棋盤中移除選中的棋CheckerBoard[ActiveChess.row][ActiveChess.col].Class = Cn_NULL;CheckerBoard[ActiveChess.row][ActiveChess.col].Colour = Cc_NULL;//2.將選中的棋放到新的位置 row colCheckerBoard[end_row][end_col].Class= ActiveChess.ChPs.Class;CheckerBoard[end_row][end_col].Colour= ActiveChess.ChPs.Colour;return ret; }

MoveChess函數(shù)是實(shí)現(xiàn)走棋的功能,參數(shù)Operator代表是操作者的身份(紅棋、黑棋),start_row、start_col代表選中的棋子在棋盤的位置,end_row、end_col代表選中的棋子落棋的位置。通過起始坐標(biāo)可以知道選中的棋子在CheckerBoard數(shù)組里的位置,從而知道該棋子是什么顏色什么棋類,再調(diào)用與該棋類相應(yīng)的走棋、吃棋規(guī)則函數(shù)來判斷是否合法。處理的每一步流程都有代碼注釋,不用看代碼框架圖也很容易理解。

悔棋功能是通過棧原理實(shí)現(xiàn)的,棧的特點(diǎn)是先進(jìn)后出,在棋盤上成功地走一步棋子,總共有兩個(gè)位置發(fā)生變化,不管是走棋還是吃棋,那么只要把這兩個(gè)位置的棋子信息保存到棧里面,并且如果棧滿了之后直接覆蓋較早的記錄,悔棋時(shí),從棧里取出上一步變化的兩個(gè)位置的信息,將其還原就行了。

Dev-C++工程使用

‘????? Dev-C++開發(fā)工具可以從網(wǎng)上免費(fèi)下載,上手容易,對(duì)于初學(xué)者來說是一款不錯(cuò)的學(xué)習(xí)工具;打開源碼工程后,可看到包括了兩個(gè)源碼文件是chess.cpp、chess.h,Dev-C++工程文件Chess-alone.dev,編譯生成的可執(zhí)行文件Chess-alone.exe。

main函數(shù):

int main(int argc, char *argv[]) {(void)argc;(void)argv;int start_row,start_col,end_row,end_col;InitCheckerBoard();CheckerBoardPrintf();PrintfTips();while(1){if(CurOperator == Cc_BLACK){printf("黑棋走棋:");}else{printf("紅棋走棋:");}fflush(stdin);scanf("(%d,%d)>(%d,%d)",&start_row,&start_col,&end_row,&end_col);if(start_row < 0 || start_row > 10 || start_col < 0 || start_col > 9||\end_row < 0 || end_row > 10 || end_col < 0 || end_col > 9){\PrintfTips();}MoveChess(CurOperator,start_row,start_col,end_row,end_col);CheckerBoardPrintf();if(Winner != Cc_NULL){if(Winner == Cc_BLACK){printf("黑棋勝利,游戲重新開始!\n");}else{printf("紅旗勝利,游戲重新開始!\n");}InitCheckerBoard();CheckerBoardPrintf();}}return 0; }

Main函數(shù)主要是從終端輸入走棋的起始坐標(biāo)和終點(diǎn)坐標(biāo)傳入MoveChess完成走棋操作,然后再將棋盤的內(nèi)容打印出來,實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的接口使用演示。這里不用糾結(jié)無法區(qū)分顏色的問題。效果圖如下:

Qt工程的使用

?????? Qt Creator是我經(jīng)常使用的一款開發(fā)工具,它可以開發(fā)跨平臺(tái)的應(yīng)用,比如說同一套代碼,可以編譯成window的應(yīng)用程序,還可以編譯成安卓的應(yīng)用程序,Linux等,而且它提供了豐富的開發(fā)接口和說明文檔;從官網(wǎng)上就可以下載免費(fèi)的個(gè)人開源版安裝包。

?????? 打開工程后,里面的文件說明如下:

?

Mainwindow.cpp文件里重寫了窗口類里的paintEvent函數(shù),每當(dāng)界面重繪時(shí)都會(huì)調(diào)用它,那么就可以將象棋的背景畫出來。

棋盤的背景通過QPainter畫線實(shí)現(xiàn),每一個(gè)棋子則是繼承了QPushButton類,棋盤上有9*10個(gè)這樣的按鈕,分別對(duì)應(yīng)CheckerBoard數(shù)組的9*10個(gè)元素,如果某個(gè)位置上沒有棋子就把該按鈕隱藏以來。

MyPiece繼承于QPushButton后重寫了鼠標(biāo)點(diǎn)擊、移動(dòng)、釋放事件,實(shí)現(xiàn)當(dāng)鼠標(biāo)點(diǎn)擊棋子時(shí),可以拖動(dòng)棋子,然后落到其他位置。當(dāng)鼠標(biāo)釋放時(shí),就可以得到鼠標(biāo)的起始坐標(biāo)和終點(diǎn)坐標(biāo),然后調(diào)用MoveChess進(jìn)行走棋。

效果圖:

下面展示部分代碼:

piece.c

#include "piece.h"MyPiece::MyPiece(QWidget *parent) :QPushButton(parent) {//none }MyPiece::~MyPiece() {//none }void MyPiece::Display(void)//將棋子顯示出來 {this->setText(QString(GetChessName(this->Colour,this->Class)));if(this->Colour == Cc_BLACK){this->setStyleSheet("QPushButton{background-color: rgb(255, 170, 127);""font-size:24px;color:black;border-style:solid;""border-width:1px;border-color:black;border-radius:20px;}");}else{this->setStyleSheet("QPushButton{background-color: rgb(255, 170, 127);""font-size:24px;color:red;border-style:solid;""border-width:1px;border-color:black;border-radius:20px;}");}this->setHidden(false); }void MyPiece::mousePressEvent(QMouseEvent *e)//棋子點(diǎn)擊事件 {//qDebug() <<e;Point_Start = this->pos();Point_Click = e->globalPos()-this->pos();/*將此小部件提升到父小部件堆棧的頂部*/this->raise(); }void MyPiece::mouseMoveEvent(QMouseEvent *e)//棋子移動(dòng)事件 {//qDebug() <<e;tPoint = e->globalPos()-Point_Click;/*限制棋子不能被拖到棋盤外*/tPoint.rx() = tPoint.rx() < 40?40:tPoint.rx();tPoint.rx() = tPoint.rx() > 520?520:tPoint.rx();tPoint.ry() = tPoint.ry() < 40?40:tPoint.ry();tPoint.ry() = tPoint.ry() > 580?580:tPoint.ry();/*讓棋子跟著鼠標(biāo)走*/this->move(tPoint); }void MyPiece::mouseReleaseEvent(QMouseEvent *e)//棋子釋放事件 {(void)e;unsigned char x_start,y_start,x_end,y_end;/*將棋子的起點(diǎn)和終點(diǎn)的像素位置轉(zhuǎn)換成在棋盤里的坐標(biāo)*/x_start=Point_Start.rx()/60;y_start=Point_Start.ry()/60;x_end=tPoint.rx()/60;y_end=tPoint.ry()/60;qDebug("(%d,%d)->(%d,%d)",x_start,y_start,x_end,y_end);/*得到起點(diǎn)和終點(diǎn)坐標(biāo)后,還原鼠標(biāo)選中的棋子,發(fā)出走棋信號(hào)就行,判斷是否真的移動(dòng)到終點(diǎn)交給外部處理*/this->move(Point_Start);/*若位置發(fā)生了改變,則發(fā)出走棋信號(hào)*/if(x_start != x_end || y_start != y_end){emit GoChess(y_start,x_start,y_end,x_end);} }

可擴(kuò)展的地方

  • 目前只是實(shí)現(xiàn)了在一臺(tái)電腦上對(duì)戰(zhàn)的游戲模式,可以對(duì)模式進(jìn)行擴(kuò)展,利用tcp/udp通訊協(xié)議,實(shí)現(xiàn)局域網(wǎng)對(duì)戰(zhàn)模式。
  • 可以給棋盤提供豐富的背景,調(diào)整棋子上的字體,棋子的外形、顏色。
  • 目前走棋只能通過鼠標(biāo)拖動(dòng),可以增加一種點(diǎn)擊的方式,鼠標(biāo)左鍵點(diǎn)擊一個(gè)棋子,再點(diǎn)擊另一個(gè)位置來完成走棋操作。
  • 可以將chess.c chess.h里的內(nèi)容用面向?qū)ο蟮姆椒▽?shí)現(xiàn),因?yàn)檫@里考慮到方便移植到其他的嵌入式平臺(tái),所以用C語言編寫。
  • 可以優(yōu)化以下走棋規(guī)則、吃棋規(guī)則的代碼,這里用的C語言充分體現(xiàn)了其面向過程編程的特點(diǎn),其中游戲處理流程可以簡(jiǎn)化。
  • ?

    如有錯(cuò)誤之處,還望指出,謝謝閱讀,求贊。

    ?

    ?

    《兼聽則明,偏信則暗。———資治通鑒》

    總結(jié)

    以上是生活随笔為你收集整理的C语言实现中国象棋(Qt实现界面,源码下载,详细注释,易移植)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。