之前写了棋盘绘制之类的,打算做五子棋象棋之类的,但是想起了一个更加简单的棋类游戏,井字棋,大家小时候应该都玩过把。
百度的游戏规则:
两个玩家,一个打圈(O),一个打叉(X),轮流在3乘3的格上打自己的符号,最先以横、直、斜连成一线则为胜。如果双方都下得正确无误,将得和局。这种游戏实际上是由第一位玩家所控制,第一位玩家是攻,第二位玩家是守。
需求分析
首先肯定是绘制棋盘,然后就是点击下棋功能,下一个判断是否胜利,判断是否平局。我这里写的是人人对战,人机对战的算法研究一下之后应该会做。
结果展示
具体实现步骤
1.画棋盘: 棋盘这些格子之类的绘画,就不用UI设计了,for循环的代码肯定更香啊,我这里除了画棋盘,还设置了一个开始游戏的按钮,点击按钮棋盘才可用。
void Widget:: Print(){
//设置窗体背景为白色
QPalette palette(this->palette());
palette.setColor(QPalette::Background, Qt::white);
this->setPalette(palette);
//设置九个网格图片
int x = 0, y = 0, w = 180, h = 180;
for(int i = 0; i < 3; ++ i){
for(int j = 0; j < 3; ++ j){
QPushButton *button = new QPushButton(this);
gridButton.push_back(button);
//坐标
x = j * 180 + 30, y = i * 180 + 30;
button->setGeometry(x, y, w, h); //设置按钮位置和大小
button->setStyleSheet("border-image:url(:/img/grid.png);"); //设置按钮图片
connect(button, SIGNAL(clicked(bool)), this, SLOT(ButtonClick()));//为每个按钮添加响应函数
}
}
qDebug()<<gridButton.size();
for(int k=0;k<gridButton.size();k++){
gridButton[k]->setEnabled(false);
}
QPushButton *play = new QPushButton(this);
play->setGeometry(640, 225, 200, 100); //设置按钮位置和大小
play->setText("开始游戏");
connect(play, SIGNAL(clicked(bool)), this, SLOT(gameAction()));
}
2.人下棋函数的设计,就是点击该处按钮,读取后进行图片的替换,然后设置为不可用,用一个flag判断玩家是谁,我这里1是玩家1,下了之后就变成玩家2.
int Widget::HumanChess1(QPushButton *button)
{
int i = button->pos().x() / 180;
int j = (button->pos().y() - 30) / 180;
chess[j][i] = 1; //人类在点(i, j)下了一个子
button->setStyleSheet("border-image: url(:/img/circle.png);");
button->setEnabled(false); //只能下一次
cur_player = 2;
return 2; //下棋成功
}
int Widget::HumanChess2(QPushButton *button)
{
int i = button->pos().x() / 180;
int j = (button->pos().y() - 30) / 180;
chess[j][i] = -1; //人类在点(i, j)下了一个子
button->setStyleSheet("border-image: url(:/img/fork.png);");
button->setEnabled(false); //只能下一次
cur_player = 1;
return 1; //下棋成功
}
3. 判断游戏的输赢和是否和棋,你每下一布棋就进行判断,输赢 是根据和进行判断的,玩家1下的点每个赋值为1,判断水平,列和斜的和,为3即1胜利,2下的是-1,和棋是判断是否每个地方都已经下了棋(可以优化)。
int Widget::GetWinPeople() //判断输赢
{
int sum = 0;
for(int i = 0; i < 3; ++ i){//水平方向
sum = chess[i][0] +chess[i][1] + chess[i][2];
if( sum == 3) return 1;
else if(sum == -3) return -1;
}
for(int i = 0; i < 3; ++ i){//垂直方向
sum = chess[0][i] + chess[1][i] + chess[2][i];
if(sum == 3) return 1;
else if(sum == -3) return -1;
}
int psum = chess[0][0] + chess[1][1] + chess[2][2];//正对角线
int csum = chess[2][0] + chess[1][1] + chess[0][2];//副对角线
if(psum == 3 || csum == 3) return 1;
else if(psum == -3 || csum == -3) return -1;
return 0; //未决胜负
}
bool Widget::Tie() //平局
{
int cnt = 0; //有多少个格子走过
for(int i = 0; i < 3; ++ i){
for(int j = 0; j < 3; ++ j){
if(chess[i][j] != 0){
++cnt;
}
}
}
if(cnt == 9){ //9个格子都走过
QMessageBox::information(this, tr("井字棋"), tr("平局"), QMessageBox::Ok);
GameOver(); //游戏结束
return true;
}
return false;
}
游戏结束,棋盘重制
void Widget::GameOver() //游戏结束
{
for(int i = 0; i < 9; ++ i){
gridButton[i]->setStyleSheet("border-image: url(:/img/grid.png);");
gridButton[i]->setEnabled(true);
}
//棋盘重置
for(int i = 0; i < 3; ++ i){
for(int j = 0; j < 3; ++ j){
chess[i][j] = 0;
}
}
for(int k=0;k<gridButton.size();k++){
gridButton[k]->setEnabled(false);
}
}
很简单的井字棋游戏,希望对大家有所帮助,后续研究一下算法,会出人机对战,然后就是五子棋,象棋,之后会通过TCP或者其他方式进行联机。