五子棋GUI_C++
生活随笔
收集整理的這篇文章主要介紹了
五子棋GUI_C++
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
五子棋游戲人機對戰(zhàn) C/C++ (圖形界面)
準備:找好游戲圖片、音樂等基本素材。另外,代碼中的圖片尺寸數(shù)據(jù)根據(jù)各自的實際素材調(diào)整。
注:本人的素材均不做盈利用,不涉及版權(quán)。
tools文件是從相關(guān)網(wǎng)站學(xué)習(xí)課程上獲得的,此處對相關(guān)內(nèi)容不做明示。可以告知的是tools做的工作是使PNG圖片背景透明。
tools.h
主函數(shù):
#define _CRT_SECURE_NO_WARNINGS 1 /* * 設(shè)計一個人機交互程序——五子棋 也可參考設(shè)計軍棋、跳棋、圍棋、象棋 */ #include "ChessData.h"int main() { //_wuziqi2board_Init();//主要功能區(qū)while (1) { //~while(true) C/C++最好用while(1)MOUSEMSG msg = GetMouseMsg(); //獲取光標信息 如果報錯4996,項目名右鍵->屬性->c/c++->sdl檢查選否if (msg.uMsg == WM_LBUTTONDOWN && clickBoard(msg)) { //鼠標左鍵點擊落子 且是有效點擊man_Go();if (checkOver()) {board_Init();continue;}AI_Go();if (checkOver()) {board_Init();continue;}}}closegraph();system("pause");return 0; }“ChessData.h”文件內(nèi)容:(需要graphics.h)
說明:AI走子算法是關(guān)鍵。
“ChessData.cpp”文件內(nèi)容:
#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h> //NULL #include <math.h> //sqrt #include <string.h> #include <memory.h> //memset //string.h #include <conio.h> //getch #include <time.h> #include "ChessData.h"//加載圖片到內(nèi)存,提高效率 IMAGE chessBlackImg; //黑白子需要不斷輸出 IMAGE chessWhiteImg; int clickPosRow, clickPosCol; //表示有效點擊的實際位置(行列) struct ChessData game;void initChessData(struct ChessData* data) {if (!data) { //data == NULLreturn;}memset(data->chessMap, 0, sizeof(data->chessMap)); //比雙重for更高級memset(data->scoreMap, 0, sizeof(data->scoreMap));data->playerFlag = true; } void board_Init() {initgraph(673, 672); //根據(jù)圖片尺寸確定loadimage(0, "res/棋盤.jpg"); //加載報錯時,項目名右鍵->屬性->高級->字符集選擇多字節(jié)字符集//添加對戰(zhàn)開始背景音mciSendString("play res/start.wav", 0, 0, 0); //可以添加背景音樂,mciSendString("play 背景音樂 repeat", 0, 0, 0);loadimage(&chessBlackImg, "res/black.png", BLOCK_SIZE, BLOCK_SIZE, true); //圖片太大時true等比縮放loadimage(&chessWhiteImg, "res/white.png", BLOCK_SIZE, BLOCK_SIZE, true);initChessData(&game); }bool clickBoard(MOUSEMSG msg) {//上下邊界 x32 y31,定義在ChessData.h中int col = (msg.x - margin_x) / BLOCK_SIZE;int row = (msg.y - margin_y) / BLOCK_SIZE;int leftTopPosX = margin_x + col * BLOCK_SIZE;int leftTopPosY = margin_y + row * BLOCK_SIZE;int selectPos = false;do {//左上角int len = sqrt((msg.x - leftTopPosX) * (msg.x - leftTopPosX) +(msg.y - leftTopPosY) * (msg.y - leftTopPosY));if (len < POS_OFFSET) {clickPosRow = row;clickPosCol = col;selectPos = true;break;}//右上角 leftTopPosX+BLOCK_SIZE leftTopPosY,其余同理len = sqrt((msg.x - (leftTopPosX + BLOCK_SIZE)) * (msg.x - (leftTopPosX + BLOCK_SIZE)) +(msg.y - leftTopPosY) * (msg.y - leftTopPosY));if (len < POS_OFFSET) {clickPosRow = row;clickPosCol = col + 1;selectPos = true;break;}//右下角len = sqrt((msg.x - (leftTopPosX + BLOCK_SIZE)) * (msg.x - (leftTopPosX + BLOCK_SIZE)) +(msg.y - (leftTopPosY + BLOCK_SIZE)) * (msg.y - (leftTopPosY + BLOCK_SIZE)));if (len < POS_OFFSET) {clickPosRow = row + 1;clickPosCol = col + 1;selectPos = true;break;}//左下角len = sqrt((msg.x - leftTopPosX) * (msg.x - leftTopPosX) +(msg.y - (leftTopPosY + BLOCK_SIZE)) * (msg.y - (leftTopPosY + BLOCK_SIZE)));if (len < POS_OFFSET) {clickPosRow = row + 1;clickPosCol = col;selectPos = true;break;}} while (0); //只循環(huán)一次,關(guān)鍵作用是break避免使用returnreturn selectPos; } void chessDown(int row, int col, chess_kind_t kind) {mciSendString("play res/down7.WAV", 0, 0, 0);int x = margin_x + clickPosCol * BLOCK_SIZE - 0.5 * BLOCK_SIZE;int y = margin_y + clickPosRow * BLOCK_SIZE - 0.5 * BLOCK_SIZE;if (kind == CHESS_BLACK) {//putimage(msg.x, msg.y, &chessBlackImg); //在鼠標點擊處放圖片,從左上角開始鋪圖drawPNG(x, y, &chessBlackImg); //tools.h中的函數(shù)//還需要模糊算法處理擺正位置,模塊化,clickBoard}else {drawPNG(x, y, &chessWhiteImg);} } void updateGameMap(ChessData* data, int row, int col) {if (!data) {return;}if (data->playerFlag) {data->chessMap[row][col] = 1;}else {data->chessMap[row][col] = -1;}data->playerFlag = !data->playerFlag; //換手 }bool checkWin(ChessData* game, int row, int col) {//8個方向,本質(zhì)是4個方向只要有5連就算贏int i;//水平for (i = 0; i < 5; i++) {//左、右各匹配if (col - i >= 0 &&col - i + 4 < BOARD_GRADE_SIZE &&game->chessMap[row][col - i] == game->chessMap[row][col - i + 1] &&game->chessMap[row][col - i] == game->chessMap[row][col - i + 2] &&game->chessMap[row][col - i] == game->chessMap[row][col - i + 3] &&game->chessMap[row][col - i] == game->chessMap[row][col - i + 4] ) {return true;}}//豎直for (i = 0; i < 5; i++) {if (row - i >= 0 &&row - i + 4 < BOARD_GRADE_SIZE &&game->chessMap[row - i][col] == game->chessMap[row - i + 1][col] &&game->chessMap[row - i][col] == game->chessMap[row - i + 2][col] &&game->chessMap[row - i][col] == game->chessMap[row - i + 3][col] &&game->chessMap[row - i][col] == game->chessMap[row - i + 4][col] ){return true;}}// '/'for (i = 0; i < 5; i++) {if (row + i < BOARD_GRADE_SIZE &&row + i - 4 >= 0 &&col - i >= 0 &&col - i + 4 < BOARD_GRADE_SIZE &&//第[row+i]行,第[col-i]列的棋子,與右上方連續(xù)4子相同game->chessMap[row + i][col - i] == game->chessMap[row + i - 1][col - i + 1] &&game->chessMap[row + i][col - i] == game->chessMap[row + i - 2][col - i + 2] &&game->chessMap[row + i][col - i] == game->chessMap[row + i - 3][col - i + 3] &&game->chessMap[row + i][col - i] == game->chessMap[row + i - 4][col - i + 4] ){return true;}}// '\'for (i = 0; i < 5; i++) {if (row - i >= 0 &&row - i + 4 < BOARD_GRADE_SIZE &&col - i >= 0 &&col - i + 4 < BOARD_GRADE_SIZE &&//第[row-i]行,第[col-i]列的棋子,與右下方連續(xù)4子相同game->chessMap[row - i][col - i] == game->chessMap[row - i + 1][col - i + 1] &&game->chessMap[row - i][col - i] == game->chessMap[row - i + 2][col - i + 2] &&game->chessMap[row - i][col - i] == game->chessMap[row - i + 3][col - i + 3] &&game->chessMap[row - i][col - i] == game->chessMap[row - i + 4][col - i + 4] ){return true;}}return false; } bool checkOver() {if (checkWin(&game, clickPosRow, clickPosCol)) {//Sleep(1500);if (game.playerFlag == false) {mciSendString("play res/不錯.mp3", 0, 0, 0);loadimage(0, "res/勝利.jpg");}else {mciSendString("play res/失敗.mp3", 0, 0, 0);loadimage(0, "res/失敗.jpg");}getch();return true;}return false; }void man_Go() {chessDown(clickPosRow, clickPosCol, CHESS_BLACK);updateGameMap(&game, clickPosRow, clickPosCol); }//*************************系統(tǒng)評分函數(shù),是關(guān)鍵******************************* /* * 黑子 白子(連1/普通~~~5) * 連2 10 10 * 死3 30 25 * 活3 40 50 * 死4 60 55 * 活4 200 300 * 連5 20000 30000 */ void caculateScore(ChessData* data) {if (!data) {return;}int row, col, i, k;//統(tǒng)計玩家或電腦連子個數(shù)int man_Num = 0; //玩家連子個數(shù)int AI_Num = 0; //AI連子個數(shù)int emptyNum = 0; //空白位個數(shù)//清空評分數(shù)組memset(data->scoreMap, 0, sizeof(data->scoreMap));for (row = 0; row < BOARD_GRADE_SIZE; row++) {for (col = 0; col < BOARD_GRADE_SIZE; col++) {//空白點就算if (row >= 0 && col >= 0 && data->chessMap[row][col] == 0) {//遍歷周圍4個方向,考慮正反int direction[4][2] = { {1,0}, {1,1}, {0,1}, {-1,1} }; //for (k = 0; k < 4; k++) {int x = direction[k][0];int y = direction[k][1]; ////重置man_Num = 0;AI_Num = 0;emptyNum = 0;//黑方正向計數(shù)for (i = 1; i <= 4; i++) {if (row + i * y >= 0 &&row + i * y < BOARD_GRADE_SIZE &&col + i * x >= 0 &&col + i * x < BOARD_GRADE_SIZE &&data->chessMap[row + i * y][col + i * x] == 1){man_Num++;}else if (row + i * y >= 0 &&row + i * y < BOARD_GRADE_SIZE &&col + i * x >= 0 &&col + i * x < BOARD_GRADE_SIZE &&data->chessMap[row + i * y][col + i * x] == 0){emptyNum++;break; //遇到空白位,停止搜索}else { //出邊界或者遇到白棋,停止搜索break;}}//黑反for (i = 1; i <= 4; i++) {if (row - i * y >= 0 &&row - i * y < BOARD_GRADE_SIZE &&col - i * x >= 0 &&col - i * x < BOARD_GRADE_SIZE &&data->chessMap[row - i * y][col - i * x] == 1){man_Num++;}else if (row - i * y >= 0 &&row - i * y < BOARD_GRADE_SIZE &&col - i * x >= 0 &&col - i * x < BOARD_GRADE_SIZE &&data->chessMap[row - i * y][col - i * x] == 0){emptyNum++;break; //遇到空白位,停止搜索}else { //出邊界或者遇到白棋,停止搜索break;}}//黑,數(shù)->分 //elseif elseif (man_Num == 1) { //殺2data->scoreMap[row][col] += 10;}else if (man_Num == 2) { //殺3if (emptyNum == 1) { //死3data->scoreMap[row][col] += 30;}else if (emptyNum == 2) { //活3data->scoreMap[row][col] += 40;}}else if (man_Num == 3) { //殺4if (emptyNum == 1) {data->scoreMap[row][col] += 60;}else if (emptyNum == 2) {data->scoreMap[row][col] += 200;}}else if (man_Num == 4) { //殺5data->scoreMap[row][col] += 20000;}//進行一次清空emptyNum = 0;//對白棋評分for (i = 1; i <= 4; i++) { //正if (row + i * y > 0 &&row + i * y < BOARD_GRADE_SIZE &&col + i * x > 0 &&col + i * x < BOARD_GRADE_SIZE &&data->chessMap[row + i * y][col + i * x] == -1){AI_Num++;}else if (row + i * y > 0 &&row + i * y < BOARD_GRADE_SIZE &&col + i * x > 0 &&col + i * x < BOARD_GRADE_SIZE &&data->chessMap[row + i * y][col + i * x] == 0){emptyNum++;break;}else {break;}}for (i = 1; i <= 4; i++) { //反if (row - i * y > 0 &&row - i * y < BOARD_GRADE_SIZE &&col - i * x > 0 &&col - i * x < BOARD_GRADE_SIZE &&data->chessMap[row - i * y][col - i * x] == -1){AI_Num++;}else if (row - i * y > 0 &&row - i * y < BOARD_GRADE_SIZE &&col - i * x > 0 &&col - i * x < BOARD_GRADE_SIZE &&data->chessMap[row - i * y][col - i * x] == 0) //空白位{emptyNum++;break;}else { //出邊界break;}}if (AI_Num == 0) { //普通下子data->scoreMap[row][col] += 5;}else if (AI_Num == 1) { //活2data->scoreMap[row][col] += 10;}else if (AI_Num == 2) {if (emptyNum == 1) {data->scoreMap[row][col] += 25;}else if (emptyNum == 2) {data->scoreMap[row][col] += 50;}}else if (AI_Num == 3) {if (emptyNum == 1) {data->scoreMap[row][col] += 55;}else if (emptyNum == 2) {data->scoreMap[row][col] += 300;}}else if (AI_Num >= 4) {data->scoreMap[row][col] += 30000;}}}}} }point_t action_AI(ChessData* data) {caculateScore(data);int maxScore = 0;//std::vector<std::pair<int, int>>maxPoints;point_t maxPoints[BOARD_GRADE_SIZE * BOARD_GRADE_SIZE] = { 0, };int k = 0;for (int row = 0; row < BOARD_GRADE_SIZE; row++) { //面向?qū)ο笳Z言for (int col = 0; col < BOARD_GRADE_SIZE; col++) {//前提是坐標為空if (data->chessMap[row][col] == 0) {if (data->scoreMap[row][col] > maxScore) {//maxPoints.clear();memset(maxPoints, 0, sizeof(maxPoints));k = 0;maxScore = data->scoreMap[row][col];//maxPoints.push_back(std::make_pair(row, col));maxPoints[k].row = row;maxPoints[k].col = col;k++;}else if (data->scoreMap[row][col] == maxScore) {//maxPoints.push_back(std::make_pair(row, col));maxPoints[k].row = row;maxPoints[k].col = col;k++;}}}}srand((unsigned)time(0));int index = rand() % k;return maxPoints[index]; } void AI_Go() {point_t point = action_AI(&game);clickPosRow = point.row;clickPosCol = point.col;//Sleep(1000);chessDown(clickPosRow, clickPosCol, CHESS_WHITE);updateGameMap(&game, clickPosRow, clickPosCol); }附結(jié)果圖:
補充:已發(fā)現(xiàn)的漏洞有黑子可覆蓋白子,需要在玩家走子函數(shù)中添加判斷條件。
總結(jié)
以上是生活随笔為你收集整理的五子棋GUI_C++的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 多路选择器(multiplexer)简介
- 下一篇: multiplexer protocol