有时我们也许会抱怨鱼和熊掌不可兼得,在一些实际生活场景中,我们没法既在A的环境了做a,又在B的环境里做b,让我们回到编程开发角度,假如你既要做CPU的相关开发,又要做机器学习深度学习从而不免要用到GPU,可是问题的关键在于这些不同的工作分别需要的软硬件设施并没有在方方面面做到兼容,我们不得不在我们的电脑存储空间中安装各种各样的软件、硬件来达到我们的目标,不过,这样的情况在intel推出自己的oneAPI异构编程工具后得到了改变。
oneAPI是干什么的?首先,oneAPI我们从字面意思去解构:“统一的接口”,这已经在一定程度上表明了oneAPI在统一程序编程模型的功能上的贡献。实际上,oneAPI作为一个编程模型,其使命即在于简化跨多平台的开发过程,这对于程序员来说可谓是一大福利,因为在不同的行业和不同的要求下,程序开发环境和框架都会有所不同,而统一的编程模型无疑使得跨平台、跨环境的开发交流得到极大的便利,同时也让程序员在跨不同的硬件架构上的程序开发过程能有一个更好的体验。统一的编程模型,统一的库函数等等无疑让开发变得更加规范,表达更加清晰且统一,增强了可读性的同时也使得编程变得更加规范化。
那么,有了好的统一的编程模型,我们还需要与之搭配的编程工具,例如intel公司提供的 dpc++语言等,其基于c++,同时又支持数据并行性和异构编程。下面是本人关于实现“五子连珠”项目的代码:
#pragma once
#include <iostream>
#include <cmath>
#include <string>
#include <string.h>
#include "def.h"
#include "ball.h"
using namespace std;
typedef struct _PATH
{
int num;
POS path[ROW_NUM * COL_NUM];
}PATH;
class BOARD
{
public:
BOARD();
void drawBoard(int rowNum, int colNum, int border);//画出棋盘框架
void produceBall(int num); //随机产生num个球
int scanBoard(); //扫描整个棋盘,设置每个球四个方向(neighbor)上的同颜色的球的个数
void setRootBall(int x, int y); //设置根球的位置
int getRootBall(POS &p); //得到根球的位置坐标
void slcRootBall(int x, int y); //选择根球
void setCurrentBall(int x, int y);//设置当前球的位置
int getCurrentBall(POS& p); //得到当前球的位置坐标
void bak2shortPath(const PATH& p);//将最短路径的相关数据存入最短路径
void recCurrentPath(int x, int y);//用于在查找路径时,按顺序记录当前路径中当前球的位置
void delCurrentPath(); //用于在查找路径时的回退,消除最后一个球的位置
void moveBall(int x, int y); //移动当前球到制定位置
void displayRowCol(); //显示当前球的行列号
void displayScore(); //显示当前得分
void displayOver(); //显示游戏结束和最终得分
void setOneBallNeighbor(int x, int y);
void isGameOver();
void getKbMouseAction();
int calculateRowCol(int x, int y, int& row, int& col);
void arrowMove(int kb, int cr);
int otherKb(int kb, int cr);
void run();
void findShortPath(int row, int col, int color);
void cancelAllObjSlc();//撤销遍历选中标志
void fixAllObjSlc();//修正选中标志
void displayCalculate(int flg); //显示正在计算最短路径
void showShortPath(int flg);//显示最短路径
private:
int score; //做成数组,存储多次游戏分数
int gameOver;
POS rootBall;
POS objectBall;
POS currentBall;
PATH shortPath;
PATH currentPath;
BALL ball[ROW_NUM][COL_NUM];
};
#include "ball.h"
#include "cmd_console_tools.h"
using namespace std;
BALL::BALL(int x,int y)
{
pos.x = x;
pos.y = y;
color = 0;
neighbor[0] = 0;
neighbor[1] = 0;
neighbor[2] = 0;
neighbor[3] = 0;
slc = 0;
objSlc = 0;
passSlc = 0;
//drawBall();
}
void BALL::setSlc(int choice)
{
if (choice > 0)
slc = 1;
else
slc = 0;
}
void BALL::setObjSlc(int choice)
{
if (choice > 0)
objSlc = choice;
else
objSlc = 0;
}
int BALL::getObjSlc()
{
return objSlc;
}
void BALL::setPassSlc(int choice)
{
if (choice > 0)
passSlc = 1;
else
passSlc = 0;
}
int BALL::getNeighborSlc()
{
if (neighbor[0] || neighbor[1] || neighbor[2] || neighbor[3])
{
return 1;
}
else
{
return 0;
}
}
/***************************************************************************
函数名称:
功 能:根据节点在矩阵中的位置(row, col)
计算节点打印输出的左上角位置(x, y),
输入参数:
返 回 值:
说 明:
***************************************************************************/
void BALL::calculateXY(int& x, int& y)
{
x = 4 + pos.y * 8;
y = 3 + pos.x * 4;
}
/***************************************************************************
函数名称:
功 能:画单个球,
输入参数:border==0 无框,1有框,邻居有无同颜色的球;slc==0未选中,1选中,当前球;
pos.x矩阵中节点的行号,pos.y矩阵中节点的列号
返 回 值:
说 明:
***************************************************************************/
const int backClr[21] = { COLOR_HWHITE,
COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, COLOR_RED, COLOR_PINK,
COLOR_YELLOW, COLOR_HBLUE, COLOR_HGREEN, COLOR_HCYAN, COLOR_HRED,
COLOR_HPINK, COLOR_HYELLOW, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN,
COLOR_RED, COLOR_PINK, COLOR_YELLOW, COLOR_HBLUE, COLOR_HGREEN };
const int foreClr[21] = { COLOR_HWHITE,
COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, COLOR_BLACK,
COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, COLOR_BLACK,
COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, COLOR_BLACK,
COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, COLOR_BLACK };
void BALL::drawBall( )
{
int i;
int j;
int x;
int y;
int neighborSlc;
if (color >= CLR_NUM || pos.x >= ROW_NUM || pos.y >= COL_NUM)
return;
neighborSlc = getNeighborSlc();
calculateXY(x, y); /*返回像素位置,x为列,y为行*/
cct_gotoxy(x, y); /*根据(pos.x, pos.y)换算出打印输出的左上角位置*/
for (i = 0; i < 3; i++) /*1字一行*/
{
cct_gotoxy(x, y + i);/*每次下移一行*/
if (slc == 0 && neighborSlc == 0 && passSlc == 0)/*未选中*/
{
cct_setcolor(backClr[color], foreClr[color]);/*设置前后景颜色*/
}
else if (slc == 1 || neighborSlc == 1 || passSlc == 1)
{
if(passSlc == 1 && color == 0)
{
cct_setcolor(backClr[color], COLOR_BLACK);/*设置前后景颜色*/
}
else
{
cct_setcolor(backClr[color], COLOR_HWHITE);/*设置前后景颜色*/
}
}
for (j = 0; j < 3; j++) /*1字两列*/
{
if (i == 0)/*最上边*/
{
if (slc != 0 || passSlc != 0)//如果被选中则画出外边框
{
if (j == 0) /*最上边的左侧边*/
cout << "┌";
else if (j == 2) /*最上边的右侧边*/
cout << "┐";
else/*最上边的中间边*/
cout << "─";
}
else
cout << " ";
}
else if (i == 2)/*最下边*/
{
if (slc != 0 || passSlc != 0)
{
if (j == 0) /*最下边的第左侧*/
cout << "└";
else if (j == 2) /*最下边的右侧边*/
cout << "┘";
else/*最下边的中间边*/
cout << "─";
}
else
cout << " ";
}
else/*中间竖边*/
{
if (j == 0 || j == 2)/*其它的左或右侧*/
if (slc != 0 || passSlc != 0)
cout << "│";
else
cout << " ";
else/*中间*/
{
if (passSlc != 0)
{
/*if (slc != 0)
{
cct_setcolor(backClr[color], COLOR_HWHITE);
}
else*/
{
cct_setcolor(backClr[color], foreClr[color]);/*设置前后景颜色*/
}
}
cout << setw(2) << color;
if (passSlc != 0)
{
if(color == 0)
{
cct_setcolor(backClr[color], COLOR_BLACK);/*设置前后景颜色*/
}
else
{
cct_setcolor(backClr[color], COLOR_HWHITE);/*设置前后景颜色*/
}
}
}
}
}
cct_setcolor(COLOR_BLACK, COLOR_WHITE);/*恢复前后景颜色*/
}
}
POS BALL::getPos()
{
return pos;
}
void BALL::setPos(int x,int y)
{
pos.x = x;
pos.y = y;
}
int BALL::getColor()
{
return color;
}
void BALL::setColor(int clr)
{
color = clr;
}
int BALL::getNeighbor(int direction)
{
if (direction >= 0 && direction <= 3)
{
return neighbor[direction];
}
else
return -1;
}
void BALL::setNeighbor(int direction, int num)
{
if (direction >= 0 && direction <= 3)
{
neighbor[direction] = num;
}
}
void BALL::copy(const BALL& ball)
{
color = ball.color;
neighbor[0] = 0;
neighbor[1] = 0;
neighbor[2] = 0;
neighbor[3] = 0;
slc = ball.slc;
objSlc = 0;
}
void BALL::clear()
{
color = 0;
neighbor[0] = 0;
neighbor[1] = 0;
neighbor[2] = 0;
neighbor[3] = 0;
slc = 0;
objSlc = 0;
}
#pragma once
#include <iostream>
#include <cmath>
#include <string>
#include <string.h>
#include "def.h"
using namespace std;
class BALL
{
public:
BALL(int x = 0, int y = 0);
void drawBall();
POS getPos();
void setPos(int x, int y);
int getColor();
void setColor(int clr);
int getNeighbor(int direction);
void setNeighbor(int direction, int num);
void setSlc(int choice);
void setObjSlc(int choice);
int getObjSlc();
void copy(const BALL& ball);
void clear();
void setPassSlc(int choice);
private:
void calculateXY(int& x, int& y);
int getNeighborSlc();
POS pos; //对象的位置坐标
int color; //对象颜色
int neighbor[4]; //对象的四个方向上的同颜色球的个数,
// [0]上下方向,[1]左右方向,[2]左上右下方向,[3]右上左下方向
int slc; //选中标志
int objSlc; //最短路径目标选中标志
int passSlc; //鼠标或键盘移动时暂时选中
};
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <conio.h>
#include <windows.h>
#include "ball.h"
#include "cmd_console_tools.h"
#include "board.h"
using namespace std;
BOARD::BOARD()
{
score = 0;
gameOver = 0;
rootBall.x = ROW_NUM;
rootBall.y = COL_NUM;
//objectBall.x = ROW_NUM;
//objectBall.y = COL_NUM;
currentBall.x = 0;
currentBall.y = 0;
shortPath.num = ROW_NUM * COL_NUM + 1;//表示当前最短路径没有数据,为空
currentPath.num = 0;
cct_setconsoleborder(80, 80, 128, 96);
cct_enable_mouse();//使能鼠标
cct_setcursor(CURSOR_INVISIBLE);
drawBoard(ROW_NUM, COL_NUM, 1);
for (int i = 0; i < ROW_NUM; i++)
{
for (int j = 0; j < COL_NUM; j++)
{
ball[i][j].setPos(i, j);
//ball[i][j].setSlc(0);
// ball[i][j].setColor(0);
ball[i][j].drawBall();
}
}
produceBall(7);
scanBoard();
setCurrentBall(currentBall.x, currentBall.y);
}
/***************************************************************************
函数名称:
功 能:画边框,
输入参数:border==0 只画外框,1外框和内格
返 回 值:
说 明:
***************************************************************************/
//画出棋盘框架
void BOARD::drawBoard(int rowNum, int colNum, int border)
{
int i;
int j;
/*
cct_setconsoleborder(3 + colNum * 8 + 2, 6 + rowNum * 4 + 1,
3 + colNum * 8 + 2, 6 + rowNum * 4 + 1);根据矩阵行列数调整窗口大小*/
cct_cls();
/*
cct_gotoxy(0, 0);
cout << "屏幕当前设置为:"
<< 5 + rowNum * 4 + 1 << "行"
<< 3 + colNum * 8 + 2 << "列";*/
cct_gotoxy(0, 1);
for (j = 0; j < colNum; j++)
cout << setw(8) << j;
for (i = 0; i < rowNum * 4 + 1; i++)/*1字一行*/
{
cct_gotoxy(0, i + 2);
if (i % 4 == 2)
cout << (char)('0' + i / 4) << ' ';
else
cout << " ";
cct_setcolor(COLOR_HWHITE, COLOR_HBLACK);/*设置前后景颜色*/
for (j = 0; j < colNum * 4 + 1; j++)/*1字两列*/
{
if (i == 0)/*最上边*/
{
if (j == 0) /*最上边的最左侧*/
cout << "┌";
else if (j == colNum * 4) /*最上边的右侧边*/
cout << "┐";
else if (j % 4 == 0)
{
if (border == 0)/*最上边左右节点的中间*/
cout << "─";
else
cout << "┬";
}
else/*最上边的其它*/
cout << "─";
}
else if (i == rowNum * 4)/*最下边*/
{
if (j == 0) /*最下边的最左侧*/
cout << "└";
else if (j == colNum * 4) /*最下边的右侧边*/
cout << "┘";
else if (j % 4 == 0)
{
if (border == 0)/*最下边左右节点的中间*/
cout << "─";
else
cout << "┴";
}
else/*最下边的其它*/
cout << "─";
}
else if (i % 4 == 0)/*上下节点中间*/
{
if (j == 0)/*上下节点中间的最左侧*/
{
if (border == 0)
cout << "│";
else
cout << "├";
}
else if (j == colNum * 4) /*上下节点中间的右侧边*/
{
if (border == 0)
cout << "│";
else
cout << "┤";
}
else if (j % 4 == 0)/*上下节点中间的左右节点中间*/
{
if (border != 0)
cout << "┼";
else
cout << " ";
}
else/*上下节点中间的其它*/
{
if (border != 0)
cout << "─";
else
cout << " ";
}
}
else /*其它竖边*/
{
if (j == 0 || j == colNum * 4)/*其它的最左或右侧*/
cout << "│";
else if (j % 4 == 0)/*其它的的左右节点中间*/
{
if (border != 0)
cout << "│";
else
cout << " ";
}
else/*上下节点中间的其它*/
cout << " ";
}
}
cct_setcolor(COLOR_BLACK, COLOR_WHITE);/*恢复前后景颜色*/
}
cct_gotoxy(0, i + 3);
}
//随机产生num个球
void BOARD::produceBall(int num)
{
int x;
int y;
int color;
int sum = 0;
for (int i = 0; i < ROW_NUM; i++)
{
for (int j = 0; j < COL_NUM; j++)
{
if (ball[i][j].getColor() == 0)
{
sum++;
}
}
}
if (sum < num)
{
num = sum;
}
srand((unsigned)time(NULL));
for (int i = 0; i < num; i++)
{
do
{
x = (unsigned)rand() % ROW_NUM;
y = (unsigned)rand() % COL_NUM;
} while (ball[x][y].getColor() != 0);
if (x == currentBall.x && y == currentBall.y)
{
ball[x][y].setPassSlc(1);
}
color = (unsigned)rand() % 6 + 1;
ball[x][y].setColor(color);
ball[x][y].drawBall();
}
}
void BOARD::setOneBallNeighbor(int x, int y)
{
int num = 0;
if (x >= 0 && x < ROW_NUM && y >= 0 && y < COL_NUM)
{
for (int i = y + 1; i < COL_NUM; i++)
{
if (ball[x][i].getColor() == ball[x][y].getColor() && ball[x][i].getColor() != 0)
{
num++;
}
else
break;
}
for (int i = y - 1; i >= 0; i--)
{
if (ball[x][i].getColor() == ball[x][y].getColor() && ball[x][i].getColor() != 0)
{
num++;
}
else
break;
}
ball[x][y].setNeighbor(1, num);//左右方向
num = 0;
for (int j = x + 1; j < ROW_NUM; j++)
{
if (ball[j][y].getColor() == ball[x][y].getColor() && ball[j][y].getColor() != 0)
{
num++;
}
else
break;
}
for (int j = x - 1; j >= 0;j--)
{
if (ball[j][y].getColor() == ball[x][y].getColor() && ball[j][y].getColor() != 0)
{
num++;
}
else
break;
}
ball[x][y].setNeighbor(0, num);//上下方向
num = 0;
for (int j = x+1,i = y+1; j < ROW_NUM && i < COL_NUM; j++,i++)
{
if (ball[j][i].getColor() == ball[x][y].getColor() && ball[j][i].getColor() != 0)
{
num++;
}
else
break;
}
for (int j = x-1, i = y-1; j >= 0 && i >= 0; j--, i--)
{
if (ball[j][i].getColor() == ball[x][y].getColor() && ball[j][i].getColor() != 0)
{
num++;
}
else
break;
}
ball[x][y].setNeighbor(3, num);//左上右下方向
num = 0;
for (int j = x-1, i = y+1; j >= 0 && i < COL_NUM; j--, i++)
{
if (ball[j][i].getColor() == ball[x][y].getColor() && ball[j][i].getColor() != 0)
{
num++;
}
else
break;
}
for (int j = x+1, i = y-1; j < ROW_NUM && i >= 0; j++, i--)
{
if (ball[j][i].getColor() == ball[x][y].getColor() && ball[j][i].getColor() != 0)
{
num++;
}
else
break;
}
ball[x][y].setNeighbor(2, num);//右上左下方向
num = 0;
}
}
//扫描整个棋盘,设置每个球四个方向(neighbor)上的同颜色的球的个数
int BOARD::scanBoard()
{
int flag = 0;
for (int i = 0; i < ROW_NUM; i++)
{
for (int j = 0; j < COL_NUM; j++)
{
setOneBallNeighbor(i, j);
}
}
for (int i = 0; i < ROW_NUM; i++)
{
for (int j = 0; j < COL_NUM; j++)
{
if (ball[i][j].getNeighbor(0) >= CONNECT_MIN ||
ball[i][j].getNeighbor(1) >= CONNECT_MIN ||
ball[i][j].getNeighbor(2) >= CONNECT_MIN ||
ball[i][j].getNeighbor(3) >= CONNECT_MIN)
{
flag = 1;
score = score + 2;
ball[i][j].clear();
if (i == rootBall.x && j == rootBall.y) //当前球被消掉后,当前球记录被置为无效
{
rootBall.x = ROW_NUM;
rootBall.y = COL_NUM;
}
ball[i][j].drawBall();
}
else if(ball[i][j].getNeighbor(0) > 0||
ball[i][j].getNeighbor(1) > 0 ||
ball[i][j].getNeighbor(2) > 0 ||
ball[i][j].getNeighbor(3) > 0)
{
ball[i][j].drawBall();
}
}
}
int sum = 0;
for (int i = 0; i < ROW_NUM; i++)
{
for (int j = 0; j < COL_NUM; j++)
{
setOneBallNeighbor(i, j);
if (ball[i][j].getColor() == 0)
{
sum++;
}
}
}
if (sum == ROW_NUM * COL_NUM)
{
produceBall(7);
}
displayScore();
return flag;
}
//设置根球的位置
void BOARD::setRootBall(int x, int y)
{
if (x >= 0 && x < ROW_NUM && y >= 0 && y < COL_NUM)
{
if (ball[x][y].getColor() != 0)
{
rootBall.x = x;
rootBall.y = y;
}
}
}
//得到根球的位置坐标
int BOARD::getRootBall(POS& p)
{
if (rootBall.x >= ROW_NUM || rootBall.y >= COL_NUM ||
rootBall.x < 0 || rootBall.y < 0)
return -1;
else
{
p = rootBall;
return 0;
}
}
//撤销遍历选中标志
void BOARD::cancelAllObjSlc()
{
for (int i = 0; i < ROW_NUM; i++)
{
for (int j = 0; j < COL_NUM; j++)
{
ball[i][j].setObjSlc(0);
}
}
fixAllObjSlc();
}
//修正选中标志
void BOARD::fixAllObjSlc()
{
int i;
int j;
if (rootBall.x >= ROW_NUM || rootBall.x < 0 || rootBall.y >= COL_NUM || rootBall.y < 0)
return;
if (ball[0][0].getColor() == 0 &&
ball[0][1].getColor() == 0 &&
ball[1][0].getColor() == 0 &&
ball[1][1].getColor() == 0)
{
ball[0][0].setObjSlc(2);//左上角
}
if (ball[0][COL_NUM - 1].getColor() == 0 &&
ball[0][COL_NUM - 2].getColor() == 0 &&
ball[1][COL_NUM - 1].getColor() == 0 &&
ball[1][COL_NUM - 2].getColor() == 0)
{
ball[0][COL_NUM - 1].setObjSlc(2);//右上角
}
if (ball[ROW_NUM - 1][0].getColor() == 0 &&
ball[ROW_NUM - 1][1].getColor() == 0 &&
ball[ROW_NUM - 2][0].getColor() == 0 &&
ball[ROW_NUM - 2][1].getColor() == 0)
{
ball[ROW_NUM - 1][0].setObjSlc(2);//左下角
}
if (ball[ROW_NUM - 1][COL_NUM - 1].getColor() == 0 &&
ball[ROW_NUM - 1][COL_NUM - 2].getColor() == 0 &&
ball[ROW_NUM - 2][COL_NUM - 1].getColor() == 0 &&
ball[ROW_NUM - 2][COL_NUM - 2].getColor() == 0)
{
ball[ROW_NUM - 1][COL_NUM - 1].setObjSlc(2);//右下角
}
for (i = 0; i < ROW_NUM; i++)
{
for (j = 0; j < COL_NUM; j++)
{
if (i == 0 && j > 0 && j < COL_NUM - 1)//上边沿
{
if(ball[i][j].getColor() == 0 &&
ball[i][j-1].getColor() == 0 &&//左面
ball[i][j+1].getColor() == 0 &&//右面
ball[i+1][j-1].getColor() == 0 &&//左下
ball[i+1][j].getColor() == 0 && //下
ball[i+1][j+1].getColor() == 0) //右下
ball[i][j].setObjSlc(2);
}
if (i == ROW_NUM - 1 && j > 0 && j < COL_NUM - 1)//下边沿
{
if (ball[i][j].getColor() == 0 &&
ball[i][j-1].getColor() == 0 &&//左面
ball[i][j+1].getColor() == 0 &&//右面
ball[i-1][j-1].getColor() == 0 &&//左上
ball[i-1][j].getColor() == 0 &&//上
ball[i-1][j+1].getColor() == 0)//右上
ball[i][j].setObjSlc(2);
}
if (j == 0 && i > 0 && i < ROW_NUM - 1)//左边沿
{
if (ball[i][j].getColor() == 0 &&
ball[i-1][j].getColor() == 0 &&//上面
ball[i+1][j].getColor() == 0 &&//下面
ball[i-1][j+1].getColor() == 0 &&//右上
ball[i][j+1].getColor() == 0 &&//右面
ball[i+1][j+1].getColor() == 0)//右下
ball[i][j].setObjSlc(2);
}
if (j == COL_NUM - 1 && i > 0 && i < ROW_NUM - 1)//右边沿
{
if (ball[i][j].getColor() == 0 &&
ball[i-1][j].getColor() == 0 &&//上面
ball[i+1][j].getColor() == 0 &&//下面
ball[i-1][j-1].getColor() == 0 &&//左上
ball[i][j-1].getColor() == 0 &&//左面
ball[i+1][j-1].getColor() == 0)//左下
ball[i][j].setObjSlc(2);
}
if (i > 0 && i < ROW_NUM - 1 && j > 0 && j < COL_NUM - 1)//中间部分
{
if (ball[i][j].getColor() == 0 && //中间球
ball[i-1][j].getColor() == 0 && ball[i - 1][j].getObjSlc() != 2 && //上面球
ball[i+1][j].getColor() == 0 && ball[i + 1][j].getObjSlc() != 2 && //下面球
ball[i][j-1].getColor() == 0 && ball[i][j - 1].getObjSlc() != 2 && //左面球
ball[i][j+1].getColor() == 0 && ball[i][j + 1].getObjSlc() != 2 && //右面球
ball[i-1][j-1].getColor() == 0 && //左上角球
ball[i-1][j+1].getColor() == 0 && //右上角球
ball[i+1][j-1].getColor() == 0 && //左下角球
ball[i+1][j+1].getColor() == 0) //右下角球
ball[i][j].setObjSlc(2);
}
}
}
//寻找某行全部被修正的
for (i = 0; i < ROW_NUM; i++)
{
for (j = 0; j < COL_NUM; j++)
{
if (ball[i][j].getObjSlc() != 2)
break;
}
if (j >= COL_NUM && i != 0 && i != ROW_NUM-1) //该i行被全部修正了
{
ball[i][rootBall.y].setObjSlc(0);
}
}
//寻找某列全部被修正的
for (j = 0; j < COL_NUM; j++)
{
for (i = 0; i < ROW_NUM; i++)
{
if (ball[i][j].getObjSlc() != 2)
break;
}
if (i >= ROW_NUM && j != 0 && j != COL_NUM - 1) //该i行被全部修正了
{
ball[rootBall.x][j].setObjSlc(0);
}
}
}
void BOARD::displayCalculate(int num)
{
cct_gotoxy(0, 4 + ROW_NUM * 4);
if(num == -1)
cout << "正在计算路径.... " << endl;
else if (num >= 0)
cout << "路径计算完毕,有最短路径 " << num << endl;
else
cout << "路径计算完毕,未找到路径 " << endl;
}
//选择根球
void BOARD::slcRootBall(int x, int y)
{
int color;
if (x >= ROW_NUM || x < 0 || y >= COL_NUM || y < 0)
return;
color = ball[x][y].getColor();
if (color == 0)
return;
if (rootBall.x >= 0 && rootBall.x < ROW_NUM &&
rootBall.y >= 0 && rootBall.y < COL_NUM)
{
ball[rootBall.x][rootBall.y].setSlc(0);
ball[rootBall.x][rootBall.y].drawBall();
}
setRootBall(x, y);
ball[x][y].setSlc(1);
ball[x][y].drawBall();
showShortPath(0);
displayCalculate(-1);
shortPath.num = ROW_NUM * COL_NUM + 1;
cancelAllObjSlc();
currentPath.num = 0;
findShortPath(x - 1, y, color);
cancelAllObjSlc();
currentPath.num = 0;
findShortPath(x, y - 1, color);
cancelAllObjSlc();
currentPath.num = 0;
findShortPath(x, y + 1, color);
cancelAllObjSlc();
currentPath.num = 0;
findShortPath(x + 1, y, color);
if (shortPath.num < ROW_NUM * COL_NUM + 1)
{
displayCalculate(shortPath.num);
showShortPath(1);
}
else
displayCalculate(-2);
}
void BOARD::showShortPath(int flg)//显示最短路径
{
int i;
int x;
int y;
if (shortPath.num >= ROW_NUM * COL_NUM + 1)
return;
if (flg == 1)
{
for (i = 0; i < shortPath.num; i++)
{
x = shortPath.path[i].x;
y = shortPath.path[i].y;
ball[x][y].setPassSlc(1);
ball[x][y].drawBall();
}
}
else
{
for (i = 0; i < shortPath.num; i++)
{
x = shortPath.path[i].x;
y = shortPath.path[i].y;
ball[x][y].setPassSlc(0);
ball[x][y].drawBall();
}
}
}
//设置当前选中的球的位置
void BOARD::setCurrentBall(int x, int y)
{
if (x >= 0 && x < ROW_NUM && y >= 0 && y < COL_NUM)
{
/*取消以前的显示*/
ball[currentBall.x][currentBall.y].setPassSlc(0);
ball[currentBall.x][currentBall.y].drawBall();
currentBall.x = x;
currentBall.y = y;
/*更新当前的显示*/
ball[currentBall.x][currentBall.y].setPassSlc(1);
ball[currentBall.x][currentBall.y].drawBall();
displayRowCol();
}
}
//得到当前球的位置坐标
int BOARD::getCurrentBall(POS& p)
{
if (currentBall.x < 0 || currentBall.x >= ROW_NUM ||
currentBall.y < 0 || currentBall.y >= COL_NUM)
return 0;
else
{
p.x = currentBall.x;
p.y = currentBall.y;
return 1;
}
}
//将最短路径的相关数据存入最短路径
void BOARD::bak2shortPath(const PATH& p)
{
if (p.num < shortPath.num)
{
shortPath.num = p.num;
for (int i = 0; i < p.num; i++)
{
shortPath.path[i].x = p.path[i].x;
shortPath.path[i].y = p.path[i].y;
}
}
}
//用于在查找路径时,按顺序记录当前路径中当前球的位置
void BOARD::recCurrentPath(int x, int y)
{
if (currentPath.num < ROW_NUM * COL_NUM - 1)
{
currentPath.path[currentPath.num].x = x;
currentPath.path[currentPath.num].y = y;
currentPath.num++;
}
else
{
cct_gotoxy(0, 4 + (ROW_NUM) * 4 + 8);
cout << "++ currentPath.num " << currentPath.num;
}
}
//用于在查找路径时的回退,消除最后一个球的位置
void BOARD::delCurrentPath()
{
if(currentPath.num > 0)
currentPath.num--;
else
{
cct_gotoxy(0, 4 + (ROW_NUM) * 4 + 8);
cout << "-- currentPath.num " << currentPath.num;
}
}
//移动根球到制定位置
void BOARD::moveBall(int x, int y)
{
if (x < 0 || x >= ROW_NUM ||
y < 0 || y >= COL_NUM)
return;
if (rootBall.x < ROW_NUM && rootBall.y < COL_NUM)
{
if ((rootBall.x == x + 1 && rootBall.y == y ||
rootBall.x == x - 1 && rootBall.y == y ||
rootBall.x == x && rootBall.y == y + 1 ||
rootBall.x == x && rootBall.y == y - 1)
&& ball[x][y].getColor() == 0)
{
ball[x][y].copy(ball[rootBall.x][rootBall.y]);
ball[rootBall.x][rootBall.y].clear();
ball[rootBall.x][rootBall.y].drawBall();
if (!scanBoard())
{
produceBall(3);
scanBoard();
}
slcRootBall(x, y);
}
else
{
isGameOver();
}
}
}
//显示得分
void BOARD::displayRowCol()
{
cct_gotoxy(0 , 4 + ROW_NUM * 4 + 1);
cout << "当前行号:"<<currentBall.x << ", 当前列号:" << currentBall.y << endl;
}
void BOARD::displayScore()
{
cct_gotoxy(0, 4 + (ROW_NUM) * 4 + 2);
cout << "当前得分:" << score <<" (按q或Q可以退出)"<< endl;
}
void BOARD::displayOver()
{
cct_gotoxy(0, 4 + (ROW_NUM) * 4 + 3);
cout << "游戏结束,最终得分为:" << score << endl;
cct_gotoxy(0, 4 + (ROW_NUM) * 4 + 5);
}
void BOARD::isGameOver()
{
int i = 0;
int j = 0;
for (i = 0; i < ROW_NUM; i++)
{
for (j = 0; j < COL_NUM; j++)
{
if (ball[i][j].getColor() == 0)
{
return;
}
}
}
gameOver = 1;
}
/***************************************************************************
函数名称:
功 能:根据鼠标位置(x, y)判断节点在矩阵中的位置(row, col)
输入参数:
返 回 值:0表示位置非法,1是矩阵的节点
说 明:
***************************************************************************/
int BOARD::calculateRowCol(int x, int y, int& row, int& col)
{
int i;
int j;
for (i = 0; i < ROW_NUM; i++)
{
for (j = 0; j < COL_NUM; j++)
{
if (x >= 4 + j * 8 && x <= 4 + j * 8 + 5 &&
y >= 3 + i * 4 && y <= 3 + i * 4 + 2)
{
row = i;
col = j;
return 1;
}
}
}
row = -1;
col = -1;
return 0;
}
/***************************************************************************
函数名称:
功 能:箭头按键处理
输入参数:
返 回 值:
说 明:
***************************************************************************/
void BOARD::arrowMove(int kb, int cr)
{
POS pos;
if (getCurrentBall(pos))
{
if (kb == KB_ARROW_LEFT)
pos.y = (COL_NUM + pos.y - 1) % COL_NUM;
else if (kb == KB_ARROW_RIGHT)
pos.y = (pos.y + 1) % COL_NUM;
else if (kb == KB_ARROW_UP)
pos.x = (ROW_NUM + pos.x - 1) % ROW_NUM;
else if (kb == KB_ARROW_DOWN)
pos.x = (pos.x + 1) % ROW_NUM;
else
return;
}
/*获取当前指向的矩阵节点位置
if (cr == 1)
{*/
/*mouseMoveOrArrow*/setCurrentBall(pos.x, pos.y);
/* }
else */if (cr == 0)
{
if ((pos.x == rootBall.x + 1 && pos.y == rootBall.y ||
pos.x == rootBall.x - 1 && pos.y == rootBall.y ||
pos.x == rootBall.x && pos.y == rootBall.y + 1 ||
pos.x == rootBall.x && pos.y == rootBall.y - 1)
&& ball[pos.x][pos.y].getColor() == 0)
{
moveBall(pos.x, pos.y);
}
}
}
/***************************************************************************
函数名称:
功 能:非箭头按键(主要是回车键、Y、N、Q、C)处理
输入参数:
返 回 值:
说 明:
***************************************************************************/
int BOARD::otherKb(int kb, int cr)
{
int ret = -1;
if (kb == '\r') /*回车键*/
{
if (currentBall.x != ROW_NUM && currentBall.y != COL_NUM) //当前球有效
{
if ((rootBall.x == currentBall.x && rootBall.y == currentBall.y) && //当前球为根球,并敲回车,下次移动方向键不移动根球
ball[currentBall.x][currentBall.y].getColor() != 0 && cr == 0)
{
ret = 1;
}
else if (ball[currentBall.x][currentBall.y].getColor() != 0) //当前球不为根球,并敲回车
{
slcRootBall(currentBall.x, currentBall.y);
ret = 0;
}
}
}
else if (kb == 'Q' || kb == 'q')
{
gameOver = 1;
}
return ret;
}
/***************************************************************************
函数名称:
功 能:获取鼠标或鼠标的动作
输入参数:
返 回 值:
说 明:
***************************************************************************/
void BOARD::getKbMouseAction()
{
int x;
int y;
int row;
int col;
int ret;
int cctRet;
int kb0;
int kb1;
int mAction;
static int cr=1;
cctRet = cct_read_keyboard_and_mouse(x, y, mAction, kb0, kb1); /*获取键盘和鼠标的动作*/
if (cctRet == CCT_MOUSE_EVENT)/*鼠标动作*/
{
ret = calculateRowCol(x, y, row, col);
if (mAction == MOUSE_ONLY_MOVED)/*只移动了位置*/
{
if (ret)/*鼠标/箭头键移动后,指向了矩阵中某个节点*/
{
/*mouseMoveOrArrow*/ setCurrentBall(row, col);
}
/*else 鼠标/箭头键移动后,未指向了矩阵中任何一个节点
{
cct_gotoxy(0, 4 + ROW_NUM * 4 + 8); //定位当矩阵显示完后的下一行
cout << "[当前鼠标] " << "位置非法";
}*/
}
else if (mAction == MOUSE_LEFT_BUTTON_CLICK)/*只左键单击*/
{
if (ret)
{
if (ball[row][col].getColor() != 0)
{
slcRootBall(row, col);
}
else
{
moveBall(row, col);
}
}
}
/*else if (mAction == MOUSE_RIGHT_BUTTON_CLICK)只右键单击
{
if (rootBall.x != ROW_NUM && rootBall.y != COL_NUM)
{
if (ball[row][col].getColor() == ball[rootBall.x][rootBall.y].getColor())
{
objectBall.x = row;
objectBall.y = col;
ball[objectBall.x][objectBall.y].setSlc(1);
ball[objectBall.x][objectBall.y].drawBall();
}
}
}*/
/*else 其它鼠标按键
{
}*/
}
else if (cctRet == CCT_KEYBOARD_EVENT)/*键盘动作*/
{
if (kb0 == 0xe0)/*箭头按键,只移动位置*/
{
arrowMove(kb1, cr);
}
else/*其它按键*/
{
cr=otherKb(kb0, cr);
}
}
}
/***************************************************************************
函数名称:
功 能:
输入参数:
返 回 值:
说 明:
***************************************************************************/
void BOARD::run()
{
while (gameOver == 0)
{
getKbMouseAction();
isGameOver();
Sleep(10);
}
displayOver();
}
/***************************************************************************
函数名称:
功 能:递归方式从指定坐标位置(行号、列号)处开始遍历
输入参数:
返 回 值:
说 明:
***************************************************************************/
void BOARD::findShortPath(int row, int col, int color)
{
if (row >= ROW_NUM || row < 0 || col >= COL_NUM || col < 0)
return; //越界
if (ball[row][col].getColor() != 0 && ball[row][col].getColor() != color)
return; //其他球挡路
if (ball[row][col].getObjSlc())
return; //已经遍历过,或修正过的球
if(row == rootBall.x && col == rootBall.y)
return; //根球
if (ball[row][col].getColor() == color) //同色球
{
bak2shortPath(currentPath);
return;
}
ball[row][col].setObjSlc(1);
recCurrentPath(row, col);
//[row][col].setPassSlc(1);
//ball[row][col].drawBall();
//Sleep(10);
findShortPath(row - 1, col, color);/*向上遍历*/
findShortPath(row, col - 1, color);/*向左遍历*/
findShortPath(row, col + 1, color);/*向右遍历*/
findShortPath(row + 1, col, color);/*向下遍历*/
delCurrentPath();
if (ball[row][col].getObjSlc() == 1)
ball[row][col].setObjSlc(0);
//ball[row][col].setPassSlc(0);
//ball[row][col].drawBall();
//Sleep(10);
}
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <conio.h>
#include <windows.h>
#include "ball.h"
#include "cmd_console_tools.h"
#include "board.h"
using namespace std;
int main()
{
BOARD board;
board.run();
return 0;
}
#pragma once
#define ROW_NUM 9
#define COL_NUM 9
#define CLR_NUM 8
#define CONNECT_MIN 4
typedef struct _POSITION //坐标
{
int x;
int y;
}POS;
typedef struct _GENERAL
{
POS pos;
int num;
}GENERAL;
#pragma once
/* 定义颜色(用宏定义取代数字,方便记忆) */
#define COLOR_BLACK 0 //黑
#define COLOR_BLUE 1 //蓝
#define COLOR_GREEN 2 //绿
#define COLOR_CYAN 3 //青
#define COLOR_RED 4 //红
#define COLOR_PINK 5 //粉
#define COLOR_YELLOW 6 //黄
#define COLOR_WHITE 7 //白
#define COLOR_HBLACK 8 //亮黑
#define COLOR_HBLUE 9 //亮蓝
#define COLOR_HGREEN 10 //亮绿
#define COLOR_HCYAN 11 //亮青
#define COLOR_HRED 12 //亮红
#define COLOR_HPINK 13 //亮粉
#define COLOR_HYELLOW 14 //亮黄
#define COLOR_HWHITE 15 //亮白
/* 定义鼠标键盘操作类型 */
#define CCT_MOUSE_EVENT 0
#define CCT_KEYBOARD_EVENT 1
/* 定义四个方向键 */
#define KB_ARROW_UP 72
#define KB_ARROW_DOWN 80
#define KB_ARROW_LEFT 75
#define KB_ARROW_RIGHT 77
/* 定义鼠标的操作 */
#define MOUSE_NO_ACTION 0x0000 //无鼠标操作
#define MOUSE_ONLY_MOVED 0x0001 //鼠标移动
#define MOUSE_LEFT_BUTTON_CLICK 0x0002 //按下左键
#define MOUSE_LEFT_BUTTON_DOUBLE_CLICK 0x0004 //双击左键
#define MOUSE_RIGHT_BUTTON_CLICK 0x0008 //按下右键
#define MOUSE_RIGHT_BUTTON_DOUBLE_CLICK 0x0010 //双击右键
#define MOUSE_LEFTRIGHT_BUTTON_CLICK 0x0020 //同时按下左右键
#define MOUSE_WHEEL_CLICK 0x0040 //滚轮被按下
#define MOUSE_WHEEL_MOVED_UP 0x0080 //滚轮向上移动
#define MOUSE_WHEEL_MOVED_DOWN 0x0100 //滚轮向下移动
/* 定义光标的形态 */
#define CURSOR_VISIBLE_FULL 0 //光标显示,全高色块
#define CURSOR_VISIBLE_HALF 1 //光标显示,半高色块
#define CURSOR_VISIBLE_NORMAL 2 //光标显示,横线(缺省为此方式)
#define CURSOR_INVISIBLE 3 //光标不显示
/* cmd_console_tools.cpp下的函数声明 */
/* 清屏、颜色设置、光标设置、字符/字符串显示 */
void cct_cls(void);
void cct_setcolor(const int bg_color = COLOR_BLACK, const int fg_color = COLOR_WHITE);
void cct_getcolor(int& bg_color, int& fg_color);
void cct_gotoxy(const int X, const int Y);
void cct_getxy(int& x, int& y);
void cct_setcursor(const int options);
void cct_showch(const int X, const int Y, const char ch, const int bg_color = COLOR_BLACK, const int fg_color = COLOR_WHITE, const int rpt = 1);
void cct_showstr(const int X, const int Y, const char* str, const int bg_color = COLOR_BLACK, const int fg_color = COLOR_WHITE, int rpt = 1, int max_len = -1);
void cct_showint(const int X, const int Y, const int num, const int bg_color = COLOR_BLACK, const int fg_color = COLOR_WHITE, const int rpt = 1);
/* 与窗口大小有关的函数 */
void cct_setconsoleborder(int set_cols, int set_lines, int set_buffer_cols = -1, int set_buffer_lines = -1);
void cct_getconsoleborder(int& cols, int& lines, int& buffer_cols, int& buffer_lines);
/* 有标题栏有关的函数 */
void cct_getconsoletitle(char* title, int maxbuflen);
void cct_setconsoletitle(const char* title);
/* 与鼠标操作有关的函数 */
void cct_enable_mouse(void);
void cct_disable_mouse(void);
int cct_read_keyboard_and_mouse(int& MX, int& MY, int& MAction, int& keycode1, int& keycode2);
/* 与字体及字号设置有关的函数 */
int cct_getfontinfo(void);
void cct_setfontsize(const char* fontname, const int high, const int width = 0);