完善历史局面浏览和从中间重新开始

This commit is contained in:
liuweilhy 2018-08-21 23:02:19 +08:00
parent 2d7a795f97
commit bdea2253bb
6 changed files with 114 additions and 118 deletions

View File

@ -7,6 +7,8 @@
#include <QApplication>
#include <Qsound>
#include <QDebug>
#include <QMessageBox>
#include <QAbstractButton>
#include "gamecontroller.h"
#include "graphicsconst.h"
#include "boarditem.h"
@ -16,6 +18,7 @@ GameController::GameController(GameScene &scene, QObject *parent) : QObject(pare
// 是否浏览过历史纪录
scene(scene),
piece(NULL),
currentRow(-1),
isEditing(false),
isInverted(false),
isEngine1(false),
@ -70,6 +73,7 @@ const QMap<int, QStringList> GameController::getActions()
void GameController::gameStart()
{
chess.start();
chessTemp = chess;
// 每隔100毫秒调用一次定时器处理函数
if (timeID == 0) {
timeID = startTimer(100);
@ -108,6 +112,7 @@ void GameController::gameReset()
}
// 更新棋谱
manualListModel.removeRows(0, manualListModel.rowCount());
currentRow = 0;
manualListModel.insertRow(0);
manualListModel.setData(manualListModel.index(0), chess.getCmdLine());
@ -261,14 +266,22 @@ void GameController::timerEvent(QTimerEvent *event)
// 历史局面
void GameController::phaseChange(int row, bool change /*= false*/)
{
// 如果row是当前浏览的棋谱行则直接推出不刷新
if (currentRow == row)
return;
else
currentRow = row;
int rows = manualListModel.rowCount();
QStringList mlist = manualListModel.stringList();
qDebug() << "rows: " << rows;
qDebug() << "rows:" << rows << " current:" << row;
for (int i = 0; i <= row; i++)
{
qDebug() << mlist.at(i);
chessTemp.command(mlist.at(i).toStdString().c_str());
}
// 下面这步关键,让悔棋者承担时间损失
chessTemp.setStartTimeb(chess.getStartTimeb());
updateScence(chessTemp);
}
@ -277,6 +290,33 @@ void GameController::phaseChange(int row, bool change /*= false*/)
bool GameController::actionPiece(QPointF pos)
{
bool result = false;
// 是否在浏览历史记录
if (currentRow != manualListModel.rowCount() - 1)
{
// 定义新对话框
QMessageBox msgBox;
msgBox.setIcon(QMessageBox::Question);
msgBox.setMinimumSize(600, 400);
msgBox.setText(tr("当前正在浏览历史局面。"));
msgBox.setInformativeText(tr("是否在此局面下重新开始?"));
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Cancel);
(msgBox.button(QMessageBox::Ok))->setText(tr("确定"));
(msgBox.button(QMessageBox::Cancel))->setText(tr("取消"));
if (QMessageBox::Ok == msgBox.exec())
{
chess = chessTemp;
manualListModel.removeRows(currentRow + 1, manualListModel.rowCount() - currentRow - 1);
}
else
{
return result;
}
}
switch (chess.getPhase()) {
case NineChess::GAME_NOTSTARTED:
// 如果未开局则开局这里还要继续判断不可break
@ -291,8 +331,8 @@ bool GameController::actionPiece(QPointF pos)
result = removePiece(pos);
}
// 如果完成后进入中局,则删除禁点
if (chess.getPhase() == NineChess::GAME_MID && chess.getRule()->hasForbidden)
cleanForbidden();
//if (chess.getPhase() == NineChess::GAME_MID && chess.getRule()->hasForbidden)
// cleanForbidden();
break;
case NineChess::GAME_MID:
@ -319,111 +359,82 @@ bool GameController::actionPiece(QPointF pos)
if (result)
{
int row = manualListModel.rowCount();
int c = 0;
// 将新增的棋谱行插入到ListModel
currentRow = manualListModel.rowCount() - 1;
int k = 0;
// 输出命令行
for (auto i = (chess.getCmdList())->begin(); i != (chess.getCmdList())->end(); ++i) {
if (++c <= row)
// 跳过已添加的因标准list容器没有下标
if (k++ <= currentRow)
continue;
manualListModel.insertRow(c - 1);
manualListModel.setData(manualListModel.index(c - 1), (*i).c_str());
manualListModel.insertRow(++currentRow);
manualListModel.setData(manualListModel.index(currentRow), (*i).c_str());
}
if (chess.whoWin() != NineChess::NOBODY)
playSound(soundWin);
}
updateScence(this->chess);
return result;
}
// 选子
PieceItem *GameController::choosePiece(QPointF pos)
bool GameController::choosePiece(QPointF pos)
{
int c, p;
if (!scene.pos2cp(pos, c, p))
return false;
PieceItem *piece = NULL;
QGraphicsItem *item = scene.itemAt(pos, QTransform());
if (!item) {
scene.clearSelection();
this->piece->setSelected(true);
if (!scene.pos2cp(pos, c, p)) {
return false;
}
PieceItem *piece = NULL;
QGraphicsItem *item = scene.itemAt(pos, QTransform());
piece = qgraphicsitem_cast<PieceItem *>(item);
if (!piece)
if (!piece) {
return false;
}
if (chess.choose(c, p)) {
scene.clearSelection();
this->piece = piece;
this->piece->setSelected(true);
// 发信号更新状态栏
message = QString::fromStdString(chess.getTip());
emit statusBarChanged(message);
// 播放音效
playSound(soundChoose);
return piece;
return true;
}
else
{
scene.clearSelection();
if (this->piece)
this->piece->setSelected(true);
else {
return false;
}
return NULL;
}
// 落下新子
PieceItem *GameController::placePiece(QPointF pos)
bool GameController::placePiece(QPointF pos)
{
int c, p;
if (!scene.pos2cp(pos, c, p))
return NULL;
PieceItem *newP = NULL;
PieceItem::Models md;
if (chess.whosTurn() == NineChess::PLAYER1)
{
md = isInverted ? PieceItem::whitePiece : PieceItem::blackPiece;
}
else {
md = isInverted ? PieceItem::blackPiece : PieceItem::whitePiece;
if (!scene.pos2cp(pos, c, p)) {
return false;
}
if (!chess.place(c, p)) {
scene.clearSelection();
if (this->piece)
this->piece->setSelected(true);
return NULL;
return false;
}
newP = new PieceItem;
newP->setModel(md);
newP->setDeleted(false);
newP->setPos(pos);
newP->setNum(chess.getPieceNum(c, p));
// 如果重复三连不可用,则显示棋子序号
if (!(chess.getRule()->canRepeated))
newP->setShowNum(true);
pieceList.append(newP);
scene.addItem(newP);
scene.clearSelection();
this->piece = newP;
this->piece->setSelected(true);
// 发信号更新状态栏
message = QString::fromStdString(chess.getTip());
emit statusBarChanged(message);
// 播放音效
playSound(soundDrog);
return newP;
return true;
}
// 移动旧子
bool GameController::movePiece(QPointF pos)
{
if (!piece)
if (!piece) {
return false;
}
int c, p;
if (!scene.pos2cp(pos, c, p))
if (!scene.pos2cp(pos, c, p)) {
return false;
}
if (chess.place(c, p))
{
piece->setPos(pos);
// 发信号更新状态栏
message = QString::fromStdString(chess.getTip());
emit statusBarChanged(message);
@ -431,8 +442,6 @@ bool GameController::movePiece(QPointF pos)
playSound(soundMove);
return true;
}
scene.clearSelection();
this->piece->setSelected(true);
return false;
}
@ -440,42 +449,13 @@ bool GameController::movePiece(QPointF pos)
bool GameController::removePiece(QPointF pos)
{
int c, p;
if (!scene.pos2cp(pos, c, p))
if (!scene.pos2cp(pos, c, p)) {
return false;
}
if (!chess.remove(c, p)) {
scene.clearSelection();
if (this->piece)
this->piece->setSelected(true);
return false;
}
PieceItem *piece = NULL;
QGraphicsItem *item = scene.itemAt(pos, QTransform());
if (!item) {
scene.clearSelection();
if (this->piece)
this->piece->setSelected(true);
return false;
}
piece = qgraphicsitem_cast<PieceItem *>(item);
if (!piece) {
scene.clearSelection();
if (this->piece)
this->piece->setSelected(true);
return false;
}
// 如果开局阶段有禁点
if (chess.getPhase() == NineChess::GAME_OPENING && chess.getRule()->hasForbidden)
{
piece->setDeleted();
}
else
{
pieceList.removeOne(piece);
delete piece;
this->piece = NULL;
}
scene.clearSelection();
// 发信号更新状态栏
message = QString::fromStdString(chess.getTip());
emit statusBarChanged(message);
@ -484,6 +464,7 @@ bool GameController::removePiece(QPointF pos)
return true;
}
/* 下面的用不到了
bool GameController::cleanForbidden()
{
for (PieceItem *p : pieceList)
@ -495,6 +476,7 @@ bool GameController::cleanForbidden()
}
return true;
}
*/
bool GameController::updateScence(NineChess &chess)
{
@ -504,9 +486,10 @@ bool GameController::updateScence(NineChess &chess)
piece = NULL;
const char *board = chess.getBoard();
QPointF pos;
for (int i = NineChess::SEAT; i < (NineChess::SEAT)*(NineChess::RING + 1); i++) {
QPointF pos = scene.cp2pos(i / NineChess::SEAT, i % NineChess::SEAT + 1);
pos = scene.cp2pos(i / NineChess::SEAT, i % NineChess::SEAT + 1);
if (board[i] & 0x30) {
PieceItem *newP = NULL;
PieceItem::Models md;
@ -534,7 +517,13 @@ bool GameController::updateScence(NineChess &chess)
}
}
scene.clearSelection();
int ipos = chess.getCurrentPos();
if (ipos) {
pos = scene.cp2pos(ipos / NineChess::SEAT, ipos % NineChess::SEAT + 1);
piece = qgraphicsitem_cast<PieceItem *> (scene.itemAt(pos, QTransform()));
if (piece)
piece->setSelected(true);
}
return true;
}

View File

@ -77,16 +77,16 @@ protected:
// 定时器
void timerEvent(QTimerEvent * event);
// 选子
PieceItem *choosePiece(QPointF pos);
bool choosePiece(QPointF pos);
// 落下新子
PieceItem *placePiece(QPointF pos);
bool placePiece(QPointF pos);
// 移动旧子
bool movePiece(QPointF pos);
// 去子
bool removePiece(QPointF pos);
// 删除禁止点子
bool cleanForbidden();
// 更新棋局显示
//bool cleanForbidden();
// 更新棋局显示,每步后必须执行
bool updateScence(NineChess &chess);
private:
@ -96,12 +96,12 @@ private:
NineChess chessTemp;
// 棋局的场景类
GameScene &scene;
// 棋谱列表
//SizeHintListView &listView;
// 所有棋子
QList<PieceItem *> pieceList;
// 当前棋子
PieceItem *piece;
// 当前浏览的棋谱行
int currentRow;
// 玩家1手棋数、玩家2手棋数、待去棋数
int player1_InHand, player2_InHand, num_NeedRemove;
// 是否处于“编辑棋局”状态

View File

@ -290,7 +290,7 @@ bool NineChess::setData(const struct Rule *rule, int s, int t, int step, int fla
millList.clear();
// 不选中棋子
posOfSelected = 0;
currentPos = 0;
// 用时置零
player1_MS = player2_MS = 0;
@ -370,7 +370,7 @@ bool NineChess::reset()
millList.clear();
// 不选中棋子
posOfSelected = 0;
currentPos = 0;
// 用时置零
player1_MS = player2_MS = 0;
@ -467,7 +467,7 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
player_ms = update(time_p);
sprintf(cmdline, "(%1u,%1u) %02u:%02u.%03u", c, p, player_ms / 60000, player_ms / 1000, player_ms % 1000);
cmdlist.push_back(string(cmdline));
posOfSelected = pos;
currentPos = pos;
step++;
// 如果决出胜负
if (win()) {
@ -475,7 +475,7 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
return true;
}
n = addMills(posOfSelected);
n = addMills(currentPos);
// 开局阶段未成三
if (n == 0) {
// 如果双方都无未放置的棋子
@ -523,7 +523,7 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
(turn == PLAYER2 && (player2_Remain > rule.numAtLest || !rule.canFly))) {
int i;
for (i = 0; i < 4; i++) {
if (pos == moveTable[posOfSelected][i])
if (pos == moveTable[currentPos][i])
break;
}
// 不在招法表中
@ -532,14 +532,14 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
}
// 移子
player_ms = update(time_p);
sprintf(cmdline, "(%1u,%1u)->(%1u,%1u) %02u:%02u.%03u", posOfSelected / SEAT, posOfSelected % SEAT + 1,
sprintf(cmdline, "(%1u,%1u)->(%1u,%1u) %02u:%02u.%03u", currentPos / SEAT, currentPos % SEAT + 1,
c, p, player_ms / 60000, player_ms / 1000, player_ms % 1000);
cmdlist.push_back(string(cmdline));
board[pos] = board[posOfSelected];
board[posOfSelected] = '\x00';
posOfSelected = pos;
board[pos] = board[currentPos];
board[currentPos] = '\x00';
currentPos = pos;
step++;
n = addMills(posOfSelected);
n = addMills(currentPos);
// 中局阶段未成三
if (n == 0) {
@ -607,7 +607,7 @@ bool NineChess::remove(int c, int p, long time_p /* = -1*/)
player_ms = update(time_p);
sprintf(cmdline, "-(%1u,%1u) %02u:%02u.%03u", c, p, player_ms / 60000, player_ms / 1000, player_ms % 1000);
cmdlist.push_back(string(cmdline));
posOfSelected = 0;
currentPos = 0;
num_NeedRemove--;
step++;
// 去子完成
@ -699,7 +699,7 @@ bool NineChess::choose(int c, int p)
return false;
}
// 选子
posOfSelected = pos;
currentPos = pos;
// 选子完成,进入落子状态
action = ACTION_PLACE;
return true;

View File

@ -106,6 +106,8 @@ public:
const char *getBoard();
// 获取当前规则
const struct Rule *getRule() { return &rule; }
// 获取当前点
int getCurrentPos() { return currentPos; }
// 获取当前步数
int getStep() { return step; }
// 获取局面阶段标识
@ -128,6 +130,10 @@ public:
const char *getCmdLine() { return cmdline; }
// 获得棋谱
const list<string> * getCmdList() { return &cmdlist; }
// 获取开局时间
timeb getStartTimeb() { return startTimeb; }
// 重新设置开局时间
void setStartTimeb(timeb stimeb) { startTimeb = stimeb; }
// 玩家1剩余未放置子数
int getPlayer1_InHand() { return player1_InHand; }
@ -221,7 +227,7 @@ private:
*/
char board[(RING + 2)*SEAT];
// 选中的棋子在board中的位置
int posOfSelected;
int currentPos;
// 空棋盘点位,用于判断一个棋子位置是否在棋盘上
static const char inBoard[(RING + 2)*SEAT];
// 招法表每个位置有最多4种走法顺时针、逆时针、向内、向外

View File

@ -181,7 +181,7 @@ void NineChessWindow::initialize()
ui.listView->setModel(& game->manualListModel);
// 因为QListView的rowsInserted在setModel之后才能启动
// 第一次需手动初始化选中listView第一项
qDebug() << ui.listView->model();
//qDebug() << ui.listView->model();
ui.listView->setCurrentIndex(ui.listView->model()->index(0, 0));
// 初始局面、前一步、后一步、最终局面的槽
connect(ui.actionBegin_S, &QAction::triggered,
@ -444,11 +444,11 @@ void NineChessWindow::on_actionLimited_T_triggered()
game->setRule(ruleNo, stepLimited, timeLimited);
}
// 更新规则显示
ruleInfo();
// 删除对话框,子控件会一并删除
delete dialog;
// 更新规则显示
ruleInfo();
}
void NineChessWindow::on_actionLocal_L_triggered()

View File

@ -19,7 +19,8 @@ showNum(false)
// 鼠标放在棋子上时显示为伸开的手形
setCursor(Qt::OpenHandCursor);
// 只接受左键事件
setAcceptedMouseButtons(Qt::LeftButton);
//setAcceptedMouseButtons(Qt::LeftButton);
setAcceptedMouseButtons(0);
// 默认模型为没有棋子
model = noPiece;
// 棋子尺寸