qt: Change comments to English
This commit is contained in:
parent
f5c4a5f7d9
commit
ca495f1f49
|
@ -26,13 +26,13 @@ BoardItem::BoardItem(QGraphicsItem *parent) :
|
|||
{
|
||||
Q_UNUSED(parent)
|
||||
|
||||
// 棋盘中心放在场景中心
|
||||
// The center of the board is in the center of the scene
|
||||
setPos(0, 0);
|
||||
|
||||
// 初始化24个落子点
|
||||
// Initialize 24 drop points
|
||||
for (int r = 0; r < FILE_NB; r++) {
|
||||
// 内圈的12点钟方向为第一个位置,按顺时针方向排序
|
||||
// 然后是中圈和外圈
|
||||
// The first position is the 12 o'clock direction of the inner ring, which is sorted clockwise
|
||||
// Then there is the middle ring and the outer ring
|
||||
int a = (r + 1) * LINE_INTERVAL;
|
||||
|
||||
position[r * RANK_NB + 0].rx() = 0;
|
||||
|
@ -89,14 +89,14 @@ void BoardItem::paint(QPainter *painter,
|
|||
Q_UNUSED(option)
|
||||
Q_UNUSED(widget)
|
||||
|
||||
// 填充阴影
|
||||
// Fill shadow
|
||||
#ifndef MOBILE_APP_UI
|
||||
QColor shadowColor(128, 42, 42);
|
||||
shadowColor.setAlphaF(0.3);
|
||||
painter->fillRect(boundingRect(), QBrush(shadowColor));
|
||||
#endif /* ! MOBILE_APP_UI */
|
||||
|
||||
// 填充图片
|
||||
// Fill in picture
|
||||
#ifdef MOBILE_APP_UI
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(QColor(239, 239, 239));
|
||||
|
@ -106,7 +106,7 @@ void BoardItem::paint(QPainter *painter,
|
|||
QPixmap(":/image/resources/image/board.png"));
|
||||
#endif /* MOBILE_APP_UI */
|
||||
|
||||
// 实线画笔
|
||||
// Solid line brush
|
||||
#ifdef MOBILE_APP_UI
|
||||
QPen pen(QBrush(QColor(241, 156, 159)), LINE_WEIGHT, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin);
|
||||
#else
|
||||
|
@ -114,28 +114,28 @@ void BoardItem::paint(QPainter *painter,
|
|||
#endif
|
||||
painter->setPen(pen);
|
||||
|
||||
// 空画刷
|
||||
// No brush
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
|
||||
for (uint8_t i = 0; i < FILE_NB; i++) {
|
||||
// 画3个方框
|
||||
// Draw three boxes
|
||||
painter->drawPolygon(position + i * RANK_NB, RANK_NB);
|
||||
}
|
||||
|
||||
// 画4条纵横线
|
||||
// Draw 4 vertical and horizontal lines
|
||||
for (int i = 0; i < RANK_NB; i += 2) {
|
||||
painter->drawLine(position[i], position[(FILE_NB - 1) * RANK_NB + i]);
|
||||
}
|
||||
|
||||
if (hasObliqueLine) {
|
||||
// 画4条斜线
|
||||
// Draw 4 diagonal lines
|
||||
for (int i = 1; i < RANK_NB; i += 2) {
|
||||
painter->drawLine(position[i], position[(FILE_NB - 1) * RANK_NB + i]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PLAYER_DRAW_SEAT_NUMBER
|
||||
// 画 Seat 编号
|
||||
// Draw the seat number
|
||||
QPen fontPen(QBrush(Qt::white), LINE_WEIGHT, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin);
|
||||
painter->setPen(fontPen);
|
||||
QFont font;
|
||||
|
@ -154,12 +154,12 @@ void BoardItem::paint(QPainter *painter,
|
|||
|
||||
QPointF BoardItem::nearestPosition(QPointF const pos)
|
||||
{
|
||||
// 初始最近点设为(0,0)点
|
||||
// The initial closest point is set to (0,0) point
|
||||
QPointF nearestPos = QPointF(0, 0);
|
||||
|
||||
// 寻找最近的落子点
|
||||
// Look for the nearest spot
|
||||
for (auto i : position) {
|
||||
// 如果鼠标点距离落子点在棋子半径内
|
||||
// If the distance between the mouse point and the falling point is within the radius of the chess piece
|
||||
if (QLineF(pos, i).length() < PIECE_SIZE / 2) {
|
||||
nearestPos = i;
|
||||
break;
|
||||
|
@ -171,14 +171,14 @@ QPointF BoardItem::nearestPosition(QPointF const pos)
|
|||
|
||||
QPointF BoardItem::polar2pos(File file, Rank rank)
|
||||
{
|
||||
return position[((int)file - 1) * RANK_NB + (int)rank - 1]; // TODO: 为什么是 r - 1 和算法部分不一样?
|
||||
return position[((int)file - 1) * RANK_NB + (int)rank - 1];
|
||||
}
|
||||
|
||||
bool BoardItem::pos2polar(QPointF pos, File &file, Rank &rank)
|
||||
{
|
||||
// 寻找最近的落子点
|
||||
// Look for the nearest spot
|
||||
for (int i = 0; i < EFFECTIVE_SQUARE_NB; i++) {
|
||||
// 如果pos点在落子点附近
|
||||
// If the pos point is near the falling point
|
||||
if (QLineF(pos, position[i]).length() < PIECE_SIZE / 6) {
|
||||
file = File(i / RANK_NB + 1);
|
||||
rank = Rank(i % RANK_NB + 1);
|
||||
|
|
|
@ -37,8 +37,8 @@ public:
|
|||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||
QWidget *widget = nullptr) override;
|
||||
|
||||
// 用UserType+1表示棋子,用qgraphicsitem_cast()判断是否为BoardItem类的对象
|
||||
// 还有一个方式是把类名放在Data的0key位置setData(0, "BoardItem"),然后用data(0)来判断
|
||||
// Use UserType + 1 to represent chess pieces, and use qgraphicsitem_cast() determines whether it is an object of the boarditem class
|
||||
// Another way is to put the class name in the 0key position of data, SetData(0, "BoardItem"), and then use data(0) to judge
|
||||
enum
|
||||
{
|
||||
Type = UserType + 1
|
||||
|
@ -49,35 +49,26 @@ public:
|
|||
return Type;
|
||||
}
|
||||
|
||||
// 设置有无斜线
|
||||
//Set with or without slash
|
||||
void setDiagonal(bool arg = true);
|
||||
|
||||
// 返回最近的落子点
|
||||
//Return to the nearest drop point
|
||||
QPointF nearestPosition(QPointF pos);
|
||||
|
||||
// 将模型的圈、位转化为落子点坐标
|
||||
// The circle and position of the model are transformed into the point coordinates
|
||||
QPointF polar2pos(File file, Rank rank);
|
||||
|
||||
// 将落子点坐标转化为模型用的圈、位
|
||||
// The coordinates of the falling point are transformed into circles and positions for the model
|
||||
bool pos2polar(QPointF pos, File &file, Rank &rank);
|
||||
|
||||
// 3圈,禁止修改!
|
||||
static const uint8_t FILE_NB = 3;
|
||||
|
||||
// 8位,禁止修改!
|
||||
static const uint8_t RANK_NB = 8;
|
||||
|
||||
private:
|
||||
// 棋盘尺寸
|
||||
int size;
|
||||
|
||||
// 影子尺寸
|
||||
int size; // board size
|
||||
int sizeShadow {5};
|
||||
|
||||
// 24个落子点
|
||||
QPointF position[EFFECTIVE_SQUARE_NB];
|
||||
|
||||
// 是否有斜线
|
||||
QPointF position[EFFECTIVE_SQUARE_NB]; // 24 points
|
||||
bool hasObliqueLine {false};
|
||||
};
|
||||
|
||||
|
|
|
@ -62,8 +62,9 @@ Game::Game(
|
|||
timeLimit(0),
|
||||
stepsLimit(50)
|
||||
{
|
||||
// 已在view的样式表中添加背景,scene中不用添加背景
|
||||
// 区别在于,view中的背景不随视图变换而变换,scene中的背景随视图变换而变换
|
||||
// The background has been added to the style sheet of view, but not to scene
|
||||
// The difference is that the background in view does not change with the view transformation,
|
||||
// and the background in scene changes with the view transformation
|
||||
//scene.setBackgroundBrush(QPixmap(":/image/resources/image/background.png"));
|
||||
#ifdef MOBILE_APP_UI
|
||||
scene.setBackgroundBrush(QColor(239, 239, 239));
|
||||
|
@ -79,7 +80,7 @@ Game::Game(
|
|||
qRegisterMetaType<std::string>("string");
|
||||
|
||||
#ifdef QT_GUI_LIB
|
||||
// 关联AI和控制器的着法命令行
|
||||
// The command line of AI and controller
|
||||
connect(aiThread[BLACK], SIGNAL(command(const string &, bool)),
|
||||
this, SLOT(command(const string &, bool)));
|
||||
connect(aiThread[WHITE], SIGNAL(command(const string &, bool)),
|
||||
|
@ -94,7 +95,7 @@ Game::Game(
|
|||
uint16_t clientPort = server->getPort() == 30001 ? 30002 : 30001;
|
||||
client = new Client(nullptr, clientPort);
|
||||
|
||||
// 关联AI和网络类的着法命令行
|
||||
// The command line of AI andnetwork
|
||||
connect(getClient(), SIGNAL(command(const string &, bool)),
|
||||
this, SLOT(command(const string &, bool)));
|
||||
#endif // NET_FIGHT_SUPPORT
|
||||
|
@ -106,19 +107,13 @@ Game::Game(
|
|||
#endif
|
||||
|
||||
moveHistory.reserve(256);
|
||||
|
||||
// 安装事件过滤器监视scene的各个事件,
|
||||
// 由于我重载了QGraphicsScene,相关事件在重载函数中已设定,不必安装监视器。
|
||||
//scene.installEventFilter(this);
|
||||
}
|
||||
|
||||
Game::~Game()
|
||||
{
|
||||
// 停止计时器
|
||||
if (timeID != 0)
|
||||
killTimer(timeID);
|
||||
|
||||
// 停掉线程
|
||||
pauseAndWaitThreads();
|
||||
deleteAiThreads();
|
||||
|
||||
|
@ -133,12 +128,13 @@ Game::~Game()
|
|||
|
||||
const map<int, QStringList> Game::getActions()
|
||||
{
|
||||
// 主窗口更新菜单栏
|
||||
// 之所以不用信号和槽的模式,是因为发信号的时候槽还来不及关联
|
||||
// Main window update menu bar
|
||||
// The reason why we don't use the mode of signal and slot is that
|
||||
// it's too late for the slot to be associated when the signal is sent
|
||||
map<int, QStringList> actions;
|
||||
|
||||
for (int i = 0; i < N_RULES; i++) {
|
||||
// map的key存放int索引值,value存放规则名称和规则提示
|
||||
//The key of map stores int index value, and value stores rule name and rule prompt
|
||||
QStringList strlist;
|
||||
strlist.append(tr(RULES[i].name));
|
||||
strlist.append(tr(RULES[i].description));
|
||||
|
@ -159,7 +155,7 @@ void Game::gameStart()
|
|||
position.start();
|
||||
startTime = time(nullptr);
|
||||
|
||||
// 每隔100毫秒调用一次定时器处理函数
|
||||
// The timer handler is called every 100 milliseconds
|
||||
if (timeID == 0) {
|
||||
timeID = startTimer(100);
|
||||
}
|
||||
|
@ -184,14 +180,12 @@ void Game::gameReset()
|
|||
|
||||
loggerDebug("\n");
|
||||
|
||||
// 停止计时器
|
||||
if (timeID != 0)
|
||||
killTimer(timeID);
|
||||
|
||||
// 定时器ID为0
|
||||
timeID = 0;
|
||||
|
||||
// 重置游戏
|
||||
// Reset game
|
||||
// WAR
|
||||
if (moveHistory.size() > 1) {
|
||||
string bak = moveHistory[0];
|
||||
|
@ -203,28 +197,28 @@ void Game::gameReset()
|
|||
elapsedSeconds[BLACK] = elapsedSeconds[WHITE] = 0;
|
||||
sideToMove = position.side_to_move();
|
||||
|
||||
// 停掉线程
|
||||
// Stop threads
|
||||
if (!gameOptions.getAutoRestart()) {
|
||||
pauseThreads();
|
||||
resetAiPlayers();
|
||||
}
|
||||
|
||||
// 清除棋子
|
||||
// Clear pieces
|
||||
qDeleteAll(pieceList);
|
||||
pieceList.clear();
|
||||
currentPiece = nullptr;
|
||||
|
||||
// 重新绘制棋盘
|
||||
// Redraw pieces
|
||||
scene.setDiagonal(rule.hasObliqueLines);
|
||||
|
||||
// 绘制所有棋子,放在起始位置
|
||||
// 0: 先手第1子; 1:后手第1子
|
||||
// 2:先手第2子; 3:后手第2子
|
||||
// Draw all the pieces and put them in the starting position
|
||||
// 0: the first piece in the first hand; 1: the first piece in the second hand
|
||||
// 2: the first second piece; 3: the second piece
|
||||
// ......
|
||||
PieceItem::Models md;
|
||||
|
||||
for (int i = 0; i < rule.piecesCount; i++) {
|
||||
// 先手的棋子
|
||||
// The first piece
|
||||
md = isInverted ? PieceItem::Models::whitePiece : PieceItem::Models::blackPiece;
|
||||
PieceItem *newP = new PieceItem;
|
||||
newP->setModel(md);
|
||||
|
@ -235,7 +229,7 @@ void Game::gameReset()
|
|||
pieceList.push_back(newP);
|
||||
scene.addItem(newP);
|
||||
|
||||
// 后手的棋子
|
||||
// Backhand piece
|
||||
md = isInverted ? PieceItem::Models::blackPiece : PieceItem::Models::whitePiece;
|
||||
newP = new PieceItem;
|
||||
newP->setModel(md);
|
||||
|
@ -247,41 +241,41 @@ void Game::gameReset()
|
|||
scene.addItem(newP);
|
||||
}
|
||||
|
||||
// 读取规则限时要求
|
||||
// Read rule time limit requirement
|
||||
timeLimit = 0; // TODO: rule.maxTimeLedToLose;
|
||||
|
||||
// 如果规则不要求计时,则time1和time2表示已用时间
|
||||
// If the rule does not require timing, time1 and time2 represent the time used
|
||||
if (timeLimit <= 0) {
|
||||
// 将玩家的已用时间清零
|
||||
// Clear the player's used time
|
||||
remainingTime[BLACK] = remainingTime[WHITE] = 0;
|
||||
} else {
|
||||
// 将玩家的剩余时间置为限定时间
|
||||
// Set the player's remaining time to a limited time
|
||||
remainingTime[BLACK] = remainingTime[WHITE] = timeLimit * 60;
|
||||
}
|
||||
|
||||
// 更新棋谱
|
||||
// Update move history
|
||||
manualListModel.removeRows(0, manualListModel.rowCount());
|
||||
manualListModel.insertRow(0);
|
||||
manualListModel.setData(manualListModel.index(0), position.get_record());
|
||||
currentRow = 0;
|
||||
|
||||
// 发出信号通知主窗口更新LCD显示
|
||||
// Signal the main window to update the LCD display
|
||||
const QTime qtime = QTime(0, 0, 0, 0).addSecs(static_cast<int>(remainingTime[BLACK]));
|
||||
emit time1Changed(qtime.toString("hh:mm:ss"));
|
||||
emit time2Changed(qtime.toString("hh:mm:ss"));
|
||||
|
||||
// 发信号更新状态栏
|
||||
// Signal update status bar
|
||||
updateScence();
|
||||
message = QString::fromStdString(getTips());
|
||||
emit statusBarChanged(message);
|
||||
|
||||
// 更新比分 LCD 显示
|
||||
// Update LCD display
|
||||
emit nGamesPlayedChanged(QString::number(position.gamesPlayedCount, 10));
|
||||
emit score1Changed(QString::number(position.score[BLACK], 10));
|
||||
emit score2Changed(QString::number(position.score[WHITE], 10));
|
||||
emit scoreDrawChanged(QString::number(position.score_draw, 10));
|
||||
|
||||
// 更新胜率 LCD 显示
|
||||
// Update winning rate LCD display
|
||||
position.gamesPlayedCount = position.score[BLACK] + position.score[WHITE] + position.score_draw;
|
||||
int winningRate_1 = 0, winningRate_2 = 0, winningRate_draw = 0;
|
||||
if (position.gamesPlayedCount != 0) {
|
||||
|
@ -294,7 +288,7 @@ void Game::gameReset()
|
|||
emit winningRate2Changed(QString::number(winningRate_2, 10));
|
||||
emit winningRateDrawChanged(QString::number(winningRate_draw, 10));
|
||||
|
||||
// 播放音效
|
||||
// Sound effects play
|
||||
//playSound(":/sound/resources/sound/newgame.wav");
|
||||
}
|
||||
|
||||
|
@ -307,18 +301,18 @@ void Game::setInvert(bool arg)
|
|||
{
|
||||
isInverted = arg;
|
||||
|
||||
// 遍历所有棋子
|
||||
// For all pieces
|
||||
for (PieceItem *pieceItem : pieceList) {
|
||||
if (pieceItem) {
|
||||
// 黑子变白
|
||||
// Black -> White
|
||||
if (pieceItem->getModel() == PieceItem::Models::blackPiece)
|
||||
pieceItem->setModel(PieceItem::Models::whitePiece);
|
||||
|
||||
// 白子变黑
|
||||
// White -> Black
|
||||
else if (pieceItem->getModel() == PieceItem::Models::whitePiece)
|
||||
pieceItem->setModel(PieceItem::Models::blackPiece);
|
||||
|
||||
// 刷新棋子显示
|
||||
// Refresh checkerboard display
|
||||
pieceItem->update();
|
||||
}
|
||||
}
|
||||
|
@ -326,7 +320,7 @@ void Game::setInvert(bool arg)
|
|||
|
||||
void Game::setRule(int ruleNo, int stepLimited /*= -1*/, int timeLimited /*= -1*/)
|
||||
{
|
||||
// 更新规则,原限时和限步不变
|
||||
// Update the rule, the original time limit and step limit remain unchanged
|
||||
if (ruleNo < 0 || ruleNo >= N_RULES)
|
||||
return;
|
||||
this->ruleIndex = ruleNo;
|
||||
|
@ -336,7 +330,7 @@ void Game::setRule(int ruleNo, int stepLimited /*= -1*/, int timeLimited /*= -1*
|
|||
timeLimit = timeLimited;
|
||||
}
|
||||
|
||||
// 设置模型规则,重置游戏
|
||||
// Set model rules, reset game
|
||||
if (set_rule(ruleNo) == false) {
|
||||
return;
|
||||
}
|
||||
|
@ -352,7 +346,7 @@ void Game::setRule(int ruleNo, int stepLimited /*= -1*/, int timeLimited /*= -1*
|
|||
moveHistory.clear();
|
||||
moveHistory.emplace_back(cmd);
|
||||
|
||||
// 重置游戏
|
||||
// Reset game
|
||||
gameReset();
|
||||
}
|
||||
|
||||
|
@ -399,7 +393,7 @@ void Game::setAnimation(bool arg) noexcept
|
|||
{
|
||||
hasAnimation = arg;
|
||||
|
||||
// 默认动画时间500ms
|
||||
// The default animation time is 500ms
|
||||
if (hasAnimation)
|
||||
durationTime = 500;
|
||||
else
|
||||
|
@ -561,7 +555,6 @@ void Game::setOpeningBook(bool enabled)
|
|||
gameOptions.setOpeningBook(enabled);
|
||||
}
|
||||
|
||||
// 上下翻转
|
||||
void Game::flip()
|
||||
{
|
||||
stopAndWaitAiThreads();
|
||||
|
@ -569,13 +562,13 @@ void Game::flip()
|
|||
position.mirror(moveHistory);
|
||||
position.rotate(moveHistory, 180);
|
||||
|
||||
// 更新棋谱
|
||||
// Update move history
|
||||
int row = 0;
|
||||
for (const auto &str : *(move_hostory())) {
|
||||
manualListModel.setData(manualListModel.index(row++), str.c_str());
|
||||
}
|
||||
|
||||
// 刷新显示
|
||||
// Refresh display
|
||||
if (currentRow == row - 1)
|
||||
updateScence();
|
||||
else
|
||||
|
@ -585,14 +578,13 @@ void Game::flip()
|
|||
startAiThreads();
|
||||
}
|
||||
|
||||
// 左右镜像
|
||||
void Game::mirror()
|
||||
{
|
||||
stopAndWaitAiThreads();
|
||||
|
||||
position.mirror(moveHistory);
|
||||
|
||||
// 更新棋谱
|
||||
// Update move history
|
||||
int row = 0;
|
||||
|
||||
for (const auto &str : *(move_hostory())) {
|
||||
|
@ -601,7 +593,7 @@ void Game::mirror()
|
|||
|
||||
loggerDebug("list: %d\n", row);
|
||||
|
||||
// 刷新显示
|
||||
// Update display
|
||||
if (currentRow == row - 1)
|
||||
updateScence();
|
||||
else
|
||||
|
@ -611,21 +603,20 @@ void Game::mirror()
|
|||
startAiThreads();
|
||||
}
|
||||
|
||||
// 视图须时针旋转90°
|
||||
void Game::turnRight()
|
||||
{
|
||||
stopAndWaitAiThreads();
|
||||
|
||||
position.rotate(moveHistory, -90);
|
||||
|
||||
// 更新棋谱
|
||||
// Update move history
|
||||
int row = 0;
|
||||
|
||||
for (const auto &str : *(move_hostory())) {
|
||||
manualListModel.setData(manualListModel.index(row++), str.c_str());
|
||||
}
|
||||
|
||||
// 刷新显示
|
||||
// Update display
|
||||
if (currentRow == row - 1)
|
||||
updateScence();
|
||||
else
|
||||
|
@ -635,20 +626,19 @@ void Game::turnRight()
|
|||
startAiThreads();
|
||||
}
|
||||
|
||||
// 视图逆时针旋转90°
|
||||
void Game::turnLeft()
|
||||
{
|
||||
stopAndWaitAiThreads();
|
||||
|
||||
position.rotate(moveHistory, 90);
|
||||
|
||||
// 更新棋谱
|
||||
// Update move history
|
||||
int row = 0;
|
||||
for (const auto &str : *(move_hostory())) {
|
||||
manualListModel.setData(manualListModel.index(row++), str.c_str());
|
||||
}
|
||||
|
||||
// 刷新显示
|
||||
// Update display
|
||||
updateScence();
|
||||
|
||||
threadsSetAi(&position);
|
||||
|
@ -680,14 +670,14 @@ void Game::timerEvent(QTimerEvent *event)
|
|||
Q_UNUSED(event)
|
||||
static QTime qt1, qt2;
|
||||
|
||||
// 玩家的已用时间
|
||||
// Player's time spent
|
||||
updateTime();
|
||||
remainingTime[BLACK] = get_elapsed_time(BLACK);
|
||||
remainingTime[WHITE] = get_elapsed_time(WHITE);
|
||||
|
||||
// 如果规则要求计时,则time1和time2表示倒计时
|
||||
// If the rule requires a timer, time1 and time2 indicate a countdown
|
||||
if (timeLimit > 0) {
|
||||
// 玩家的剩余时间
|
||||
// Player's remaining time
|
||||
remainingTime[BLACK] = timeLimit * 60 - remainingTime[BLACK];
|
||||
remainingTime[WHITE] = timeLimit * 60 - remainingTime[WHITE];
|
||||
}
|
||||
|
@ -698,46 +688,44 @@ void Game::timerEvent(QTimerEvent *event)
|
|||
emit time1Changed(qt1.toString("hh:mm:ss"));
|
||||
emit time2Changed(qt2.toString("hh:mm:ss"));
|
||||
|
||||
// 如果胜负已分
|
||||
// If it's divided
|
||||
const Color winner = position.get_winner();
|
||||
if (winner != NOBODY) {
|
||||
// 停止计时
|
||||
// Stop the clock
|
||||
killTimer(timeID);
|
||||
|
||||
// 定时器ID为0
|
||||
// Timer ID is 0
|
||||
timeID = 0;
|
||||
|
||||
// 发信号更新状态栏
|
||||
// Signal update status bar
|
||||
updateScence();
|
||||
message = QString::fromStdString(getTips());
|
||||
emit statusBarChanged(message);
|
||||
|
||||
// 弹框
|
||||
//QMessageBox::about(NULL, "游戏结果", message);
|
||||
|
||||
// 播放音效
|
||||
#ifndef DONOT_PLAY_WIN_SOUND
|
||||
playSound(GameSound::win, winner);
|
||||
#endif
|
||||
}
|
||||
|
||||
// 测试用代码
|
||||
// For debugging
|
||||
#if 0
|
||||
int ti = time.elapsed();
|
||||
static QTime t;
|
||||
if (ti < 0)
|
||||
ti += 86400; // 防止过24:00引起的时间误差,加上一天中总秒数
|
||||
ti += 86400; // Prevent the time error caused by 24:00, plus the total number of seconds in a day
|
||||
if (timeWhos == 1)
|
||||
{
|
||||
time1 = ti - time2;
|
||||
// 用于显示时间的临时变量,多出的50毫秒用于消除计时器误差产生的跳动
|
||||
// A temporary variable used to display the time. The extra 50 ms is used to eliminate the beat caused by the timer error
|
||||
t = QTime(0, 0, 0, 50).addMSecs(time1);
|
||||
emit time1Changed(t.toString("hh:mm:ss"));
|
||||
}
|
||||
else if (timeWhos == 2)
|
||||
{
|
||||
time2 = ti - time1;
|
||||
// 用于显示时间的临时变量,多出的50毫秒用于消除计时器误差产生的跳动
|
||||
// A temporary variable used to display the time. The extra 50 ms is used to eliminate the beat caused by the timer error
|
||||
t = QTime(0, 0, 0, 50).addMSecs(time2);
|
||||
emit time2Changed(t.toString("hh:mm:ss"));
|
||||
}
|
||||
|
@ -749,10 +737,10 @@ bool Game::isAIsTurn()
|
|||
return isAiPlayer[sideToMove];
|
||||
}
|
||||
|
||||
// 关键槽函数,根据QGraphicsScene的信号和状态来执行选子、落子或去子
|
||||
// Key slot function, according to the signal and state of qgraphics scene to select, drop or remove sub
|
||||
bool Game::actionPiece(QPointF p)
|
||||
{
|
||||
// 点击非落子点,不执行
|
||||
// Click non drop point, do not execute
|
||||
File f;
|
||||
Rank r;
|
||||
|
||||
|
@ -760,17 +748,17 @@ bool Game::actionPiece(QPointF p)
|
|||
return false;
|
||||
}
|
||||
|
||||
// 电脑走棋或正在搜索时,点击无效
|
||||
// When the computer is playing chess or searching, the click is invalid
|
||||
if (isAIsTurn() ||
|
||||
aiThread[BLACK]->searching ||
|
||||
aiThread[WHITE]->searching) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 在浏览历史记录时点击棋盘,则认为是悔棋
|
||||
// When you click the chessboard while browsing the history, it is considered repentance
|
||||
if (currentRow != manualListModel.rowCount() - 1) {
|
||||
#ifndef MOBILE_APP_UI
|
||||
// 定义新对话框
|
||||
// Define new dialog box
|
||||
QMessageBox msgBox;
|
||||
msgBox.setIcon(QMessageBox::Question);
|
||||
msgBox.setMinimumSize(600, 400);
|
||||
|
@ -791,13 +779,13 @@ bool Game::actionPiece(QPointF p)
|
|||
moveHistory.pop_back();
|
||||
}
|
||||
|
||||
// 如果再决出胜负后悔棋,则重新启动计时
|
||||
// If you regret the game, restart the timing
|
||||
if (position.get_winner() == NOBODY) {
|
||||
|
||||
// 重新启动计时
|
||||
// Restart timing
|
||||
timeID = startTimer(100);
|
||||
|
||||
// 发信号更新状态栏
|
||||
// Signal update status bar
|
||||
updateScence();
|
||||
message = QString::fromStdString(getTips());
|
||||
emit statusBarChanged(message);
|
||||
|
@ -809,11 +797,11 @@ bool Game::actionPiece(QPointF p)
|
|||
}
|
||||
}
|
||||
|
||||
// 如果未开局则开局
|
||||
// If not, start
|
||||
if (position.get_phase() == Phase::ready)
|
||||
gameStart();
|
||||
|
||||
// 判断执行选子、落子或去子
|
||||
// Judge whether to select, drop or remove the seed
|
||||
bool result = false;
|
||||
PieceItem *piece = nullptr;
|
||||
QGraphicsItem *item = scene.itemAt(p, QTransform());
|
||||
|
@ -822,17 +810,17 @@ bool Game::actionPiece(QPointF p)
|
|||
case Action::place:
|
||||
if (position.put_piece(f, r)) {
|
||||
if (position.get_action() == Action::remove) {
|
||||
// 播放成三音效
|
||||
// Play form mill sound effects
|
||||
playSound(GameSound::mill, position.side_to_move());
|
||||
} else {
|
||||
// 播放移动棋子音效
|
||||
// Playing the sound effect of moving chess pieces
|
||||
playSound(GameSound::drog, position.side_to_move());
|
||||
}
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// 如果移子不成功,尝试重新选子,这里不break
|
||||
// If the moving is not successful, try to reselect. There is no break here
|
||||
[[fallthrough]];
|
||||
|
||||
case Action::select:
|
||||
|
@ -840,53 +828,49 @@ bool Game::actionPiece(QPointF p)
|
|||
if (!piece)
|
||||
break;
|
||||
if (position.select_piece(f, r)) {
|
||||
// 播放选子音效
|
||||
playSound(GameSound::select, position.side_to_move());
|
||||
result = true;
|
||||
} else {
|
||||
// 播放禁止音效
|
||||
playSound(GameSound::banned, position.side_to_move());
|
||||
}
|
||||
break;
|
||||
|
||||
case Action::remove:
|
||||
if (position.remove_piece(f, r)) {
|
||||
// 播放音效
|
||||
playSound(GameSound::remove, position.side_to_move());
|
||||
result = true;
|
||||
} else {
|
||||
// 播放禁止音效
|
||||
playSound(GameSound::banned, position.side_to_move());
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// 如果是结局状态,不做任何响应
|
||||
// If it is game over state, no response will be made
|
||||
break;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
moveHistory.emplace_back(position.record);
|
||||
|
||||
// 发信号更新状态栏
|
||||
// Signal update status bar
|
||||
updateScence();
|
||||
message = QString::fromStdString(getTips());
|
||||
emit statusBarChanged(message);
|
||||
|
||||
// 将新增的棋谱行插入到ListModel
|
||||
// Insert the new chess score line into listmodel
|
||||
currentRow = manualListModel.rowCount() - 1;
|
||||
int k = 0;
|
||||
|
||||
// 输出命令行
|
||||
// Output command line
|
||||
for (const auto & i : *(move_hostory())) {
|
||||
// 跳过已添加的,因标准list容器没有下标
|
||||
// Skip added because the standard list container has no subscripts
|
||||
if (k++ <= currentRow)
|
||||
continue;
|
||||
manualListModel.insertRow(++currentRow);
|
||||
manualListModel.setData(manualListModel.index(currentRow), i.c_str());
|
||||
}
|
||||
|
||||
// 播放胜利或失败音效
|
||||
// Play win or lose sound
|
||||
#ifndef DONOT_PLAY_WIN_SOUND
|
||||
const Color winner = position.get_winner();
|
||||
if (winner != NOBODY &&
|
||||
|
@ -894,12 +878,12 @@ bool Game::actionPiece(QPointF p)
|
|||
playSound(GameSound::win, winner);
|
||||
#endif
|
||||
|
||||
// AI设置
|
||||
// 如果还未决出胜负
|
||||
// AI settings
|
||||
// If it's not decided yet
|
||||
if (position.get_winner() == NOBODY) {
|
||||
resumeAiThreads(position.sideToMove);
|
||||
}
|
||||
// 如果已经决出胜负
|
||||
// If it's decided
|
||||
else {
|
||||
pauseThreads();
|
||||
}
|
||||
|
@ -919,13 +903,13 @@ bool Game::resign()
|
|||
return false;
|
||||
}
|
||||
|
||||
// 将新增的棋谱行插入到ListModel
|
||||
// Insert the new record line into listmodel
|
||||
currentRow = manualListModel.rowCount() - 1;
|
||||
int k = 0;
|
||||
|
||||
// 输出命令行
|
||||
// Output command line
|
||||
for (const auto & i : *(move_hostory())) {
|
||||
// 跳过已添加的,因标准list容器没有下标
|
||||
// Skip added because the standard list container has no index
|
||||
if (k++ <= currentRow)
|
||||
continue;
|
||||
manualListModel.insertRow(++currentRow);
|
||||
|
@ -939,7 +923,7 @@ bool Game::resign()
|
|||
return result;
|
||||
}
|
||||
|
||||
// 关键槽函数,棋谱的命令行执行,与actionPiece独立
|
||||
// Key slot function, command line execution of chess score, independent of actionPiece
|
||||
bool Game::command(const string &cmd, bool update /* = true */)
|
||||
{
|
||||
int total = 0;
|
||||
|
@ -948,7 +932,7 @@ bool Game::command(const string &cmd, bool update /* = true */)
|
|||
Q_UNUSED(hasSound)
|
||||
|
||||
#ifdef QT_GUI_LIB
|
||||
// 防止接收滞后结束的线程发送的指令
|
||||
// Prevents receiving instructions sent by threads that end late
|
||||
if (sender() == aiThread[BLACK] && !isAiPlayer[BLACK])
|
||||
return false;
|
||||
|
||||
|
@ -956,7 +940,6 @@ bool Game::command(const string &cmd, bool update /* = true */)
|
|||
return false;
|
||||
#endif // QT_GUI_LIB
|
||||
|
||||
// 声音
|
||||
GameSound soundType = GameSound::none;
|
||||
|
||||
switch (position.get_action()) {
|
||||
|
@ -972,7 +955,6 @@ bool Game::command(const string &cmd, bool update /* = true */)
|
|||
}
|
||||
//#endif
|
||||
|
||||
// 如果未开局则开局
|
||||
if (position.get_phase() == Phase::ready) {
|
||||
gameStart();
|
||||
}
|
||||
|
@ -995,35 +977,35 @@ bool Game::command(const string &cmd, bool update /* = true */)
|
|||
updateScence(position);
|
||||
}
|
||||
|
||||
// 发信号更新状态栏
|
||||
// Signal update status bar
|
||||
updateScence();
|
||||
message = QString::fromStdString(getTips());
|
||||
emit statusBarChanged(message);
|
||||
|
||||
// 对于新开局
|
||||
// For opening
|
||||
if (move_hostory()->size() <= 1) {
|
||||
manualListModel.removeRows(0, manualListModel.rowCount());
|
||||
manualListModel.insertRow(0);
|
||||
manualListModel.setData(manualListModel.index(0), position.get_record());
|
||||
currentRow = 0;
|
||||
}
|
||||
// 对于当前局
|
||||
// For the current position
|
||||
else {
|
||||
currentRow = manualListModel.rowCount() - 1;
|
||||
// 跳过已添加行,迭代器不支持+运算符,只能一个个++
|
||||
// Skip the added rows. The iterator does not support the + operator and can only skip one by one++
|
||||
auto i = (move_hostory()->begin());
|
||||
for (int r = 0; i != (move_hostory())->end(); i++) {
|
||||
if (r++ > currentRow)
|
||||
break;
|
||||
}
|
||||
// 将新增的棋谱行插入到ListModel
|
||||
// Insert the new chess score line into listmodel
|
||||
while (i != move_hostory()->end()) {
|
||||
manualListModel.insertRow(++currentRow);
|
||||
manualListModel.setData(manualListModel.index(currentRow), (*i++).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// 播放胜利或失败音效
|
||||
// Play win or lose sound
|
||||
#ifndef DONOT_PLAY_WIN_SOUND
|
||||
const Color winner = position.get_winner();
|
||||
if (winner != NOBODY &&
|
||||
|
@ -1032,12 +1014,12 @@ bool Game::command(const string &cmd, bool update /* = true */)
|
|||
}
|
||||
#endif
|
||||
|
||||
// AI设置
|
||||
// 如果还未决出胜负
|
||||
// AI Settings
|
||||
// If it's not decided yet
|
||||
if (position.get_winner() == NOBODY) {
|
||||
resumeAiThreads(position.sideToMove);
|
||||
}
|
||||
// 如果已经决出胜负
|
||||
// If it's decided
|
||||
else {
|
||||
pauseThreads();
|
||||
|
||||
|
@ -1106,16 +1088,15 @@ bool Game::command(const string &cmd, bool update /* = true */)
|
|||
}
|
||||
|
||||
#ifdef MESSAGEBOX_ENABLE
|
||||
// 弹框
|
||||
message = QString::fromStdString(position.get_tips());
|
||||
QMessageBox::about(NULL, "游戏结果", message);
|
||||
QMessageBox::about(NULL, "Game Result", message);
|
||||
#endif
|
||||
}
|
||||
|
||||
gameTest->writeToMemory(QString::fromStdString(cmd));
|
||||
|
||||
#ifdef NET_FIGHT_SUPPORT
|
||||
// 网络: 将着法放到服务器的发送列表中
|
||||
// Network: put the method in the server's send list
|
||||
getServer()->setAction(QString::fromStdString(cmd));
|
||||
#endif
|
||||
|
||||
|
@ -1143,14 +1124,14 @@ bool Game::command(const string &cmd, bool update /* = true */)
|
|||
return true;
|
||||
}
|
||||
|
||||
// 浏览历史局面,通过command函数刷新局面显示
|
||||
// Browse the historical situation and refresh the situation display through the command function
|
||||
bool Game::phaseChange(int row, bool forceUpdate)
|
||||
{
|
||||
// 如果row是当前浏览的棋谱行,则不需要刷新
|
||||
// If row is the currently viewed chess score line, there is no need to refresh it
|
||||
if (currentRow == row && !forceUpdate)
|
||||
return false;
|
||||
|
||||
// 需要刷新
|
||||
// Need to refresh
|
||||
currentRow = row;
|
||||
int rows = manualListModel.rowCount();
|
||||
QStringList mlist = manualListModel.stringList();
|
||||
|
@ -1162,10 +1143,10 @@ bool Game::phaseChange(int row, bool forceUpdate)
|
|||
position.command(mlist.at(i).toStdString().c_str());
|
||||
}
|
||||
|
||||
// 下面这步关键,会让悔棋者承担时间损失
|
||||
// The key step is to let the penitent bear the loss of time
|
||||
set_start_time(static_cast<int>(start_timeb()));
|
||||
|
||||
// 刷新棋局场景
|
||||
// Refresh the chess scene
|
||||
updateScence(position);
|
||||
|
||||
return true;
|
||||
|
@ -1181,16 +1162,16 @@ bool Game::updateScence(Position &p)
|
|||
const Piece *board = p.get_board();
|
||||
QPointF pos;
|
||||
|
||||
// game类中的棋子代码
|
||||
// Chess code in game class
|
||||
int key;
|
||||
|
||||
// 棋子总数
|
||||
// Total number of pieces
|
||||
int nTotalPieces = rule.piecesCount * 2;
|
||||
|
||||
// 动画组
|
||||
// Animation group
|
||||
auto *animationGroup = new QParallelAnimationGroup;
|
||||
|
||||
// 棋子就位
|
||||
// The pieces are in place
|
||||
PieceItem *piece = nullptr;
|
||||
PieceItem *deletedPiece = nullptr;
|
||||
|
||||
|
@ -1199,21 +1180,21 @@ bool Game::updateScence(Position &p)
|
|||
|
||||
piece->setSelected(false);
|
||||
|
||||
// 将pieceList的下标转换为game的棋子代号
|
||||
// Convert the subscript of pieceList to the chess code of game
|
||||
key = (i % 2) ? (i / 2 + W_STONE_1) : (i / 2 + B_STONE_1);
|
||||
|
||||
int j;
|
||||
|
||||
// 遍历棋盘,查找并放置棋盘上的棋子
|
||||
// Traverse the board, find and place the pieces on the board
|
||||
for (j = SQ_BEGIN; j < SQ_END; j++) {
|
||||
if (board[j] == key) {
|
||||
pos = scene.polar2pos(File(j / RANK_NB), Rank(j % RANK_NB + 1));
|
||||
if (piece->pos() != pos) {
|
||||
|
||||
// 让移动的棋子位于顶层
|
||||
// Let the moving pieces be at the top level
|
||||
piece->setZValue(1);
|
||||
|
||||
// 棋子移动动画
|
||||
// Pieces movement animation
|
||||
QPropertyAnimation *animation = new QPropertyAnimation(piece, "pos");
|
||||
animation->setDuration(durationTime);
|
||||
animation->setStartValue(piece->pos());
|
||||
|
@ -1221,16 +1202,16 @@ bool Game::updateScence(Position &p)
|
|||
animation->setEasingCurve(QEasingCurve::InOutQuad);
|
||||
animationGroup->addAnimation(animation);
|
||||
} else {
|
||||
// 让静止的棋子位于底层
|
||||
// Let the still pieces be at the bottom
|
||||
piece->setZValue(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有找到,放置棋盘外的棋子
|
||||
// If not, place the pieces outside the chessboard
|
||||
if (j == (RANK_NB) * (FILE_NB + 1)) {
|
||||
// 判断是被吃掉的子,还是未安放的子
|
||||
// Judge whether it is a removing seed or an unplaced one
|
||||
if (key & B_STONE) {
|
||||
pos = (key - 0x11 < nTotalPieces / 2 - p.count<IN_HAND>(BLACK)) ?
|
||||
scene.pos_p2_g : scene.pos_p1;
|
||||
|
@ -1240,7 +1221,7 @@ bool Game::updateScence(Position &p)
|
|||
}
|
||||
|
||||
if (piece->pos() != pos) {
|
||||
// 为了对最近移除的棋子置为选择状态作准备
|
||||
// In order to prepare for the selection of the recently removed pieces
|
||||
deletedPiece = piece;
|
||||
|
||||
#ifdef GAME_PLACING_SHOW_REMOVED_PIECES
|
||||
|
@ -1261,7 +1242,7 @@ bool Game::updateScence(Position &p)
|
|||
piece->setSelected(false);
|
||||
}
|
||||
|
||||
// 添加摆棋阶段禁子点
|
||||
// Add banned points in placing phase
|
||||
if (rule.hasBannedLocations && p.get_phase() == Phase::placing) {
|
||||
for (int j = SQ_BEGIN; j < SQ_END; j++) {
|
||||
if (board[j] == BAN_STONE) {
|
||||
|
@ -1280,7 +1261,7 @@ bool Game::updateScence(Position &p)
|
|||
}
|
||||
}
|
||||
|
||||
// 走棋阶段清除禁子点
|
||||
// Clear banned points in moving phase
|
||||
if (rule.hasBannedLocations && p.get_phase() != Phase::placing) {
|
||||
while (nTotalPieces < static_cast<int>(pieceList.size())) {
|
||||
delete pieceList.at(pieceList.size() - 1);
|
||||
|
@ -1288,7 +1269,7 @@ bool Game::updateScence(Position &p)
|
|||
}
|
||||
}
|
||||
|
||||
// 选中当前棋子
|
||||
// Select the current piece
|
||||
int ipos = p.current_square();
|
||||
if (ipos) {
|
||||
key = board[p.current_square()];
|
||||
|
@ -1299,19 +1280,19 @@ bool Game::updateScence(Position &p)
|
|||
}
|
||||
}
|
||||
|
||||
// 对最近移除的棋子置为选择状态
|
||||
// Set the most recently removed pieces to select action
|
||||
if (deletedPiece) {
|
||||
deletedPiece->setSelected(true);
|
||||
}
|
||||
|
||||
animationGroup->start(QAbstractAnimation::DeleteWhenStopped);
|
||||
|
||||
// 更新比分 LCD 显示
|
||||
// Update LCD display
|
||||
emit score1Changed(QString::number(p.score[BLACK], 10));
|
||||
emit score2Changed(QString::number(p.score[WHITE], 10));
|
||||
emit scoreDrawChanged(QString::number(p.score_draw, 10));
|
||||
|
||||
// 更新胜率 LCD 显示
|
||||
// Update winning rate LCD display
|
||||
position.gamesPlayedCount = position.score[BLACK] + position.score[WHITE] + position.score_draw;
|
||||
int winningRate_1 = 0, winningRate_2 = 0, winningRate_draw = 0;
|
||||
if (position.gamesPlayedCount != 0) {
|
||||
|
@ -1362,19 +1343,16 @@ void Game::saveScore()
|
|||
|
||||
QFile file;
|
||||
|
||||
// 文件对象
|
||||
file.setFileName(path);
|
||||
|
||||
if (file.isOpen()) {
|
||||
file.close();
|
||||
}
|
||||
|
||||
// 打开文件,只写方式打开
|
||||
if (!(file.open(QFileDevice::WriteOnly | QFileDevice::Text))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 写文件
|
||||
QTextStream textStream(&file);
|
||||
|
||||
textStream << QCoreApplication::applicationFilePath() << endl << endl;
|
||||
|
|
162
src/ui/qt/game.h
162
src/ui/qt/game.h
|
@ -13,14 +13,15 @@
|
|||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with this program. If not, see <http:// www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* 这个类处理场景对象QGraphicsScene
|
||||
* 它是本程序MVC模型中唯一的控制模块
|
||||
* 它不对主窗口中的控件做任何操作,只向主窗口发出信号
|
||||
* 本来可以重载QGraphicsScene实现它,还能省去写事件过滤器的麻烦
|
||||
* 但用一个场景类做那么多控制模块的操作看上去不太好
|
||||
/*
|
||||
* This class deals with the scene object QGraphicsScene
|
||||
* It is the only control module in MVC model of this program
|
||||
* It doesn't do any operation on the controls in the main window, only signals the main window
|
||||
* You could have overloaded QGraphicsScene to implement it and saved the trouble of writing event filters
|
||||
* But it doesn't look good to use one scene class to do so many control module operations
|
||||
*/
|
||||
|
||||
#ifndef GAMECONTROLLER_H
|
||||
|
@ -86,7 +87,7 @@ public:
|
|||
);
|
||||
~Game() override;
|
||||
|
||||
//主窗口菜单栏明细
|
||||
// Main window menu bar details
|
||||
const map<int, QStringList> getActions();
|
||||
|
||||
int getRuleIndex() noexcept
|
||||
|
@ -166,101 +167,101 @@ public:
|
|||
|
||||
signals:
|
||||
|
||||
// 总盘数改变的信号
|
||||
// Signal of total disk number change
|
||||
void nGamesPlayedChanged(const QString &score);
|
||||
|
||||
// 玩家1(先手)赢盘数改变的信号
|
||||
// Player 1 (first hand) signal to change the number of winning sets
|
||||
void score1Changed(const QString &score);
|
||||
|
||||
// 玩家2(后手)赢盘数改变的信号
|
||||
// Signal for player 2 (backhand) to change the number of winning sets
|
||||
void score2Changed(const QString &score);
|
||||
|
||||
// 和棋数改变的信号
|
||||
// The signal of the change of draw number
|
||||
void scoreDrawChanged(const QString &score);
|
||||
|
||||
// 玩家1(先手)胜率改变的信号
|
||||
// Signal of player 1 (first hand) winning rate change
|
||||
void winningRate1Changed(const QString &score);
|
||||
|
||||
// 玩家2(后手)胜率改变的信号
|
||||
// Signal of player 2 (backhand) winning rate change
|
||||
void winningRate2Changed(const QString &score);
|
||||
|
||||
// 和棋率改变的信号
|
||||
// Signal of change of draw rate
|
||||
void winningRateDrawChanged(const QString &score);
|
||||
|
||||
// 玩家1(先手)用时改变的信号
|
||||
// Player 1 (first hand) time changed signal
|
||||
void time1Changed(const QString &time);
|
||||
|
||||
// 玩家2(后手)用时改变的信号
|
||||
// Player 2 (backhand) time changed signal
|
||||
void time2Changed(const QString &time);
|
||||
|
||||
// 通知主窗口更新状态栏的信号
|
||||
// A signal that tells the main window to update the status bar
|
||||
void statusBarChanged(const QString &message);
|
||||
|
||||
public slots:
|
||||
|
||||
// 设置规则
|
||||
// Set rules
|
||||
void setRule(int ruleNo, int stepLimited = std::numeric_limits<uint16_t>::max(), int timeLimited = -1);
|
||||
|
||||
// 游戏开始
|
||||
// The game begins
|
||||
void gameStart();
|
||||
|
||||
// 游戏重置
|
||||
// Game reset
|
||||
void gameReset();
|
||||
|
||||
// 设置编辑棋局状态
|
||||
// Set edit chess state
|
||||
void setEditing(bool arg = true) noexcept;
|
||||
|
||||
// 设置黑白反转状态
|
||||
// Set black and white inversion state
|
||||
void setInvert(bool arg = true);
|
||||
|
||||
// id为1时让电脑执先手, id为2时让的电脑执后手
|
||||
// If Id is 1, let the computer take the lead; if Id is 2, let the computer take the second place
|
||||
void setEngine(Color color, bool enabled = true);
|
||||
void setEngineBlack(bool enabled);
|
||||
void setEngineWhite(bool enabled);
|
||||
|
||||
// 是否有落子动画
|
||||
// Is there a falling animation
|
||||
void setAnimation(bool arg = true) noexcept;
|
||||
|
||||
// 是否有落子音效
|
||||
// Is there a drop sound effect
|
||||
void setSound(bool arg = true) noexcept;
|
||||
|
||||
// 播放声音
|
||||
// Play the sound
|
||||
static void playSound(GameSound soundType, Color c);
|
||||
|
||||
// 是否必败时认输
|
||||
// Do you admit defeat when you lose
|
||||
void setResignIfMostLose(bool enabled);
|
||||
|
||||
// 是否自动开局
|
||||
// Auto start or not
|
||||
void setAutoRestart(bool enabled = false);
|
||||
|
||||
// 是否开局自动改变先后手
|
||||
// Is the start automatically changed to the first before the second
|
||||
void setAutoChangeFirstMove(bool enabled = false);
|
||||
|
||||
// AI 是否随机走子
|
||||
// Is AI random
|
||||
void setShuffling(bool enabled);
|
||||
|
||||
// AI 是否记录残局库
|
||||
// Does AI record the game library
|
||||
void setLearnEndgame(bool enabled);
|
||||
|
||||
// Alpha-Beta 搜索时是否迭代加深
|
||||
// Does alpha beta search deepen iteratively
|
||||
void setIDS(bool enabled);
|
||||
|
||||
// DepthExtension
|
||||
// DepthExtension
|
||||
void setDepthExtension(bool enabled);
|
||||
|
||||
// OpeningBook
|
||||
// OpeningBook
|
||||
void setOpeningBook(bool enabled);
|
||||
|
||||
// 上下翻转
|
||||
// Flip up and down
|
||||
void flip();
|
||||
|
||||
// 左右镜像
|
||||
// Left and right mirror images
|
||||
void mirror();
|
||||
|
||||
// 视图须时针旋转90°
|
||||
// The view must be rotated 90 ° clockwise
|
||||
void turnRight();
|
||||
|
||||
// 视图逆时针旋转90°
|
||||
// View rotated 90 degree counterclockwise
|
||||
void turnLeft();
|
||||
|
||||
bool isAIsTurn();
|
||||
|
@ -340,28 +341,28 @@ public slots:
|
|||
delete aiThread[WHITE];
|
||||
}
|
||||
|
||||
// 根据QGraphicsScene的信号和状态来执行选子、落子或去子
|
||||
// According to the signal and state of qgraphics scene, select, drop or delete the sub objects
|
||||
bool actionPiece(QPointF p);
|
||||
|
||||
// 认输
|
||||
// Admit defeat
|
||||
bool resign();
|
||||
|
||||
// 棋谱的命令行执行
|
||||
// Command line execution of chess score
|
||||
bool command(const string &cmd, bool update = true);
|
||||
|
||||
// 历史局面及局面改变
|
||||
// Historical situation and situation change
|
||||
bool phaseChange(int row, bool forceUpdate = false);
|
||||
|
||||
// 更新棋局显示,每步后执行才能刷新局面
|
||||
// Update the chess game display. Only after each step can the situation be refreshed
|
||||
bool updateScence();
|
||||
bool updateScence(Position &p);
|
||||
|
||||
#ifdef NET_FIGHT_SUPPORT
|
||||
// 显示网络配置窗口
|
||||
// The network configuration window is displayed
|
||||
void showNetworkWindow();
|
||||
#endif
|
||||
|
||||
// 显示引擎对战窗口
|
||||
// Show engine vs. window
|
||||
void showTestWindow();
|
||||
|
||||
void saveScore();
|
||||
|
@ -372,42 +373,46 @@ public slots:
|
|||
}
|
||||
|
||||
protected:
|
||||
//bool eventFilter(QObject * watched, QEvent * event);
|
||||
// 定时器
|
||||
// bool eventFilter(QObject * watched, QEvent * event);
|
||||
|
||||
// Timer
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
|
||||
private:
|
||||
// 棋对象的数据模型
|
||||
|
||||
// Data model of chess object
|
||||
Position position;
|
||||
Color sideToMove;
|
||||
|
||||
// 测试
|
||||
// Testing
|
||||
Test *gameTest;
|
||||
|
||||
private:
|
||||
// 2个AI的线程
|
||||
|
||||
// 2 AI threads
|
||||
Thread *aiThread[COLOR_NB];
|
||||
|
||||
// 棋局的场景类
|
||||
// The scene class of chess game
|
||||
GameScene &scene;
|
||||
|
||||
// 所有棋子
|
||||
// All the pieces
|
||||
vector<PieceItem *> pieceList;
|
||||
|
||||
// 当前棋子
|
||||
// Current chess pieces
|
||||
PieceItem *currentPiece;
|
||||
|
||||
// 当前浏览的棋谱行
|
||||
// Current browsing chess score line
|
||||
int currentRow;
|
||||
|
||||
// 是否处于“编辑棋局”状态
|
||||
// Is it in "Edit chess game" state
|
||||
bool isEditing;
|
||||
|
||||
// 是否黑白反转
|
||||
// Reverse black and white
|
||||
bool isInverted;
|
||||
|
||||
public:
|
||||
// 电脑执先手时为 true
|
||||
|
||||
// True when the computer takes the lead
|
||||
bool isAiPlayer[COLOR_NB];
|
||||
|
||||
string getTips()
|
||||
|
@ -416,69 +421,70 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
// 是否有落子动画
|
||||
|
||||
// Is there a falling animation
|
||||
bool hasAnimation;
|
||||
|
||||
// 动画持续时间
|
||||
// Animation duration
|
||||
int durationTime;
|
||||
|
||||
// 游戏开始时间
|
||||
// Game start time
|
||||
TimePoint gameStartTime;
|
||||
|
||||
// 游戏结束时间
|
||||
// Game end time
|
||||
TimePoint gameEndTime;
|
||||
|
||||
// 游戏持续时间
|
||||
// Game duration
|
||||
TimePoint gameDurationTime;
|
||||
|
||||
// 游戏开始周期
|
||||
// Game start cycle
|
||||
stopwatch::rdtscp_clock::time_point gameStartCycle;
|
||||
|
||||
// 游戏结束周期
|
||||
// Game end cycle
|
||||
stopwatch::rdtscp_clock::time_point gameEndCycle;
|
||||
|
||||
// 游戏持续周期
|
||||
// Game duration
|
||||
stopwatch::rdtscp_clock::duration gameDurationCycle;
|
||||
|
||||
// 时间相关
|
||||
// Time dependent
|
||||
time_t startTime;
|
||||
time_t currentTime;
|
||||
time_t elapsedSeconds[COLOR_NB];
|
||||
|
||||
// 是否有落子音效
|
||||
// Is there a drop sound effect
|
||||
inline static bool hasSound {true};
|
||||
|
||||
// 是否必败时认输
|
||||
// Do you admit defeat when you lose
|
||||
bool resignIfMostLose_ {false};
|
||||
|
||||
// 是否自动交换先后手
|
||||
// Do you want to exchange first before second
|
||||
bool isAutoChangeFirstMove { false };
|
||||
|
||||
// AI 是否为先手
|
||||
// Is ai the first
|
||||
bool isAiFirstMove { false };
|
||||
|
||||
// 定时器ID
|
||||
// Timer ID
|
||||
int timeID;
|
||||
|
||||
// 规则号
|
||||
// Rule number
|
||||
int ruleIndex;
|
||||
|
||||
// 规则限时(分钟)
|
||||
// Rule time limit (minutes)
|
||||
int timeLimit;
|
||||
|
||||
// 规则限步数
|
||||
// Rule step limit
|
||||
int stepsLimit;
|
||||
|
||||
// 玩家剩余时间(秒)
|
||||
// Player's remaining time (seconds)
|
||||
time_t remainingTime[COLOR_NB];
|
||||
|
||||
// 用于主窗口状态栏显示的字符串
|
||||
// String used to display the status bar of the main window
|
||||
QString message;
|
||||
|
||||
// 棋谱字符串列表模型
|
||||
// String list model of chess score
|
||||
QStringListModel manualListModel;
|
||||
|
||||
// 提示语
|
||||
// Hint
|
||||
string tips;
|
||||
|
||||
std::vector <std::string> moveHistory;
|
||||
|
|
|
@ -34,7 +34,6 @@ GameScene::GameScene(QObject *parent) :
|
|||
pos_p2(LINE_INTERVAL *(-4), LINE_INTERVAL *(-6)),
|
||||
pos_p2_g(LINE_INTERVAL * 4, LINE_INTERVAL *(-6))
|
||||
{
|
||||
// 添加棋盘
|
||||
board = new BoardItem;
|
||||
board->setDiagonal(false);
|
||||
addItem(board);
|
||||
|
@ -45,71 +44,43 @@ GameScene::~GameScene()
|
|||
delete board;
|
||||
}
|
||||
|
||||
// 屏蔽掉Shift和Control按键,事实证明没用,按键事件未必由视图类处理
|
||||
#if 0
|
||||
void GameScene::keyPressEvent(QKeyEvent *keyEvent)
|
||||
{
|
||||
if(keyEvent->key() == Qt::Key_Shift || keyEvent->key() == Qt::Key_Control)
|
||||
return;
|
||||
QGraphicsScene::keyPressEvent(keyEvent);
|
||||
}
|
||||
#endif
|
||||
|
||||
void GameScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvent)
|
||||
{
|
||||
//屏蔽双击事件
|
||||
// Block double click events
|
||||
mouseEvent->accept();
|
||||
}
|
||||
|
||||
|
||||
void GameScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
|
||||
{
|
||||
// 屏蔽鼠标按下事件
|
||||
// Screen mouse down events
|
||||
mouseEvent->accept();
|
||||
|
||||
#if 0
|
||||
// 只处理左键事件
|
||||
if(mouseEvent->button() != Qt::LeftButton)
|
||||
return;
|
||||
// 如果不是棋子则结束
|
||||
QGraphicsItem *item = itemAt(mouseEvent->scenePos(), QTransform());
|
||||
if (!item || item->type() != PieceItem::Type)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 调用默认事件处理函数
|
||||
//QGraphicsScene::mousePressEvent(mouseEvent);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GameScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
|
||||
{
|
||||
// 只处理左键事件
|
||||
// Only handle left click events
|
||||
if (mouseEvent->button() != Qt::LeftButton) {
|
||||
mouseEvent->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果是棋盘
|
||||
// If it's a board
|
||||
const QGraphicsItem *item = itemAt(mouseEvent->scenePos(), QTransform());
|
||||
|
||||
if (!item || item->type() == BoardItem::Type) {
|
||||
QPointF p = mouseEvent->scenePos();
|
||||
p = board->nearestPosition(p);
|
||||
if (p != QPointF(0, 0))
|
||||
// 发送鼠标点最近的落子点
|
||||
// Send the nearest drop point of the mouse point
|
||||
emit mouseReleased(p);
|
||||
} // 如果是棋子
|
||||
} // If it's a chess piece
|
||||
else if (item->type() == PieceItem::Type) {
|
||||
// 将当前棋子在场景中的位置发送出去
|
||||
// Send out the position of the current piece in the scene
|
||||
emit mouseReleased(item->scenePos());
|
||||
}
|
||||
|
||||
mouseEvent->accept();
|
||||
|
||||
// 调用默认事件处理函数
|
||||
//QGraphicsScene::mouseReleaseEvent(mouseEvent);
|
||||
}
|
||||
|
||||
QPointF GameScene::polar2pos(File file, Rank rank)
|
||||
|
|
|
@ -33,19 +33,16 @@ public:
|
|||
explicit GameScene(QObject *parent = nullptr);
|
||||
~GameScene() override;
|
||||
|
||||
// 将模型的圈、位转化为落子点坐标
|
||||
QPointF polar2pos(File file, Rank rank);
|
||||
|
||||
// 将落子点坐标转化为模型用的圈、位
|
||||
bool pos2polar(QPointF pos, File &file, Rank &rank);
|
||||
|
||||
// 设置棋盘斜线
|
||||
void setDiagonal(bool arg = true);
|
||||
|
||||
// 玩家1的己方棋盒及对方棋盒位置
|
||||
// Position of player 1's own board and opponent's board
|
||||
const QPointF pos_p1, pos_p1_g;
|
||||
|
||||
// 玩家2的己方棋盒及对方棋盒位置
|
||||
// Position of player 2's own board and opponent's board
|
||||
const QPointF pos_p2, pos_p2_g;
|
||||
|
||||
protected:
|
||||
|
@ -60,7 +57,6 @@ signals:
|
|||
public slots:
|
||||
|
||||
private:
|
||||
// 棋盘对象
|
||||
BoardItem *board {nullptr};
|
||||
|
||||
};
|
||||
|
|
|
@ -24,36 +24,31 @@ GameView::GameView(QWidget *parent) :
|
|||
QGraphicsView(parent)
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
/* 不使用下面的方法
|
||||
// 初始化缩放因子为1.0
|
||||
sx = 1.0;
|
||||
sy = 1.0;
|
||||
*/
|
||||
}
|
||||
|
||||
GameView::~GameView() = default;
|
||||
|
||||
void GameView::flip()
|
||||
{
|
||||
// 视图上下翻转
|
||||
/* 以下用到了很多图形变换矩阵方面的知识
|
||||
* 不要用scale方法,Qt的图形变换是针对坐标系的
|
||||
* 缩放矩阵为
|
||||
// Flip view up and down
|
||||
/* The following uses a lot of knowledge about graphic transformation matrix
|
||||
* Do not use the scale method, QT graphics transformation is for the coordinate system
|
||||
* Scale matrix to
|
||||
* ┌sx 0 0┐
|
||||
* S = │ 0 sy 0│
|
||||
* └ 0 0 1┘
|
||||
* 上下翻转应在原变换矩阵基础上乘以一个如下的矩阵:
|
||||
* The up and down flip should be multiplied by the following matrix on the basis of the original transformation matrix:
|
||||
* ┌1 0 0┐
|
||||
* │0 -1 0│
|
||||
* └0 0 1┘
|
||||
*/
|
||||
|
||||
// 方法一: 直接在原变换矩阵基础上乘以上面的矩阵
|
||||
// QMatrix只对变换矩阵前两列赋值
|
||||
// Method 1: directly multiply the original transformation matrix by the above matrix
|
||||
// QMatrix only assigns values to the first two columns of the transformation matrix
|
||||
setMatrix(matrix() * QMatrix(1, 0, 0, -1, 0, 0));
|
||||
|
||||
/* 方法二: 人工计算好新的变换矩阵后再对场景赋值
|
||||
* 这个方法的效率未必高,还需要人工计算
|
||||
/* Method 2: manually calculate the new transformation matrix and then assign a value to the scene
|
||||
* The efficiency of this method is not necessarily high, and manual calculation is needed
|
||||
QMatrix mt = matrix();
|
||||
mt.setMatrix(-mt.m11(), mt.m12(), -mt.m21(), mt.m22(), -mt.dx(), mt.dy());
|
||||
setMatrix(mt);
|
||||
|
@ -62,8 +57,9 @@ void GameView::flip()
|
|||
|
||||
void GameView::mirror()
|
||||
{
|
||||
// 视图左右镜像
|
||||
/* 左右镜像应在原变换矩阵基础上乘以一个如下的矩阵:
|
||||
// Left and right mirror of view
|
||||
/* The left and right mirror images shall be multiplied by the following matrix
|
||||
on the basis of the original transformation matrix:
|
||||
* ┌-1 0 0┐
|
||||
* │ 0 1 0│
|
||||
* └ 0 0 1┘
|
||||
|
@ -73,13 +69,15 @@ void GameView::mirror()
|
|||
|
||||
void GameView::turnRight()
|
||||
{
|
||||
// 视图须时针旋转90°
|
||||
/* 不要用scale方法,视图镜像或翻转后它的转向会反过来
|
||||
* 旋转矩阵为
|
||||
// The view must be rotated 90 degree clockwise
|
||||
/* Don't use the scale method.
|
||||
After the view is mirrored or flipped, its steering will be reversed
|
||||
* The rotation matrix is
|
||||
* ┌ cos(α) sin(α) 0┐
|
||||
* R = │-sin(α) cos(α) 0│
|
||||
* └ 0 0 1┘
|
||||
* 视图须时针旋转90°应在原变换矩阵基础上乘以一个如下的矩阵:
|
||||
* The view must be rotated 90 degree clockwise and multiplied by
|
||||
* the following matrix on the basis of the original transformation matrix:
|
||||
* ┌ 0 1 0┐
|
||||
* │-1 0 0│
|
||||
* └ 0 0 1┘
|
||||
|
@ -89,8 +87,10 @@ void GameView::turnRight()
|
|||
|
||||
void GameView::turnLeft()
|
||||
{
|
||||
// 视图逆时针旋转90°
|
||||
/* 视图逆时针旋转90°应在原变换矩阵基础上乘以一个如下的矩阵:
|
||||
// View rotated 90 ° counterclockwise
|
||||
/* When the view is rotated 90 degree counterclockwise,
|
||||
* it should be multiplied by the following matrix
|
||||
* on the basis of the original transformation matrix:
|
||||
* ┌0 -1 0┐
|
||||
* │1 0 0│
|
||||
* └0 0 1┘
|
||||
|
@ -101,23 +101,6 @@ void GameView::turnLeft()
|
|||
|
||||
void GameView::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
#if 0
|
||||
// 不使用下面的形式了
|
||||
// 让场景适合视图
|
||||
if (sceneRect().width() <= 0 || sceneRect().height() <= 0)
|
||||
return;
|
||||
// 恢复缩放前的大小
|
||||
scale(1 / sx, 1 / sy);
|
||||
// 设置缩放因子
|
||||
sx = width() / sceneRect().width();
|
||||
sy = height() / sceneRect().height();
|
||||
sx = sx < sy ? sx : sy;
|
||||
sy = sx;
|
||||
// 缩放视图适合场景大小
|
||||
scale(sx, sy);
|
||||
#endif
|
||||
|
||||
// 使用如下形式,更简洁
|
||||
QGraphicsView::resizeEvent(event);
|
||||
fitInView(sceneRect(), Qt::KeepAspectRatio);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// 派生这个类主要是为了让视图适应场景大小及图像旋转镜像操作
|
||||
#ifndef GRAPHICSVIEW_H
|
||||
#define GRAPHICSVIEW_H
|
||||
|
||||
|
@ -24,6 +23,8 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
// This class is mainly derived to make the view adapt to
|
||||
// the scene size and image rotation mirror operation
|
||||
class GameView : public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -40,10 +41,6 @@ public slots:
|
|||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
// 缩放因子,代码更新后不使用了
|
||||
// qreal sx, sy;
|
||||
};
|
||||
|
||||
#endif // GRAPHICSVIEW_H
|
||||
|
|
|
@ -52,45 +52,47 @@ MillGameWindow::MillGameWindow(QWidget * parent) :
|
|||
{
|
||||
ui.setupUi(this);
|
||||
|
||||
// 去掉标题栏
|
||||
// Remove the title bar
|
||||
//setWindowFlags(Qt::FramelessWindowHint);
|
||||
|
||||
// 设置透明(窗体标题栏不透明,背景透明,如果不去掉标题栏,背景就变为黑色)
|
||||
// Set transparency
|
||||
// (the title bar of the form is opaque and the background is transparent.
|
||||
// If the title bar is not removed, the background will turn black)
|
||||
//setAttribute(Qt::WA_TranslucentBackground);
|
||||
|
||||
// 设置全体透明度系数
|
||||
// Set the overall transparency factor
|
||||
//setWindowOpacity(0.7);
|
||||
|
||||
// 设置场景
|
||||
// Set up the scene
|
||||
scene = new GameScene(this);
|
||||
|
||||
// 设置场景尺寸大小为棋盘大小的1.08倍
|
||||
// Set the scene size to 1.08 times the board size
|
||||
scene->setSceneRect(-BOARD_SIZE * 0.54, -BOARD_SIZE * 0.54,
|
||||
BOARD_SIZE * 1.08, BOARD_SIZE * 1.08);
|
||||
|
||||
// 初始化各个控件
|
||||
// Initialize the controls
|
||||
|
||||
// 关联视图和场景
|
||||
// Associate views and scenes
|
||||
ui.gameView->setScene(scene);
|
||||
|
||||
// 视图反走样
|
||||
// View anti aliasing
|
||||
ui.gameView->setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
// 视图反锯齿
|
||||
// View anti aliasing
|
||||
ui.gameView->setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
// 因功能限制,使部分功能不可用,将来再添加
|
||||
// Due to function limitation, some functions are not available and will be added in the future
|
||||
ui.actionInternet_I->setDisabled(false);
|
||||
ui.actionSetting_O->setDisabled(true);
|
||||
|
||||
// 初始化游戏规则菜单
|
||||
// Initialize game rules menu
|
||||
ui.menu_R->installEventFilter(this);
|
||||
|
||||
// 关联自动运行定时器
|
||||
// Associated auto run timer
|
||||
connect(&autoRunTimer, SIGNAL(timeout()),
|
||||
this, SLOT(onAutoRunTimeOut()));
|
||||
|
||||
// 主窗口居中显示
|
||||
// Center primary window
|
||||
QRect deskTopRect = QGuiApplication::primaryScreen()->geometry();
|
||||
const int unitw = (deskTopRect.width() - width()) / 2;
|
||||
const int unith = (deskTopRect.height() - height()) / 2;
|
||||
|
@ -102,14 +104,14 @@ MillGameWindow::MillGameWindow(QWidget * parent) :
|
|||
#endif
|
||||
|
||||
#ifdef MOBILE_APP_UI
|
||||
// 隐藏菜单栏、工具栏、状态栏等
|
||||
// Hide menu bar, toolbar, status bar, etc
|
||||
ui.menuBar->setVisible(false);
|
||||
ui.mainToolBar->setVisible(false);
|
||||
ui.dockWidget->setVisible(false);
|
||||
ui.statusBar->setVisible(false);
|
||||
#endif
|
||||
|
||||
// 游戏初始化
|
||||
// Game initialization
|
||||
initialize();
|
||||
}
|
||||
|
||||
|
@ -128,7 +130,7 @@ void MillGameWindow::closeEvent(QCloseEvent *event)
|
|||
if (file.isOpen())
|
||||
file.close();
|
||||
|
||||
// 取消自动运行
|
||||
// Cancel auto run
|
||||
ui.actionAutoRun_A->setChecked(false);
|
||||
|
||||
loggerDebug("closed\n");
|
||||
|
@ -138,7 +140,7 @@ void MillGameWindow::closeEvent(QCloseEvent *event)
|
|||
|
||||
bool MillGameWindow::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
// 重载这个函数只是为了让规则菜单(动态)显示提示
|
||||
// This function is overridded just to make the rules menu (dynamic) display prompts
|
||||
if (watched == ui.menu_R &&
|
||||
event->type() == QEvent::ToolTip) {
|
||||
const auto *he = dynamic_cast <QHelpEvent *> (event);
|
||||
|
@ -154,36 +156,36 @@ bool MillGameWindow::eventFilter(QObject *watched, QEvent *event)
|
|||
|
||||
void MillGameWindow::initialize()
|
||||
{
|
||||
// 初始化函数,仅执行一次
|
||||
// Initialize the function and execute it only once
|
||||
if (game)
|
||||
return;
|
||||
|
||||
// 开辟一个新的游戏控制器
|
||||
// New a new game controller
|
||||
game = new Game(*scene, this);
|
||||
|
||||
// 添加新菜单栏动作
|
||||
// Add a new menu bar action
|
||||
map<int, QStringList> actions = game->getActions();
|
||||
|
||||
for (auto i = actions.begin(); i != actions.end(); i++) {
|
||||
// map的key存放int索引值,value存放规则名称和规则提示
|
||||
// The key of map stores int index value, and value stores rule name and rule prompt
|
||||
auto *ruleAction = new QAction(i->second.at(0), this);
|
||||
ruleAction->setToolTip(i->second.at(1));
|
||||
ruleAction->setCheckable(true);
|
||||
|
||||
// 索引值放在QAction的Data里
|
||||
// The index value is put in the data of QAction
|
||||
ruleAction->setData(i->first);
|
||||
|
||||
// 添加到动作列表
|
||||
// Add to action list
|
||||
ruleActionList.push_back(ruleAction);
|
||||
|
||||
// 添加到“规则”菜单
|
||||
// Add to rules menu
|
||||
ui.menu_R->addAction(ruleAction);
|
||||
|
||||
connect(ruleAction, SIGNAL(triggered()),
|
||||
this, SLOT(actionRules_triggered()));
|
||||
}
|
||||
|
||||
// 关联主窗口动作信号和控制器的槽
|
||||
// The main window controller is associated with the action of the signal slot
|
||||
|
||||
connect(ui.actionResign_G, SIGNAL(triggered()),
|
||||
game, SLOT(resign()));
|
||||
|
@ -248,93 +250,74 @@ void MillGameWindow::initialize()
|
|||
connect(ui.actionOpeningBook_O, SIGNAL(toggled(bool)),
|
||||
game, SLOT(setOpeningBook(bool)));
|
||||
|
||||
// 视图上下翻转
|
||||
connect(ui.actionFlip_F, &QAction::triggered,
|
||||
game, &Game::flip);
|
||||
|
||||
// 视图左右镜像
|
||||
connect(ui.actionMirror_M, &QAction::triggered,
|
||||
game, &Game::mirror);
|
||||
|
||||
// 视图须时针旋转90°
|
||||
connect(ui.actionTurnRight_R, &QAction::triggered,
|
||||
game, &Game::turnRight);
|
||||
|
||||
// 视图逆时针旋转90°
|
||||
connect(ui.actionTurnLeftt_L, &QAction::triggered,
|
||||
game, &Game::turnLeft);
|
||||
|
||||
// 关联控制器的信号和主窗口控件的槽
|
||||
|
||||
// 更新LCD,显示总盘数
|
||||
connect(game, SIGNAL(nGamesPlayedChanged(QString)),
|
||||
ui.scoreLcdNumber_GamesPlayed, SLOT(display(QString)));
|
||||
|
||||
// 更新LCD,显示玩家1赢盘数
|
||||
connect(game, SIGNAL(score1Changed(QString)),
|
||||
ui.scoreLcdNumber_1, SLOT(display(QString)));
|
||||
|
||||
// 更新LCD,显示玩家2赢盘数
|
||||
connect(game, SIGNAL(score2Changed(QString)),
|
||||
ui.scoreLcdNumber_2, SLOT(display(QString)));
|
||||
|
||||
// 更新LCD,显示和棋数
|
||||
connect(game, SIGNAL(scoreDrawChanged(QString)),
|
||||
ui.scoreLcdNumber_draw, SLOT(display(QString)));
|
||||
|
||||
// 更新LCD,显示玩家1赢盘率
|
||||
connect(game, SIGNAL(winningRate1Changed(QString)),
|
||||
ui.winningRateLcdNumber_1, SLOT(display(QString)));
|
||||
|
||||
// 更新LCD,显示玩家2赢盘率
|
||||
connect(game, SIGNAL(winningRate2Changed(QString)),
|
||||
ui.winningRateLcdNumber_2, SLOT(display(QString)));
|
||||
|
||||
// 更新LCD,显示和棋率
|
||||
connect(game, SIGNAL(winningRateDrawChanged(QString)),
|
||||
ui.winningRateLcdNumber_draw, SLOT(display(QString)));
|
||||
|
||||
// 更新LCD1,显示玩家1用时
|
||||
connect(game, SIGNAL(time1Changed(QString)),
|
||||
ui.lcdNumber_1, SLOT(display(QString)));
|
||||
|
||||
// 更新LCD2,显示玩家2用时
|
||||
connect(game, SIGNAL(time2Changed(QString)),
|
||||
ui.lcdNumber_2, SLOT(display(QString)));
|
||||
|
||||
// 关联场景的信号和控制器的槽
|
||||
connect(scene, SIGNAL(mouseReleased(QPointF)),
|
||||
game, SLOT(actionPiece(QPointF)));
|
||||
|
||||
// 为状态栏添加一个正常显示的标签
|
||||
// Add a normal display label to the status bar
|
||||
auto *statusBarlabel = new QLabel(this);
|
||||
QFont statusBarFont;
|
||||
statusBarFont.setPointSize(16);
|
||||
statusBarlabel->setFont(statusBarFont);
|
||||
ui.statusBar->addWidget(statusBarlabel);
|
||||
|
||||
// 更新状态栏
|
||||
connect(game, SIGNAL(statusBarChanged(QString)),
|
||||
connect(game, SIGNAL(statusBarChanged(QString)),
|
||||
statusBarlabel, SLOT(setText(QString)));
|
||||
|
||||
// 默认规则
|
||||
ruleNo = DEFAULT_RULE_NUMBER;
|
||||
ruleActionList[ruleNo]->setChecked(true);
|
||||
|
||||
// 重置游戏规则
|
||||
game->setRule(ruleNo);
|
||||
|
||||
// 更新规则显示
|
||||
// Update rule display
|
||||
ruleInfo();
|
||||
|
||||
// 关联列表视图和字符串列表模型
|
||||
// List of associated models and string views
|
||||
ui.listView->setModel(game->getManualListModel());
|
||||
|
||||
// 因为QListView的rowsInserted在setModel之后才能启动,
|
||||
// 第一次需手动初始化选中listView第一项
|
||||
// Because QListView's rowsInserted can only be started after setModel,
|
||||
// The first time you need to manually initialize, select the first item of listView
|
||||
ui.listView->setCurrentIndex(ui.listView->model()->index(0, 0));
|
||||
|
||||
// 初始局面、前一步、后一步、最终局面的槽
|
||||
// //The slot of the initial situation, the previous step, the next step and the final situation
|
||||
|
||||
connect(ui.actionBegin_S, &QAction::triggered,
|
||||
this, &MillGameWindow::on_actionRowChange);
|
||||
|
@ -356,14 +339,14 @@ void MillGameWindow::initialize()
|
|||
connect(ui.actionEnd_E, &QAction::triggered,
|
||||
this, &MillGameWindow::on_actionRowChange);
|
||||
|
||||
// 手动在listView里选择着法后更新的槽
|
||||
// Manually select the updated slot in listView
|
||||
connect(ui.listView, &ManualListView::currentChangedSignal,
|
||||
this, &MillGameWindow::on_actionRowChange);
|
||||
|
||||
// 更新四个键的状态
|
||||
// Update the status of the four keys
|
||||
on_actionRowChange();
|
||||
|
||||
// 设置窗体大小
|
||||
// Set form size
|
||||
#ifdef MOBILE_APP_UI
|
||||
#if 0
|
||||
const int screen_iPhone_XS_Max[] = {1242, 2688};
|
||||
|
@ -393,7 +376,6 @@ void MillGameWindow::initialize()
|
|||
ui.pushButton_hint->setVisible(false);
|
||||
#endif /* MOBILE_APP_UI */
|
||||
|
||||
// 窗口最大化
|
||||
#ifdef SHOW_MAXIMIZED_ON_LOAD
|
||||
showMaximized();
|
||||
QWidget::setWindowFlags(Qt::WindowMaximizeButtonHint |
|
||||
|
@ -422,18 +404,18 @@ void MillGameWindow::ruleInfo()
|
|||
const int s = game->getStepsLimit();
|
||||
const int t = game->getTimeLimit();
|
||||
|
||||
QString tl(" 不限时");
|
||||
QString sl(" 不限步");
|
||||
QString tl(" No Time Limit");
|
||||
QString sl(" No Steps Limit");
|
||||
|
||||
if (s > 0)
|
||||
sl = " 限" + QString::number(s) + "步";
|
||||
sl = " Limit" + QString::number(s) + "steps";
|
||||
if (t > 0)
|
||||
tl = " 限时" + QString::number(s) + "分";
|
||||
tl = " Limit" + QString::number(s) + "min";
|
||||
|
||||
// 规则显示
|
||||
// Rule display
|
||||
ui.labelRule->setText(tl + sl);
|
||||
|
||||
// 规则提示
|
||||
// Rule tips
|
||||
ui.labelInfo->setToolTip(QString(RULES[ruleNo].name) + "\n" +
|
||||
RULES[ruleNo].description);
|
||||
|
||||
|
@ -455,15 +437,12 @@ void MillGameWindow::saveBook(const QString &path)
|
|||
file.close();
|
||||
}
|
||||
|
||||
// 文件对象
|
||||
file.setFileName(path);
|
||||
|
||||
// 打开文件,只写方式打开
|
||||
if (!(file.open(QFileDevice::WriteOnly | QFileDevice::Text))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 写文件
|
||||
QTextStream textStream(&file);
|
||||
auto *strlist = qobject_cast<QStringListModel *>(ui.listView->model());
|
||||
|
||||
|
@ -476,16 +455,9 @@ void MillGameWindow::saveBook(const QString &path)
|
|||
|
||||
void MillGameWindow::on_actionLimited_T_triggered()
|
||||
{
|
||||
/*
|
||||
* 其实本来可以用设计器做个ui,然后从QDialog派生个自己的对话框
|
||||
* 但我不想再派生新类了,又要多出一个类和两个文件
|
||||
* 还要写与主窗口的接口,费劲
|
||||
* 于是手写QDialog界面
|
||||
*/
|
||||
int gStep = game->getStepsLimit();
|
||||
int gTime = game->getTimeLimit();
|
||||
|
||||
// 定义新对话框
|
||||
auto *dialog = new QDialog(this);
|
||||
dialog->setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint);
|
||||
dialog->setObjectName(QStringLiteral("Dialog"));
|
||||
|
@ -493,15 +465,14 @@ void MillGameWindow::on_actionLimited_T_triggered()
|
|||
dialog->resize(256, 108);
|
||||
dialog->setModal(true);
|
||||
|
||||
// 生成各个控件
|
||||
auto *formLayout = new QFormLayout(dialog);
|
||||
auto *label_step = new QLabel(dialog);
|
||||
auto *label_time = new QLabel(dialog);
|
||||
auto *comboBox_step = new QComboBox(dialog);
|
||||
auto *comboBox_time = new QComboBox(dialog);
|
||||
auto *buttonBox = new QDialogButtonBox(dialog);
|
||||
|
||||
#if 0
|
||||
// 设置各个控件ObjectName,不设也没关系
|
||||
formLayout->setObjectName(QStringLiteral("formLayout"));
|
||||
label_step->setObjectName(QStringLiteral("label_step"));
|
||||
label_time->setObjectName(QStringLiteral("label_time"));
|
||||
|
@ -509,7 +480,7 @@ void MillGameWindow::on_actionLimited_T_triggered()
|
|||
comboBox_time->setObjectName(QStringLiteral("comboBox_time"));
|
||||
buttonBox->setObjectName(QStringLiteral("buttonBox"));
|
||||
#endif
|
||||
// 设置各个控件数据
|
||||
|
||||
label_step->setText(tr("If the number of moves exceeds the limit, it will get a draw:"));
|
||||
label_time->setText(tr("Either side loses if it times out:"));
|
||||
comboBox_step->addItem(tr("Infinite"), 0);
|
||||
|
@ -527,7 +498,6 @@ void MillGameWindow::on_actionLimited_T_triggered()
|
|||
buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK"));
|
||||
buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
|
||||
|
||||
// 布局
|
||||
formLayout->setSpacing(6);
|
||||
formLayout->setContentsMargins(11, 11, 11, 11);
|
||||
formLayout->setWidget(0, QFormLayout::LabelRole, label_step);
|
||||
|
@ -536,54 +506,46 @@ void MillGameWindow::on_actionLimited_T_triggered()
|
|||
formLayout->setWidget(1, QFormLayout::FieldRole, comboBox_time);
|
||||
formLayout->setWidget(2, QFormLayout::SpanningRole, buttonBox);
|
||||
|
||||
// 关联信号和槽函数
|
||||
connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept()));
|
||||
connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject()));
|
||||
|
||||
// 收集数据
|
||||
if (dialog->exec() == QDialog::Accepted) {
|
||||
int dStep = comboBox_step->currentData().toInt();
|
||||
int dTime = comboBox_time->currentData().toInt();
|
||||
if (gStep != dStep || gTime != dTime) {
|
||||
// 重置游戏规则
|
||||
game->setRule(ruleNo, static_cast<int>(dStep), dTime);
|
||||
}
|
||||
}
|
||||
|
||||
// 删除对话框,子控件会一并删除
|
||||
dialog->disconnect();
|
||||
delete dialog;
|
||||
|
||||
// 更新规则显示
|
||||
ruleInfo();
|
||||
}
|
||||
|
||||
void MillGameWindow::actionRules_triggered()
|
||||
{
|
||||
// 取消自动运行
|
||||
ui.actionAutoRun_A->setChecked(false);
|
||||
|
||||
// 取消其它规则的选择
|
||||
// Cancel the selection of other rules
|
||||
for (QAction *action : ruleActionList)
|
||||
action->setChecked(false);
|
||||
|
||||
// 选择当前规则
|
||||
// Select current rule
|
||||
auto *action = dynamic_cast<QAction *>(sender());
|
||||
action->setChecked(true);
|
||||
ruleNo = action->data().toInt();
|
||||
|
||||
// 如果游戏规则没变化,则返回
|
||||
// If the rules of the game have not changed, return
|
||||
if (ruleNo == game->getRuleIndex())
|
||||
return;
|
||||
|
||||
// 取消AI设定
|
||||
// Cancel AI setting
|
||||
ui.actionEngine1_T->setChecked(false);
|
||||
ui.actionEngine2_R->setChecked(false);
|
||||
|
||||
// 重置游戏规则
|
||||
game->setRule(ruleNo);
|
||||
|
||||
// 更新规则显示
|
||||
ruleInfo();
|
||||
}
|
||||
|
||||
|
@ -591,7 +553,8 @@ void MillGameWindow::on_actionNew_N_triggered()
|
|||
{
|
||||
auto *strlist = qobject_cast<QStringListModel *>(ui.listView->model());
|
||||
|
||||
// 棋未下完,且已经走了若干步以上,则算对手得分
|
||||
// If you have not finished playing game and have already taken more than a few steps,
|
||||
// you will be lost
|
||||
if (strlist->stringList().size() > 12) {
|
||||
game->humanResign();
|
||||
}
|
||||
|
@ -623,19 +586,16 @@ void MillGameWindow::on_actionNew_N_triggered()
|
|||
+ whoWin + "_" + strDateTime
|
||||
+ ".txt";
|
||||
|
||||
// 下了一定步数之后新建游戏时才保存棋谱
|
||||
// After a certain number of steps, save the score when creating a new game
|
||||
if (strlist->stringList().size() > 18) {
|
||||
saveBook(path);
|
||||
}
|
||||
#endif /* SAVE_GAMEBOOK_WHEN_ACTION_NEW_TRIGGERED */
|
||||
|
||||
// 取消自动运行
|
||||
ui.actionAutoRun_A->setChecked(false);
|
||||
|
||||
// 重置游戏规则
|
||||
game->gameReset();
|
||||
|
||||
// 重设AI设定
|
||||
if (ui.actionEngine2_R->isChecked()) {
|
||||
ui.actionEngine2_R->setChecked(false);
|
||||
ui.actionEngine2_R->setChecked(true);
|
||||
|
@ -649,7 +609,7 @@ void MillGameWindow::on_actionNew_N_triggered()
|
|||
|
||||
void MillGameWindow::on_actionOpen_O_triggered()
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("打开棋谱文件"), QDir::currentPath(), "TXT(*.txt)");
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Open the move history file"), QDir::currentPath(), "TXT(*.txt)");
|
||||
|
||||
if (path.isEmpty()) {
|
||||
return;
|
||||
|
@ -659,36 +619,31 @@ void MillGameWindow::on_actionOpen_O_triggered()
|
|||
file.close();
|
||||
}
|
||||
|
||||
// 文件对象
|
||||
file.setFileName(path);
|
||||
|
||||
// 不支持 1MB 以上的文件
|
||||
// Files larger than 1MB are not supported
|
||||
if (file.size() > 0x100000) {
|
||||
// 定义新对话框
|
||||
QMessageBox msgBox(QMessageBox::Warning,
|
||||
tr("文件过大"), tr("不支持 1MB 以上文件"), QMessageBox::Ok);
|
||||
tr("The file is too large"), tr("Files larger than 1MB are not supported"), QMessageBox::Ok);
|
||||
msgBox.exec();
|
||||
return;
|
||||
}
|
||||
|
||||
// 打开文件,只读方式打开
|
||||
if (!(file.open(QFileDevice::ReadOnly | QFileDevice::Text))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 取消AI设定
|
||||
ui.actionEngine1_T->setChecked(false);
|
||||
ui.actionEngine2_R->setChecked(false);
|
||||
|
||||
// 读文件
|
||||
QTextStream textStream(&file);
|
||||
QString cmd;
|
||||
cmd = textStream.readLine();
|
||||
|
||||
// 读取并显示棋谱时,不必刷新棋局场景
|
||||
// When reading and displaying the move history, there is no need to refresh the scene
|
||||
if (!(game->command(cmd.toStdString(), false))) {
|
||||
// 定义新对话框
|
||||
QMessageBox msgBox(QMessageBox::Warning, tr("文件错误"), tr("不是正确的棋谱文件"), QMessageBox::Ok);
|
||||
QMessageBox msgBox(QMessageBox::Warning, tr("File error"), tr("Not the correct move hisory file"), QMessageBox::Ok);
|
||||
msgBox.exec();
|
||||
return;
|
||||
}
|
||||
|
@ -698,7 +653,7 @@ void MillGameWindow::on_actionOpen_O_triggered()
|
|||
game->command(cmd.toStdString(), false);
|
||||
}
|
||||
|
||||
// 最后刷新棋局场景
|
||||
// Finally, refresh the scene
|
||||
game->updateScence();
|
||||
}
|
||||
|
||||
|
@ -707,9 +662,7 @@ void MillGameWindow::on_actionSave_S_triggered()
|
|||
if (file.isOpen()) {
|
||||
file.close();
|
||||
|
||||
// 打开文件,只写方式打开
|
||||
if (file.open(QFileDevice::WriteOnly | QFileDevice::Text)) {
|
||||
// 写文件
|
||||
QTextStream textStream(&file);
|
||||
auto *strlist = qobject_cast<QStringListModel *>(ui.listView->model());
|
||||
for (const QString &cmd : strlist->stringList())
|
||||
|
@ -726,8 +679,8 @@ void MillGameWindow::on_actionSave_S_triggered()
|
|||
void MillGameWindow::on_actionSaveAs_A_triggered()
|
||||
{
|
||||
QString path = QFileDialog::getSaveFileName(this,
|
||||
tr("打开棋谱文件"),
|
||||
QDir::currentPath() + tr("棋谱_") + QString::number(QDateTime::currentDateTimeUtc().toTime_t())+ ".txt", "TXT(*.txt)");
|
||||
tr("Open the move history file"),
|
||||
QDir::currentPath() + tr("MoveHistory_") + QString::number(QDateTime::currentDateTimeUtc().toTime_t())+ ".txt", "TXT(*.txt)");
|
||||
|
||||
saveBook(path);
|
||||
}
|
||||
|
@ -739,26 +692,23 @@ void MillGameWindow::on_actionEdit_E_toggled(bool arg1)
|
|||
|
||||
void MillGameWindow::on_actionInvert_I_toggled(bool arg1)
|
||||
{
|
||||
// 如果黑白反转
|
||||
// If black and white are reversed
|
||||
if (arg1) {
|
||||
// 设置玩家1和玩家2的标识图
|
||||
ui.actionEngine1_T->setIcon(QIcon(":/icon/Resources/icon/White.png"));
|
||||
ui.actionEngine2_R->setIcon(QIcon(":/icon/Resources/icon/Black.png"));
|
||||
ui.picLabel1->setPixmap(QPixmap(":/icon/Resources/icon/White.png"));
|
||||
ui.picLabel2->setPixmap(QPixmap(":/icon/Resources/icon/Black.png"));
|
||||
} else {
|
||||
// 设置玩家1和玩家2的标识图
|
||||
ui.actionEngine1_T->setIcon(QIcon(":/icon/Resources/icon/Black.png"));
|
||||
ui.actionEngine2_R->setIcon(QIcon(":/icon/Resources/icon/White.png"));
|
||||
ui.picLabel1->setPixmap(QPixmap(":/icon/Resources/icon/Black.png"));
|
||||
ui.picLabel2->setPixmap(QPixmap(":/icon/Resources/icon/White.png"));
|
||||
}
|
||||
|
||||
// 让控制器改变棋子颜色
|
||||
// Let the controller change the color of the pieces
|
||||
game->setInvert(arg1);
|
||||
}
|
||||
|
||||
// 前后招的公共槽
|
||||
void MillGameWindow::on_actionRowChange()
|
||||
{
|
||||
QAbstractItemModel *model = ui.listView->model();
|
||||
|
@ -789,7 +739,7 @@ void MillGameWindow::on_actionRowChange()
|
|||
currentRow = ui.listView->currentIndex().row();
|
||||
}
|
||||
|
||||
// 更新动作状态
|
||||
// Update action status
|
||||
if (rows <= 1) {
|
||||
ui.actionBegin_S->setEnabled(false);
|
||||
ui.actionPrevious_B->setEnabled(false);
|
||||
|
@ -818,29 +768,8 @@ void MillGameWindow::on_actionRowChange()
|
|||
}
|
||||
}
|
||||
|
||||
// 更新局面
|
||||
// Update phrase
|
||||
game->phaseChange(currentRow);
|
||||
|
||||
#if 0
|
||||
// 下面的代码全部取消,改用QTimer的方式实现
|
||||
// 更新局面
|
||||
bool changed = state->phaseChange(currentRow);
|
||||
// 处理自动播放时的动画
|
||||
if (changed && state->isAnimation()) {
|
||||
// 不使用processEvents函数进行非阻塞延时,频繁调用占用CPU较多
|
||||
//QElapsedTimer et;
|
||||
//et.start();
|
||||
//while (et.elapsed() < waitTime) {
|
||||
// qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
//}
|
||||
|
||||
int waitTime = state->getDurationTime() + 50;
|
||||
// 使用QEventLoop进行非阻塞延时,CPU占用低
|
||||
QEventLoop loop;
|
||||
QTimer::singleShot(waitTime, &loop, SLOT(quit()));
|
||||
loop.exec();
|
||||
}
|
||||
#endif // 0
|
||||
}
|
||||
|
||||
void MillGameWindow::onAutoRunTimeOut(QPrivateSignal signal)
|
||||
|
@ -854,7 +783,7 @@ void MillGameWindow::onAutoRunTimeOut(QPrivateSignal signal)
|
|||
return;
|
||||
}
|
||||
|
||||
// 执行“下一招”
|
||||
// Do the "next move"
|
||||
if (currentRow >= rows - 1) {
|
||||
ui.actionAutoRun_A->setChecked(false);
|
||||
return;
|
||||
|
@ -866,7 +795,7 @@ void MillGameWindow::onAutoRunTimeOut(QPrivateSignal signal)
|
|||
|
||||
currentRow = ui.listView->currentIndex().row();
|
||||
|
||||
// 更新动作状态
|
||||
// Update action status
|
||||
if (currentRow <= 0) {
|
||||
ui.actionBegin_S->setEnabled(false);
|
||||
ui.actionPrevious_B->setEnabled(false);
|
||||
|
@ -887,25 +816,20 @@ void MillGameWindow::onAutoRunTimeOut(QPrivateSignal signal)
|
|||
ui.actionAutoRun_A->setEnabled(true);
|
||||
}
|
||||
|
||||
// 更新局面
|
||||
// Renew the situation
|
||||
game->phaseChange(currentRow);
|
||||
}
|
||||
|
||||
// 自动运行
|
||||
void MillGameWindow::on_actionAutoRun_A_toggled(bool arg1)
|
||||
{
|
||||
if (arg1) {
|
||||
// 自动运行前禁用控件
|
||||
ui.dockWidget->setEnabled(false);
|
||||
ui.gameView->setEnabled(false);
|
||||
|
||||
// 启动定时器
|
||||
autoRunTimer.start(game->getDurationTime() * 10 + 50);
|
||||
} else {
|
||||
// 关闭定时器
|
||||
autoRunTimer.stop();
|
||||
|
||||
// 自动运行结束后启用控件
|
||||
ui.dockWidget->setEnabled(true);
|
||||
ui.gameView->setEnabled(true);
|
||||
}
|
||||
|
@ -944,7 +868,6 @@ void MillGameWindow::on_actionEngineFight_E_triggered()
|
|||
|
||||
void MillGameWindow::on_actionEngine_E_triggered()
|
||||
{
|
||||
// 定义新对话框
|
||||
auto *dialog = new QDialog(this);
|
||||
dialog->setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint);
|
||||
dialog->setObjectName(QStringLiteral("Dialog"));
|
||||
|
@ -952,7 +875,6 @@ void MillGameWindow::on_actionEngine_E_triggered()
|
|||
dialog->resize(256, 188);
|
||||
dialog->setModal(true);
|
||||
|
||||
// 生成各个控件
|
||||
auto *vLayout = new QVBoxLayout(dialog);
|
||||
auto *groupBox1 = new QGroupBox(dialog);
|
||||
auto *groupBox2 = new QGroupBox(dialog);
|
||||
|
@ -967,7 +889,6 @@ void MillGameWindow::on_actionEngine_E_triggered()
|
|||
|
||||
auto *buttonBox = new QDialogButtonBox(dialog);
|
||||
|
||||
// 设置各个控件数据
|
||||
groupBox1->setTitle(tr("Player1 AI Settings"));
|
||||
label_time1->setText(tr("Time limit"));
|
||||
spinBox_time1->setMinimum(1);
|
||||
|
@ -983,7 +904,6 @@ void MillGameWindow::on_actionEngine_E_triggered()
|
|||
buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK"));
|
||||
buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
|
||||
|
||||
// 布局控件
|
||||
vLayout->addWidget(groupBox1);
|
||||
vLayout->addWidget(groupBox2);
|
||||
vLayout->addWidget(buttonBox);
|
||||
|
@ -994,17 +914,14 @@ void MillGameWindow::on_actionEngine_E_triggered()
|
|||
hLayout2->addWidget(label_time2);
|
||||
hLayout2->addWidget(spinBox_time2);
|
||||
|
||||
// 关联信号和槽函数
|
||||
connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept()));
|
||||
connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject()));
|
||||
|
||||
// 目前数据
|
||||
int time1, time2;
|
||||
game->getAiDepthTime(time1, time2);
|
||||
spinBox_time1->setValue(time1);
|
||||
spinBox_time2->setValue(time2);
|
||||
|
||||
// 新设数据
|
||||
if (dialog->exec() == QDialog::Accepted) {
|
||||
int time1_new, time2_new;
|
||||
|
||||
|
@ -1013,12 +930,10 @@ void MillGameWindow::on_actionEngine_E_triggered()
|
|||
|
||||
if (time1 != time1_new ||
|
||||
time2 != time2_new) {
|
||||
// 重置AI
|
||||
game->setAiDepthTime(time1_new, time2_new);
|
||||
}
|
||||
}
|
||||
|
||||
// 删除对话框,子控件会一并删除
|
||||
dialog->disconnect();
|
||||
delete dialog;
|
||||
}
|
||||
|
@ -1042,7 +957,6 @@ void MillGameWindow::on_actionAbout_A_triggered()
|
|||
dialog->setWindowTitle(tr("The Mill Game"));
|
||||
dialog->setModal(true);
|
||||
|
||||
// 生成各个控件
|
||||
auto *vLayout = new QVBoxLayout(dialog);
|
||||
auto *hLayout = new QHBoxLayout;
|
||||
//QLabel *label_icon1 = new QLabel(dialog);
|
||||
|
@ -1053,15 +967,16 @@ void MillGameWindow::on_actionAbout_A_triggered()
|
|||
auto *label_text = new QLabel(dialog);
|
||||
auto *label_image = new QLabel(dialog);
|
||||
|
||||
// 设置各个控件数据
|
||||
//label_icon1->setPixmap(QPixmap(QString::fromUtf8(":/image/resources/image/black_piece.png")));
|
||||
//label_icon2->setPixmap(QPixmap(QString::fromUtf8(":/image/resources/image/white_piece.png")));
|
||||
//label_icon1->setAlignment(Qt::AlignCenter);
|
||||
//label_icon2->setAlignment(Qt::AlignCenter);
|
||||
//label_icon1->setFixedSize(32, 32);
|
||||
//label_icon2->setFixedSize(32, 32);
|
||||
//label_icon1->setScaledContents(true);
|
||||
//label_icon2->setScaledContents(true);
|
||||
#if 0
|
||||
label_icon1->setPixmap(QPixmap(QString::fromUtf8(":/image/resources/image/black_piece.png")));
|
||||
label_icon2->setPixmap(QPixmap(QString::fromUtf8(":/image/resources/image/white_piece.png")));
|
||||
label_icon1->setAlignment(Qt::AlignCenter);
|
||||
label_icon2->setAlignment(Qt::AlignCenter);
|
||||
label_icon1->setFixedSize(32, 32);
|
||||
label_icon2->setFixedSize(32, 32);
|
||||
label_icon1->setScaledContents(true);
|
||||
label_icon2->setScaledContents(true);
|
||||
#endif
|
||||
|
||||
//date_text->setText(__DATE__);
|
||||
QString versionText;
|
||||
|
@ -1075,7 +990,6 @@ void MillGameWindow::on_actionAbout_A_triggered()
|
|||
version_text->setText(versionText);
|
||||
version_text->setAlignment(Qt::AlignLeft);
|
||||
|
||||
// 布局
|
||||
vLayout->addLayout(hLayout);
|
||||
//hLayout->addWidget(label_icon1);
|
||||
//hLayout->addWidget(label_icon2);
|
||||
|
@ -1085,10 +999,8 @@ void MillGameWindow::on_actionAbout_A_triggered()
|
|||
vLayout->addWidget(donate_text);
|
||||
vLayout->addWidget(label_image);
|
||||
|
||||
// 运行对话框
|
||||
dialog->exec();
|
||||
|
||||
// 删除对话框
|
||||
dialog->disconnect();
|
||||
delete dialog;
|
||||
}
|
||||
|
|
|
@ -57,37 +57,35 @@ protected:
|
|||
#endif /* MOBILE_APP_UI */
|
||||
|
||||
private slots:
|
||||
// 初始化
|
||||
void initialize();
|
||||
|
||||
#ifdef MOBILE_APP_UI
|
||||
// 上下文菜单
|
||||
void ctxMenu(const QPoint &pos);
|
||||
#endif /* MOBILE_APP_UI */
|
||||
|
||||
// 动态增加的菜单栏动作的槽函数
|
||||
void actionRules_triggered();
|
||||
|
||||
// 更新规则标签
|
||||
void ruleInfo();
|
||||
|
||||
// 自动运行定时处理函数
|
||||
void onAutoRunTimeOut(QPrivateSignal signal);
|
||||
|
||||
// 下面是各动作的槽函数
|
||||
// 注释掉的是已在UI管理器或主窗口初始化函数中连接好的
|
||||
// The slot function for each action
|
||||
// Remove functions have been connected in UI manager or main window initialization function
|
||||
void on_actionNew_N_triggered();
|
||||
void on_actionOpen_O_triggered();
|
||||
void on_actionSave_S_triggered();
|
||||
void on_actionSaveAs_A_triggered();
|
||||
//void on_actionExit_X_triggered();
|
||||
#if 0
|
||||
void on_actionExit_X_triggered();
|
||||
#endif
|
||||
void on_actionEdit_E_toggled(bool arg1);
|
||||
//void on_actionFlip_F_triggered();
|
||||
//void on_actionMirror_M_triggered();
|
||||
//void on_actionTurnRight_R_triggered();
|
||||
//void on_actionTurnLeftt_L_triggered();
|
||||
#if 0
|
||||
void on_actionFlip_F_triggered();
|
||||
void on_actionMirror_M_triggered();
|
||||
void on_actionTurnRight_R_triggered();
|
||||
void on_actionTurnLeftt_L_triggered();
|
||||
#endif
|
||||
void on_actionInvert_I_toggled(bool arg1);
|
||||
// 前后招的公共槽
|
||||
void on_actionRowChange();
|
||||
void on_actionAutoRun_A_toggled(bool arg1);
|
||||
//void on_actionResign_G_triggered();
|
||||
|
@ -96,14 +94,16 @@ private slots:
|
|||
void on_actionEngineFight_E_triggered();
|
||||
void on_actionInternet_I_triggered();
|
||||
void on_actionEngine_E_triggered();
|
||||
//void on_actionEngine1_R_toggled(bool arg1);
|
||||
//void on_actionEngine2_T_toggled(bool arg1);
|
||||
//void on_actionSetting_O_triggered();
|
||||
//void on_actionToolBar_T_toggled(bool arg1);
|
||||
//void on_actionDockBar_D_toggled(bool arg1);
|
||||
//void on_actionSound_S_toggled(bool arg1);
|
||||
//void on_actionAnimation_A_toggled(bool arg1);
|
||||
//void on_actionAutoRestart_A_triggered();
|
||||
#if 0
|
||||
void on_actionEngine1_R_toggled(bool arg1);
|
||||
void on_actionEngine2_T_toggled(bool arg1);
|
||||
void on_actionSetting_O_triggered();
|
||||
void on_actionToolBar_T_toggled(bool arg1);
|
||||
void on_actionDockBar_D_toggled(bool arg1);
|
||||
void on_actionSound_S_toggled(bool arg1);
|
||||
void on_actionAnimation_A_toggled(bool arg1);
|
||||
void on_actionAutoRestart_A_triggered();
|
||||
#endif
|
||||
void on_actionViewHelp_V_triggered();
|
||||
void on_actionWeb_W_triggered();
|
||||
void on_actionAbout_A_triggered();
|
||||
|
@ -112,25 +112,12 @@ protected:
|
|||
void saveBook(const QString &path);
|
||||
|
||||
private:
|
||||
// 界面文件
|
||||
Ui::MillGameWindowClass ui {};
|
||||
|
||||
// 视图场景
|
||||
GameScene *scene {nullptr};
|
||||
|
||||
// 控制器
|
||||
Game *game {nullptr};
|
||||
|
||||
// 动态增加的菜单栏动作列表
|
||||
vector<QAction *> ruleActionList;
|
||||
|
||||
// 游戏的规则号,涉及菜单项和对话框,所以要有
|
||||
int ruleNo {-1};
|
||||
|
||||
// 文件
|
||||
QFile file;
|
||||
|
||||
// 定时器
|
||||
QTimer autoRunTimer;
|
||||
|
||||
#ifdef MOBILE_APP_UI
|
||||
|
|
|
@ -16,22 +16,21 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// 定义绘图相关常量的头文件
|
||||
#ifndef GRAPHICSCONST
|
||||
#define GRAPHICSCONST
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef MOBILE_APP_UI
|
||||
constexpr short BOARD_SIZE = 500; // 棋盘大小
|
||||
constexpr short BOARD_SIZE = 500;
|
||||
#else
|
||||
constexpr short BOARD_SIZE = 600; // 棋盘大小
|
||||
constexpr short BOARD_SIZE = 600;
|
||||
#endif /* MOBILE_APP_UI */
|
||||
|
||||
constexpr short BOARD_MINISIZE = 150; // 最小宽高,即1/4大小
|
||||
constexpr short PIECE_SIZE = 56; // 棋子大小
|
||||
constexpr short LINE_INTERVAL = 72; // 线间距
|
||||
constexpr short LINE_WEIGHT = 3; // 线宽
|
||||
constexpr short BOARD_MINISIZE = 150; // Minimum width and height, i.e. 1 / 4 Size
|
||||
constexpr short PIECE_SIZE = 56;
|
||||
constexpr short LINE_INTERVAL = 72;
|
||||
constexpr short LINE_WEIGHT = 3;
|
||||
|
||||
#endif // GRAPHICSCONST
|
||||
|
||||
|
|
|
@ -16,16 +16,6 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* QListView派生类
|
||||
* 之所以要派生这个类,重载sizeHint函数
|
||||
* 只是为了让停靠栏(父窗口)在初始时不至于过宽难看
|
||||
* QDockWidget没有很好的控制初始大小的方法,resize函数没效果
|
||||
* 如果不用派生类,使用固定宽度也可以,如下所示
|
||||
* ui.listView->setFixedWidth(108);
|
||||
* 但调节停靠栏宽度后就不好看了
|
||||
*/
|
||||
|
||||
#ifndef MANUALLISTVIEW
|
||||
#define MANUALLISTVIEW
|
||||
|
||||
|
@ -34,6 +24,16 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
/*
|
||||
* QlistView derived class
|
||||
* The reason for deriving this class is to overload the sizeHint function
|
||||
* Just to make the docking bar(parent window) not too wide and ugly at the beginning
|
||||
* QDockWidget does not have a good way to control the initial size, and the reset function has no effect
|
||||
* If you don't use derived classes, you can use a fixed width, as shown below
|
||||
* ui.listView->setFixedWidth(108);
|
||||
* But it doesn't look good after adjusting the width of the dock
|
||||
*/
|
||||
|
||||
class ManualListView : public QListView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -48,21 +48,22 @@ public:
|
|||
{
|
||||
QSize size = QListView::sizeHint();
|
||||
|
||||
// 缺省宽度设为128,这样就不太宽了
|
||||
// The default width is 128, so it's not too wide
|
||||
size.setWidth(128);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
signals:
|
||||
// 需要一个currentChanged信号,但默认没有,需要把这个槽改造成信号
|
||||
// A currentChanged signal is required, but not by default.
|
||||
// This slot needs to be transformed into a signal
|
||||
void currentChangedSignal(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
|
||||
protected slots:
|
||||
// 屏蔽掉双击编辑功能
|
||||
// Block double-click editing feature
|
||||
void mouseDoubleClickEvent(QMouseEvent *mouseEvent) override
|
||||
{
|
||||
//屏蔽双击事件
|
||||
// Block double click events
|
||||
mouseEvent->accept();
|
||||
}
|
||||
|
||||
|
@ -74,30 +75,13 @@ protected slots:
|
|||
newEmptyRow = true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* 本来重载rowsInserted函数用于在插入新行后自动选中最后一行,
|
||||
但是,在关联Model的insertRow执行后rowsInserted会被立即执行,
|
||||
此时,Model的setData还未被执行,会选中一个空行。
|
||||
所以不再采用这种方式,而是在控制模块中指定。*/
|
||||
void rowsInserted(const QModelIndex &parent, int start, int end) {
|
||||
// 调用父类函数,为使滚动条更新,否则scrollToBottom不能正确执行。
|
||||
QListView::rowsInserted(parent, start, end);
|
||||
QModelIndex color = model()->square(end, 0);
|
||||
setCurrentIndex(color);
|
||||
scrollToBottom();
|
||||
}
|
||||
#endif
|
||||
|
||||
// 采用判断最后一个元素是否改变来选中之
|
||||
// Select by judging whether the last element has changed
|
||||
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
|
||||
const QVector<int> &roles = QVector<int>()) override
|
||||
{
|
||||
// 调用父类默认函数
|
||||
QListView::dataChanged(topLeft, bottomRight, roles);
|
||||
|
||||
// 如果包含model
|
||||
if (model()) {
|
||||
// 判断
|
||||
const QModelIndex square = model()->index(model()->rowCount() - 1, 0);
|
||||
if (square == bottomRight && newEmptyRow) {
|
||||
setCurrentIndex(square);
|
||||
|
@ -107,8 +91,10 @@ protected slots:
|
|||
}
|
||||
}
|
||||
|
||||
// 需要一个currentChanged信号,但默认没有,需要把这个槽改造成信号
|
||||
// activated信号需要按下回车才发出,selectedChanged和clicked信号也不合适
|
||||
// A currentChanged signal is required, but not by default.
|
||||
// This slot needs to be transformed into a signal
|
||||
// The activated signal needs to press enter to send out,
|
||||
// and the selectedChanged and clicked signals are not appropriate
|
||||
void currentChanged(const QModelIndex ¤t, const QModelIndex &previous) override
|
||||
{
|
||||
QListView::currentChanged(current, previous);
|
||||
|
@ -116,7 +102,7 @@ protected slots:
|
|||
}
|
||||
|
||||
private:
|
||||
// 添加了新空行的标识
|
||||
// The identity of the new blank line is added
|
||||
bool newEmptyRow {false};
|
||||
};
|
||||
|
||||
|
|
|
@ -27,44 +27,33 @@ PieceItem::PieceItem(QGraphicsItem *parent) :
|
|||
num(0)
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
// 允许选择和移动
|
||||
setFlags(ItemIsSelectable
|
||||
// | ItemIsMovable
|
||||
);
|
||||
|
||||
// 设置缓存模式
|
||||
setCacheMode(DeviceCoordinateCache);
|
||||
|
||||
// 鼠标放在棋子上时显示为伸开的手形
|
||||
setCursor(Qt::OpenHandCursor);
|
||||
|
||||
// 只接受左键事件
|
||||
//setAcceptedMouseButtons(Qt::LeftButton);
|
||||
|
||||
// 不接受鼠标事件
|
||||
setAcceptedMouseButtons(nullptr);
|
||||
//setAcceptHoverEvents(true);
|
||||
|
||||
// 默认模型为没有棋子
|
||||
model = Models::noPiece;
|
||||
|
||||
// 棋子尺寸
|
||||
size = PIECE_SIZE;
|
||||
|
||||
// 选中子标识线宽度
|
||||
selectLineWeight = LINE_WEIGHT;
|
||||
|
||||
// 删除线宽度
|
||||
removeLineWeight = LINE_WEIGHT * 5;
|
||||
|
||||
// 选中线为黄色
|
||||
#ifdef MOBILE_APP_UI
|
||||
selectLineColor = Qt::gray;
|
||||
#else
|
||||
selectLineColor = Qt::darkYellow;
|
||||
#endif /* MOBILE_APP_UI */
|
||||
|
||||
// 删除线颜色
|
||||
removeLineColor = QColor(227, 23, 13);
|
||||
removeLineColor.setAlphaF(0.9);
|
||||
}
|
||||
|
@ -90,11 +79,11 @@ void PieceItem::paint(QPainter *painter,
|
|||
Q_UNUSED(option)
|
||||
Q_UNUSED(widget)
|
||||
|
||||
// 空模型不画棋子
|
||||
// Empty models don't draw pieces
|
||||
|
||||
switch (model) {
|
||||
case Models::blackPiece:
|
||||
// 如果模型为黑色,则画黑色棋子
|
||||
// If the model is black, draw black pieces
|
||||
#ifdef MOBILE_APP_UI
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(QColor(0, 93, 172));
|
||||
|
@ -106,7 +95,7 @@ void PieceItem::paint(QPainter *painter,
|
|||
break;
|
||||
|
||||
case Models::whitePiece:
|
||||
// 如果模型为白色,则画白色棋子
|
||||
// If the model is white, draw white pieces
|
||||
#ifdef MOBILE_APP_UI
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(QColor(231, 36, 46));
|
||||
|
@ -120,29 +109,25 @@ void PieceItem::paint(QPainter *painter,
|
|||
break;
|
||||
}
|
||||
|
||||
// 如果模型要求显示序号
|
||||
// If the model requires the serial number to be displayed
|
||||
if (showNum) {
|
||||
// 如果模型为黑色,用白色笔画序号
|
||||
if (model == Models::blackPiece)
|
||||
painter->setPen(QColor(255, 255, 255));
|
||||
|
||||
// 如果模型为白色,用白色笔画序号
|
||||
if (model == Models::whitePiece)
|
||||
painter->setPen(QColor(0, 0, 0));
|
||||
|
||||
// 字体
|
||||
QFont font;
|
||||
font.setFamily("Arial");
|
||||
font.setPointSize(size / 3);
|
||||
painter->setFont(font);
|
||||
|
||||
// 画序号,默认中间位置偏下,需微调
|
||||
painter->drawText(boundingRect().adjusted(0, 0, 0, -size / 12),
|
||||
Qt::AlignCenter, QString::number(num));
|
||||
|
||||
}
|
||||
|
||||
// 如果模型为选中状态,则画上四个小直角
|
||||
// If the model is selected, draw four small right angles
|
||||
if (isSelected()) {
|
||||
QPen pen(selectLineColor, selectLineWeight, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin);
|
||||
painter->setPen(pen);
|
||||
|
@ -158,7 +143,7 @@ void PieceItem::paint(QPainter *painter,
|
|||
painter->drawLine(-xy, xy, -xy / 2, xy);
|
||||
}
|
||||
|
||||
// 如果模型为删除状态,则画上叉号
|
||||
// If the model is deleted, cross it
|
||||
if (deleted) {
|
||||
QPen pen(removeLineColor, removeLineWeight, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin);
|
||||
painter->setPen(pen);
|
||||
|
@ -170,7 +155,7 @@ void PieceItem::paint(QPainter *painter,
|
|||
|
||||
void PieceItem::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
|
||||
{
|
||||
// 鼠标按下时变为握住的手形
|
||||
// When the mouse is pressed, it becomes the shape of the hand it holds
|
||||
setCursor(Qt::ClosedHandCursor);
|
||||
QGraphicsItem::mousePressEvent(mouseEvent);
|
||||
}
|
||||
|
@ -182,7 +167,7 @@ void PieceItem::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
|
|||
|
||||
void PieceItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
|
||||
{
|
||||
// 鼠标松开时变为伸开的手形
|
||||
// When the mouse is released, it becomes an extended hand
|
||||
setCursor(Qt::OpenHandCursor);
|
||||
QGraphicsItem::mouseReleaseEvent(mouseEvent);
|
||||
}
|
||||
|
|
|
@ -28,8 +28,6 @@ class PieceItem : public QObject, public QGraphicsItem
|
|||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(QGraphicsItem)
|
||||
|
||||
// 位置属性
|
||||
Q_PROPERTY(QPointF pos READ pos WRITE setPos)
|
||||
|
||||
public:
|
||||
|
@ -44,8 +42,10 @@ public:
|
|||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||
QWidget *widget = nullptr) override;
|
||||
|
||||
// 用UserType+2表示棋子,用qgraphicsitem_cast()判断是否为PieceItem类的对象
|
||||
// 还有一个方式是把类名放在Data的0key位置setData(0, "PieceItem"),然后用data(0)来判断
|
||||
// Use UserType + 2 to represent pieces,
|
||||
// and use qgraphicsitems_cast() determines whether it is an object of the pieceitem class
|
||||
// Another way is to put the class name in the 0key position of data,
|
||||
// setData(0, "pieceitem"), and then use data(0) to judge
|
||||
enum
|
||||
{
|
||||
Type = UserType + 2
|
||||
|
@ -56,12 +56,11 @@ public:
|
|||
return Type;
|
||||
}
|
||||
|
||||
// 模型状态枚举,用位运算标明
|
||||
enum class Models
|
||||
{
|
||||
noPiece = 0x1, // 空棋子
|
||||
blackPiece = 0x2, // 黑色棋子
|
||||
whitePiece = 0x4, // 白色棋子
|
||||
noPiece = 0x1,
|
||||
blackPiece = 0x2,
|
||||
whitePiece = 0x4,
|
||||
};
|
||||
|
||||
enum Models getModel() noexcept
|
||||
|
@ -110,31 +109,24 @@ protected:
|
|||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) override;
|
||||
|
||||
private:
|
||||
// 棋子本质
|
||||
enum Models model;
|
||||
|
||||
// 棋子序号,黑白都从1开始
|
||||
// Piece number, black and white all start from 1
|
||||
int num {1};
|
||||
|
||||
// 棋子尺寸
|
||||
int size {0};
|
||||
|
||||
// 有无删除线
|
||||
// Is there a delete line
|
||||
bool deleted {false};
|
||||
|
||||
// 显示序号
|
||||
bool showNum {false};
|
||||
|
||||
// 选中子标识线宽度
|
||||
int selectLineWeight {0};
|
||||
|
||||
// 删除线宽度
|
||||
int removeLineWeight {0};
|
||||
|
||||
// 选中线颜色
|
||||
QColor selectLineColor;
|
||||
|
||||
// 删除线颜色
|
||||
QColor removeLineColor;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue