Оглавление
1. Введение функции
1. Создание и использование классов
2. Настройки интерфейса
3. Проектирование членов шахматной доски
4. Инициализация шахматной доски
5. Шахматисты играют в шахматы
6. Определить позицию щелчка шахматиста
7. Осознайте расположение шахматной доски.
8. Инициализация ИИ
9. ИИ играет в шахматы
10. Решение о победе или поражении
2. Функциональный дисплей
3. Код проекта
AI.h
#pragma once
#include "Chess.h"
class AI
{
public:
void init(Chess* chess);
void go();
private:
Chess* chess;
vector<vector<int>> scoreMap;
private:
void calculateScore();
ChessPos think();
};
Шахматы.ч
#pragma once
#include <graphics.h> //easux图形库的头文件
//准备:下载easyx图形库
#include <vector>
using namespace std;
//表示落子位置
struct ChessPos {
int row;
int col;
ChessPos(int r = 0, int c = 0) :row(r), col(c) {}
};
typedef enum {
CHESS_WHITE = -1, //白子
CHESS_BLACK=1 //黑子
}chess_kind_t;
class Chess
{
public:
Chess(int gradeSize, int marginX, int marginY, float chessSize);
//棋盘的初始化:加载棋盘的图片资源,初始化棋盘的相关数据
void init();
//判断在指定坐标(x,y)位置,是否是有效点击
//如果是有效点击,把有效点击的位置保存在参数pos中
bool clickBoard(int x, int y, ChessPos*pos);
//在棋盘的指定位置(pos),落子(kind)
void chessDown(ChessPos *pos, chess_kind_t kind);
//获取棋盘的大小(13,15,17,19)
int getGradeSize();
//获取其指定位置是黑棋,还是白棋,还是空白
int getChessData(ChessPos* pos);
int getChessData(int row, int col);
//检查是否结束
bool checkOver();
private:
IMAGE chessBlackImg; //黑棋棋子
IMAGE chessWhiteImg;//白棋棋子
int gradeSize; //棋盘的大小
int margin_x;//棋盘的左部边界
int margin_y; //棋盘的顶部边界
float chessSize; //棋子的大小(棋盘小方格的大小)
//存储当前棋局的棋子分布数据
// chessMap[3][5]表示棋盘的第三行第五列的落子情况 0:空白 1:黑子 -1:白子
vector<vector<int>>chessMap;
//via哦是现在该谁下棋(落子)
bool playerFlag; //true 黑子走 false 白子走
void updateGameMap(ChessPos* pos);
bool checkWin();
ChessPos lastPos;
};
ChessGame.h
#pragma once
#include "AI.h"
#include "Chess.h"
#include "Man.h"
class ChessGame
{
public:
ChessGame(Man* man, AI* ai, Chess* chess);
void play(); //开始对局
//添加数据成员
private:
Man* man;
AI* ai;
Chess* chess;
};
Ман.ч
#pragma once
#include "Chess.h"
class Man
{
public:
void init(Chess* chess);
void go();
private:
Chess *chess;
};
AI.cpp
#include "AI.h"
void AI::init(Chess* chess)
{
this->chess = chess;
int size = chess->getGradeSize();
for (int i = 0; i < size; i++) {
vector<int>row;
for (int j = 0; j < size; j++) {
row.push_back(0);
}
scoreMap.push_back(row);
}
}
void AI::go()
{
ChessPos pos = think();
Sleep(1000);
chess->chessDown(&pos, CHESS_WHITE);
}
void AI::calculateScore()
{
int personNum = 0; //棋手方(黑棋)多少个连续的棋子
int aiNum = 0; //AI方(白棋)连续有多少个连续的棋子
int emptyNum = 0; // 该方向上空白位的个数
// 评分向量数组清零
for (int i = 0; i < scoreMap.size(); i++) {
for (int j = 0; j < scoreMap[i].size(); j++) {
scoreMap[i][j] = 0;
}
}
int size = chess->getGradeSize();
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
//对每个点进行计算
if (chess->getChessData(row, col)) continue;
for (int y = -1; y <= 0; y++) { //Y的范围还是-1, 0
for (int x = -1; x <= 1; x++) { //X的范围是 -1,0,1
if (y == 0 && x == 0) continue;
if (y == 0 && x != 1) continue; //当y=0时,仅允许x=1
personNum = 0;
aiNum = 0;
emptyNum = 0;
// 假设黑棋在该位置落子,会构成什么棋型
for (int i = 1; i <= 4; i++) {
int curRow = row + i * y;
int curCol = col + i * x;
if (curRow >= 0 && curRow < size &&
curCol >= 0 && curCol < size &&
chess->getChessData(curRow, curCol) == 1) {
personNum++;
}
else if (curRow >= 0 && curRow < size &&
curCol >= 0 && curCol < size &&
chess->getChessData(curRow, curCol) == 0) {
emptyNum++;
break;
}
else {
break;
}
}
// 反向继续计算
for (int i = 1; i <= 4; i++) {
int curRow = row - i * y;
int curCol = col - i * x;
if (curRow >= 0 && curRow < size &&
curCol >= 0 && curCol < size &&
chess->getChessData(curRow, curCol) == 1) {
personNum++;
}
else if (curRow >= 0 && curRow < size &&
curCol >= 0 && curCol < size &&
chess->getChessData(curRow, curCol) == 0) {
emptyNum++;
break;
}
else {
break;
}
}
if (personNum == 1) { //连2
//CSDN 程序员Rock
scoreMap[row][col] += 10;
}
else if (personNum == 2) {
if (emptyNum == 1) {
scoreMap[row][col] += 30;
}
else if (emptyNum == 2) {
scoreMap[row][col] += 40;
}
}
else if (personNum == 3) {
if (emptyNum == 1) {
scoreMap[row][col] = 60;
}
else if (emptyNum == 2) {
scoreMap[row][col] = 5000; //200
}
}
else if (personNum == 4) {
scoreMap[row][col] = 20000;
}
// 假设白棋在该位置落子,会构成什么棋型
emptyNum = 0;
for (int i = 1; i <= 4; i++) {
int curRow = row + i * y;
int curCol = col + i * x;
if (curRow >= 0 && curRow < size &&
curCol >= 0 && curCol < size &&
chess->getChessData(curRow, curCol) == -1) {
aiNum++;
}
else if (curRow >= 0 && curRow < size &&
curCol >= 0 && curCol < size &&
chess->getChessData(curRow, curCol) == 0) {
emptyNum++;
break;
}
else {
break;
}
}
for (int i = 1; i <= 4; i++) {
int curRow = row - i * y;
int curCol = col - i * x;
if (curRow >= 0 && curRow < size &&
curCol >= 0 && curCol < size &&
chess->getChessData(curRow, curCol) == -1) {
aiNum++;
}
else if (curRow >= 0 && curRow < size &&
curCol >= 0 && curCol < size &&
chess->getChessData(curRow, curCol) == 0) {
emptyNum++;
break;
}
else {
break;
}
}
if (aiNum == 0) {
scoreMap[row][col] += 5;
}
else if (aiNum == 1) {
scoreMap[row][col] += 10;
}
else if (aiNum == 2) {
if (emptyNum == 1) {
scoreMap[row][col] += 25;
}
else if (emptyNum == 2) {
scoreMap[row][col] += 50;
}
}
else if (aiNum == 3) {
if (emptyNum == 1) {
scoreMap[row][col] += 55;
}
else if (emptyNum == 2) {
scoreMap[row][col] += 10000;
}
}
else if (aiNum >= 4) {
scoreMap[row][col] += 30000;
}
}
}
}
}
}
ChessPos AI::think()
{
calculateScore();
vector<ChessPos>maxPoints;
int maxScore = 0;
int size = chess->getGradeSize();
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
if (chess->getChessData(row, col) == 0) {
if (scoreMap[row][col] > maxScore) {
maxScore = scoreMap[row][col];
maxPoints.clear();
maxPoints.push_back(ChessPos(row, col));
}
else if (scoreMap[row][col] == maxScore) {
maxPoints.push_back(ChessPos(row,col));
}
}
}
}
int index = rand() % maxPoints.size();
return maxPoints[index];
}
Шахматы.cpp
#include <math.h>
#include "Chess.h"
#include <mmsystem.h>
#include<conio.h>
#pragma comment(lib,"winmm.lib")
void putimagePNG(int x, int y, IMAGE* picture) //x为载入图片的X坐标,y为Y坐标
{
// 变量初始化
DWORD* dst = GetImageBuffer(); // GetImageBuffer()函数,用于获取绘图设备的显存指针,EASYX自带
DWORD* draw = GetImageBuffer();
DWORD* src = GetImageBuffer(picture); //获取picture的显存指针
int picture_width = picture->getwidth(); //获取picture的宽度,EASYX自带
int picture_height = picture->getheight(); //获取picture的高度,EASYX自带
int graphWidth = getwidth(); //获取绘图区的宽度,EASYX自带
int graphHeight = getheight(); //获取绘图区的高度,EASYX自带
int dstX = 0; //在显存里像素的角标
// 实现透明贴图 公式: Cp=αp*FP+(1-αp)*BP , 贝叶斯定理来进行点颜色的概率计算
for (int iy = 0; iy < picture_height; iy++)
{
for (int ix = 0; ix < picture_width; ix++)
{
int srcX = ix + iy * picture_width; //在显存里像素的角标
int sa = ((src[srcX] & 0xff000000) >> 24); //0xAArrggbb;AA是透明度
int sr = ((src[srcX] & 0xff0000) >> 16); //获取RGB里的R
int sg = ((src[srcX] & 0xff00) >> 8); //G
int sb = src[srcX] & 0xff; //B
if (ix >= 0 && ix <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight)
{
dstX = (ix + x) + (iy + y) * graphWidth; //在显存里像素的角标
int dr = ((dst[dstX] & 0xff0000) >> 16);
int dg = ((dst[dstX] & 0xff00) >> 8);
int db = dst[dstX] & 0xff;
draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16) //公式: Cp=αp*FP+(1-αp)*BP ; αp=sa/255 , FP=sr , BP=dr
| ((sg * sa / 255 + dg * (255 - sa) / 255) << 8) //αp=sa/255 , FP=sg , BP=dg
| (sb * sa / 255 + db * (255 - sa) / 255); //αp=sa/255 , FP=sb , BP=db
}
}
}
}
Chess::Chess(int gradeSize, int marginX, int marginY, float chessSize)
{
this->gradeSize = gradeSize;
this->margin_x = marginX;
this->margin_y = marginY;
this->chessSize = chessSize;
playerFlag = CHESS_BLACK;
for (int i = 0; i < gradeSize; i++) {
vector<int>row;
for (int j = 0; j < gradeSize; j++) {
row.push_back(0);
}
chessMap.push_back(row);
}
}
void Chess::init()
{
//创建游戏窗口
initgraph(897, 895); // EX_SHOWCONSOLE
//显示棋盘图片
loadimage(0, "res/棋盘2.jpg");
//播放开始提示音
mciSendString("play res/start.wav", 0, 0, 0);
//加载黑棋和白棋棋子的图片
loadimage(&chessBlackImg, "res/black.png",chessSize,chessSize,true);
loadimage(&chessWhiteImg, "res/white.png",chessSize,chessSize,true);
//棋盘清零
for (int i = 0; i < chessMap.size(); i++) {
for (int j = 0; j < gradeSize; j++) {
chessMap[i][j] = 0;
}
}
playerFlag = true;
}
bool Chess::clickBoard(int x, int y, ChessPos* pos)
{
int col = (x - margin_x) / chessSize;
int row = (y - margin_y) / chessSize;
int leftTopPosX = margin_x + chessSize * col;
int leftTopPosY = margin_y + chessSize * row;
int offset = chessSize * 0.4;
int len;
bool ret = false;
do {
//左上角
len = sqrt((x - leftTopPosX) * (x - leftTopPosX) + (y - leftTopPosY) * (y - leftTopPosY));
if (len < offset) {
pos->row = row;
pos->col = col;
if (chessMap[pos->row][pos->col] == 0) {
ret = true;
}
break;
}
//右上角
int x2 = leftTopPosX + chessSize;
int y2 = leftTopPosY;
len = sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2));
if (len < offset) {
pos->row = row;
pos->col = col+1;
if (chessMap[pos->row][pos->col] == 0) {
ret = true;
}
break;
}
//左下角判断
x2 = leftTopPosX;
y2 = leftTopPosY + chessSize;
len = sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2));
if (len < offset) {
pos->row = row + 1;
pos->col = col;
if (chessMap[pos->row][pos->col] == 0) {
ret = true;
}
break;
}
//右下角判断
x2 = leftTopPosX + chessSize;
y2 = leftTopPosY + chessSize;
len = sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2));
if (len < offset) {
pos->row = row + 1;
pos->col = col + 1;
if (chessMap[pos->row][pos->col] == 0) {
ret = true;
}
break;
}
} while (0);
return ret;
}
void Chess::chessDown(ChessPos* pos, chess_kind_t kind)
{
mciSendString("play res/down7.WAV", 0, 0, 0);
int x = margin_x + chessSize * pos->col - 0.5 * chessSize;
int y = margin_y + chessSize * pos->row - 0.5 * chessSize;
if (kind == CHESS_WHITE) {
putimagePNG(x, y, &chessWhiteImg);
}
else {
putimagePNG(x, y, &chessBlackImg);
}
updateGameMap(pos);
}
int Chess::getGradeSize()
{
return gradeSize;
}
int Chess::getChessData(ChessPos* pos)
{
return chessMap[pos-> row][pos->col];
}
int Chess::getChessData(int row, int col)
{
return chessMap[row][col];
}
bool Chess::checkOver()
{
if (checkWin()) {
Sleep(1500);
if (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 Chess::updateGameMap(ChessPos* pos)
{
lastPos = *pos;
chessMap[pos->row][pos->col] = playerFlag ? CHESS_BLACK : CHESS_WHITE;
playerFlag = !playerFlag; //黑白方交换行棋
}
bool Chess::checkWin()
{
// 横竖斜四种大情况,每种情况都根据当前落子往后遍历5个棋子,有一种符合就算赢
// 水平方向
int row = lastPos.row;
int col = lastPos.col;
for (int i = 0; i < 5; i++)
{
// 往左5个,往右匹配4个子,20种情况
if (col - i >= 0 &&
col - i + 4 < gradeSize &&
chessMap[row][col - i] == chessMap[row][col - i + 1] &&
chessMap[row][col - i] == chessMap[row][col - i + 2] &&
chessMap[row][col - i] == chessMap[row][col - i + 3] &&
chessMap[row][col - i] == chessMap[row][col - i + 4])
return true;
}
// 竖直方向(上下延伸4个)
for (int i = 0; i < 5; i++)
{
if (row - i >= 0 &&
row - i + 4 < gradeSize &&
chessMap[row - i][col] == chessMap[row - i + 1][col] &&
chessMap[row - i][col] == chessMap[row - i + 2][col] &&
chessMap[row - i][col] == chessMap[row - i + 3][col] &&
chessMap[row - i][col] == chessMap[row - i + 4][col])
return true;
}
// “/"方向
for (int i = 0; i < 5; i++)
{
if (row + i < gradeSize &&
row + i - 4 >= 0 &&
col - i >= 0 &&
col - i + 4 < gradeSize &&
// 第[row+i]行,第[col-i]的棋子,与右上方连续4个棋子都相同
chessMap[row + i][col - i] == chessMap[row + i - 1][col - i + 1] &&
chessMap[row + i][col - i] == chessMap[row + i - 2][col - i + 2] &&
chessMap[row + i][col - i] == chessMap[row + i - 3][col - i + 3] &&
chessMap[row + i][col - i] == chessMap[row + i - 4][col - i + 4])
return true;
}
// “\“ 方向
for (int i = 0; i < 5; i++)
{
// 第[row+i]行,第[col-i]的棋子,与右下方连续4个棋子都相同
if (row - i >= 0 &&
row - i + 4 < gradeSize &&
col - i >= 0 &&
col - i + 4 < gradeSize &&
chessMap[row - i][col - i] == chessMap[row - i + 1][col - i + 1] &&
chessMap[row - i][col - i] == chessMap[row - i + 2][col - i + 2] &&
chessMap[row - i][col - i] == chessMap[row - i + 3][col - i + 3] &&
chessMap[row - i][col - i] == chessMap[row - i + 4][col - i + 4])
return true;
}
return false;
}
ChessGame.cpp
#include "ChessGame.h"
ChessGame::ChessGame(Man* man, AI* ai, Chess* chess)
{
this->man = man;
this->ai = ai;
this->chess = chess;
man->init(chess);
ai->init(chess);
}
//对局(开始五子棋游戏)
void ChessGame::play()
{
chess->init();
while (1) {
//先由棋手走棋
man->go();
if (chess->checkOver()) {
chess->init();
continue;
}
//由AI走
ai->go();
if (chess->checkOver()) {
chess->init();
continue;
}
}
}
Man.cpp
#include "Man.h"
void Man::init(Chess* chess)
{
this->chess = chess;
}
void Man::go()
{
MOUSEMSG msg;
ChessPos pos;
//通过chess对象来判断落子是否有效,以及落子功能
while (1) {
//获取鼠标点击消息
msg = GetMouseMsg();
if (msg.uMsg == WM_LBUTTONDOWN && chess->clickBoard(msg.x, msg.y, &pos)) {
break;
}
}
//printf("%d,%d\n", pos.row, pos.col);
//落子
chess->chessDown(&pos, CHESS_BLACK);
}
запускаемый файл
#include<iostream>
#include "ChessGame.h"
int main() {
Man man;
//Chess chess;
Chess chess(13, 44, 43, 67.3);
AI ai;
ChessGame game(&man, &ai, &chess);
game.play();
return 0;
}