添加命令行时间参数,删除界面tabWidget
This commit is contained in:
parent
b95e6b276b
commit
2f8fbab50a
16
History.txt
16
History.txt
|
@ -1,8 +1,12 @@
|
|||
九连棋 NineChess
|
||||
更新历史:
|
||||
2018/5/19 V1.0
|
||||
1. Qt5.10.1+MSVC2017重构;
|
||||
2. 游戏可以正确运行,实现本机对战功能,其它功能待完善。
|
||||
涔濊繛妫?NineChess
|
||||
鏇存柊鍘嗗彶锛?
|
||||
2018/6/10 V0.3
|
||||
1. 淇敼绠楁硶涓婄殑bug锛?
|
||||
2. 娣诲姞鍛戒护琛岃В鏋愬姛鑳姐€?
|
||||
|
||||
2018/5/19 V0.2
|
||||
1. Qt5.10.1+MSVC2017閲嶆瀯锛?
|
||||
2. 娓告垙鍙互姝g‘杩愯锛屽疄鐜版湰鏈哄鎴樺姛鑳斤紝鍏跺畠鍔熻兘寰呭畬鍠勩€?
|
||||
|
||||
2015/11/6 V0.1
|
||||
1. 无算法只有界面的程序。
|
||||
1. 鏃犵畻娉曞彧鏈夌晫闈㈢殑绋嬪簭銆?
|
||||
|
|
11
Licence.txt
11
Licence.txt
|
@ -1,15 +1,10 @@
|
|||
本软件代码遵循LGPL v3协议,其中:
|
||||
1. 对于Qt库,遵循GPL协议。任何人都可以免费使用,但必须保持其开源;
|
||||
2. 对于原作者自行开发的代码:
|
||||
2.1 未经原作者书面授权,任何人不得修改、传播;
|
||||
2.2 获得原作者书面授权免费使用者:
|
||||
2.2.1 其修改版必须对原作者开源;
|
||||
2.2.2 其修改版必须完整保留本Licence文件,如需新增内容,只能在原版Licence文件中追加;
|
||||
2.2.3 原作者对其修改版在保留修改者署名情况下,有修改、传播及无偿商业化使用的权利;
|
||||
2.3 获得原作者书面授权收费使用者,按照双方书面协议执行。
|
||||
2.1 任何人可以不经原作者授权,使用、修改和分发此代码,但必须保持LGPL v3协议;
|
||||
2.2 获得原作者商业授权者,按照双方书面协议执行。
|
||||
|
||||
本软件的可执行文件:
|
||||
1. Qt库文件归Qt版权方所有;
|
||||
2. 原作者、代码免费使用者的可执行文件,任何人可以免费使用、传播,但不得反汇编、修改,不得商用及其它违法用途。
|
||||
3. 获得原作者书面授权收费使用者,按照双方书面协议执行。
|
||||
2. 其余可执行文件,任何人可以免费使用、传播,但不得反汇编、修改,不得商用及其它违法用途。
|
||||
—— by liuweilhy 2018.05.21
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#-------------------------------------------------
|
||||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2015-11-03T22:30:34
|
||||
#
|
||||
|
@ -31,7 +31,6 @@ HEADERS += \
|
|||
src\boarditem.h \
|
||||
src\gameview.h \
|
||||
src\ninechess.h \
|
||||
src\sizehinttextedit.h \
|
||||
src\sizehintlistview.h \
|
||||
src\gamescene.h
|
||||
|
||||
|
|
|
@ -240,7 +240,6 @@
|
|||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">release\moc_predefs.h;%(Outputs)</Outputs>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</CustomBuild>
|
||||
<ClInclude Include="src\sizehinttextedit.h" />
|
||||
<ClInclude Include="ui_ninechesswindow.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -110,9 +110,6 @@
|
|||
<ClInclude Include="src\sizehintlistview.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\sizehinttextedit.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="debug\moc_predefs.h.cbt">
|
||||
|
|
|
@ -379,54 +379,17 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="SizeHintListView" name="listView">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>7</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="tabPosition">
|
||||
<enum>QTabWidget::South</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="SizeHintTextEdit" name="tab_Rule">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>8</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>规则</string>
|
||||
</attribute>
|
||||
<layout class="QFormLayout" name="formLayout"/>
|
||||
</widget>
|
||||
<widget class="SizeHintListView" name="tab_Manual">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>棋谱</string>
|
||||
</attribute>
|
||||
<layout class="QFormLayout" name="formLayout"/>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -855,11 +818,6 @@
|
|||
<extends>QListView</extends>
|
||||
<header>sizehintlistview.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>SizeHintTextEdit</class>
|
||||
<extends>QPlainTextEdit</extends>
|
||||
<header>sizehinttextedit.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="ninechesswindow.qrc"/>
|
||||
|
|
|
@ -141,7 +141,7 @@ void GameController::setInvert(bool arg)
|
|||
}
|
||||
}
|
||||
|
||||
void GameController::setRule(int ruleNo)
|
||||
void GameController::setRule(int ruleNo, int stepLimited /*= -1*/, int timeLimited /*= -1*/)
|
||||
{
|
||||
// 停止计时器
|
||||
if (timeID != 0)
|
||||
|
@ -149,10 +149,13 @@ void GameController::setRule(int ruleNo)
|
|||
// 定时器ID为0
|
||||
timeID = 0;
|
||||
|
||||
// 更新规则,原限时和限步不变
|
||||
// 更新规则,原限时和限步不变
|
||||
if (ruleNo < 0 || ruleNo >= NineChess::RULENUM)
|
||||
return;
|
||||
if (stepLimited != -1 && timeLimited != -1) {
|
||||
stepsLimit = stepLimited;
|
||||
timeLimit = timeLimited;
|
||||
}
|
||||
// 设置模型规则,重置游戏
|
||||
chess.setData(&NineChess::RULES[ruleNo], stepsLimit, timeLimit);
|
||||
|
||||
|
@ -177,50 +180,10 @@ void GameController::setRule(int ruleNo)
|
|||
QTime qtime = QTime(0, 0, 0, 0).addMSecs(time1);
|
||||
emit time1Changed(qtime.toString("mm:ss.zzz"));
|
||||
emit time2Changed(qtime.toString("mm:ss.zzz"));
|
||||
// 发信号更新状态栏
|
||||
message = QString::fromStdString(chess.getTip());
|
||||
emit statusBarChanged(message);
|
||||
// 播放音效
|
||||
playSound(soundNewgame);
|
||||
}
|
||||
|
||||
void GameController::setRule(int ruleNo, int stepLimited, int timeLimited)
|
||||
{
|
||||
// 停止计时器
|
||||
if (timeID != 0)
|
||||
killTimer(timeID);
|
||||
// 定时器ID为0
|
||||
timeID = 0;
|
||||
|
||||
// 更新规则,原限时和限步不变
|
||||
if (ruleNo < 0 || ruleNo >= NineChess::RULENUM)
|
||||
return;
|
||||
stepsLimit = stepLimited;
|
||||
timeLimit = timeLimited;
|
||||
// 设置模型规则,重置游戏
|
||||
chess.setData(&NineChess::RULES[ruleNo], stepsLimit, timeLimit);
|
||||
|
||||
// 清除棋子
|
||||
qDeleteAll(pieceList);
|
||||
pieceList.clear();
|
||||
piece = NULL;
|
||||
// 重新绘制棋盘
|
||||
scene.setDiagonal(chess.getRule()->hasObliqueLine);
|
||||
|
||||
// 如果规则不要求计时,则time1和time2表示已用时间
|
||||
if (timeLimit <= 0) {
|
||||
// 将玩家的已用时间清零
|
||||
time1 = time2 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 将玩家的剩余时间置为限定时间
|
||||
time1 = time2 = timeLimit * 60000;
|
||||
}
|
||||
// 发出信号通知主窗口更新LCD显示
|
||||
QTime qtime = QTime(0, 0, 0, 0).addMSecs(time1);
|
||||
emit time1Changed(qtime.toString("mm:ss.zzz"));
|
||||
emit time2Changed(qtime.toString("mm:ss.zzz"));
|
||||
// 更新棋谱
|
||||
manualListModel.removeRows(0, manualListModel.rowCount());
|
||||
manualListModel.insertRow(0);
|
||||
manualListModel.setData(manualListModel.index(0), chess.getCmdLine());
|
||||
// 发信号更新状态栏
|
||||
message = QString::fromStdString(chess.getTip());
|
||||
emit statusBarChanged(message);
|
||||
|
@ -328,9 +291,6 @@ bool GameController::actionPiece(QPointF pos)
|
|||
case NineChess::GAME_NOTSTARTED:
|
||||
// 如果未开局则开局,这里还要继续判断,不可break
|
||||
gameStart();
|
||||
manualListModel.setStringList(QStringList());
|
||||
manualListModel.insertRow(0);
|
||||
manualListModel.setData(manualListModel.index(0), chess.getCmdLine());
|
||||
|
||||
case NineChess::GAME_OPENING:
|
||||
// 如果是开局阶段(轮流落下新子),落子
|
||||
|
@ -353,7 +313,8 @@ bool GameController::actionPiece(QPointF pos)
|
|||
}// 移子
|
||||
else if (chess.getAction() == NineChess::ACTION_PLACE) {
|
||||
// 如果移子不成功,尝试重新选子
|
||||
if (!movePiece(pos))
|
||||
result = movePiece(pos);
|
||||
if (!result)
|
||||
result = choosePiece(pos);
|
||||
}// 去子
|
||||
else if (chess.getAction() == NineChess::ACTION_REMOVE) {
|
||||
|
@ -368,18 +329,16 @@ bool GameController::actionPiece(QPointF pos)
|
|||
|
||||
if (result)
|
||||
{
|
||||
manualListModel.insertRow(manualListModel.rowCount());
|
||||
int row = manualListModel.rowCount();
|
||||
manualListModel.setData(manualListModel.index(row-1), chess.getCmdLine());
|
||||
if (chess.whoWin() != NineChess::NOBODY) {
|
||||
// 取胜时,会连续出2个命令行,需要将前一个插入
|
||||
if (row < chess.getCmdList()->size()) {
|
||||
manualListModel.insertRow(row-1);
|
||||
auto i = (chess.getCmdList())->rbegin();
|
||||
manualListModel.setData(manualListModel.index(row - 1), (*(++i)).c_str());
|
||||
}
|
||||
playSound(soundWin);
|
||||
int size = chess.getCmdList()->size();
|
||||
auto i = (chess.getCmdList())->rbegin();
|
||||
// 输出命令行
|
||||
for (int n = size - row; n > 0; n--) {
|
||||
manualListModel.insertRow(row);
|
||||
manualListModel.setData(manualListModel.index(row), (*(i++)).c_str());
|
||||
}
|
||||
if (chess.whoWin() != NineChess::NOBODY)
|
||||
playSound(soundWin);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -536,7 +495,7 @@ bool GameController::removePiece(QPointF pos)
|
|||
|
||||
bool GameController::cleanForbidden()
|
||||
{
|
||||
foreach (PieceItem *p, pieceList)
|
||||
foreach(PieceItem *p, pieceList)
|
||||
{
|
||||
if (p->isDeleted()) {
|
||||
pieceList.removeOne(p);
|
||||
|
|
|
@ -52,10 +52,8 @@ public slots:
|
|||
void setEditing(bool arg = true);
|
||||
// 设置黑白反转状态
|
||||
void setInvert(bool arg = true);
|
||||
// 设置规则,不改变限时限步
|
||||
void setRule(int ruleNo);
|
||||
// 设置规则,改变限时限步
|
||||
void setRule(int ruleNo, int stepLimited, int timeLimited);
|
||||
// 设置规则
|
||||
void setRule(int ruleNo, int stepLimited = -1, int timeLimited = -1);
|
||||
// 让电脑执先手
|
||||
void setEngine1(bool arg = true);
|
||||
// 让电脑执后手
|
||||
|
|
|
@ -296,6 +296,22 @@ bool NineChess::setData(const struct Rule *rule, int s, int t, int step, int fla
|
|||
// 提示
|
||||
setTip();
|
||||
|
||||
// 计棋谱
|
||||
cmdlist.clear();
|
||||
int i;
|
||||
for (i = 0; i < RULENUM; i++) {
|
||||
if (strcmp(this->rule.name, RULES[i].name) == 0)
|
||||
break;
|
||||
}
|
||||
if (sprintf(cmdline, "r%1u s%03u t%02u", i + 1, s, t) > 0) {
|
||||
cmdlist.push_back(string(cmdline));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
cmdline[0] = '\0';
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -331,21 +347,6 @@ bool NineChess::start()
|
|||
phase = GAME_OPENING;
|
||||
// 启动计时器
|
||||
ftime(&startTimeb);
|
||||
// 计棋谱
|
||||
cmdlist.clear();
|
||||
int i;
|
||||
for (i = 0; i < RULENUM; i++) {
|
||||
if (strcmp(rule.name, RULES[i].name) == 0)
|
||||
break;
|
||||
}
|
||||
if (sprintf(cmdline, "r%1d s%03d t%02d", i + 1, rule.maxSteps, rule.maxTime) > 0) {
|
||||
cmdlist.push_back(string(cmdline));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
cmdline[0] = '\0';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 其它情况
|
||||
|
@ -359,7 +360,7 @@ int NineChess::cp2pos(int c, int p)
|
|||
return c * SEAT + p - 1;
|
||||
}
|
||||
|
||||
bool NineChess::place(int c, int p)
|
||||
bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
||||
{
|
||||
// 如果局面为"未开局"或“结局”,返回false
|
||||
if (phase == GAME_NOTSTARTED || phase == GAME_OVER)
|
||||
|
@ -371,6 +372,8 @@ bool NineChess::place(int c, int p)
|
|||
int pos = cp2pos(c, p);
|
||||
if (!inBoard[pos] || board[pos])
|
||||
return false;
|
||||
// 时间的临时变量
|
||||
long player_ms = -1;
|
||||
|
||||
// 对于开局落子
|
||||
char piece = '\x00';
|
||||
|
@ -392,7 +395,8 @@ bool NineChess::place(int c, int p)
|
|||
player2_InHand--;
|
||||
player2_Remain++;
|
||||
}
|
||||
sprintf(cmdline, "(%1d,%1d)", c, p);
|
||||
player_ms = update(time_p);
|
||||
sprintf(cmdline, "(%1u,%1u) %02u:%02u.%03u", c, p, player_ms / 60000, player_ms / 1000, player_ms % 1000);
|
||||
cmdlist.push_back(string(cmdline));
|
||||
posOfSelected = pos;
|
||||
step++;
|
||||
|
@ -438,7 +442,6 @@ bool NineChess::place(int c, int p)
|
|||
num_NeedRemove = rule.removeMore ? n : 1;
|
||||
// 进入去子状态
|
||||
action = ACTION_REMOVE;
|
||||
setTip();
|
||||
}
|
||||
setTip();
|
||||
return true;
|
||||
|
@ -459,7 +462,9 @@ bool NineChess::place(int c, int p)
|
|||
return false;
|
||||
}
|
||||
// 移子
|
||||
sprintf(cmdline, "(%1d,%1d)->(%1d,%1d)", posOfSelected / RING, posOfSelected % RING + 1, c, p);
|
||||
player_ms = update(time_p);
|
||||
sprintf(cmdline, "(%1u,%1u)->(%1u,%1u) %02u:%02u.%03u", posOfSelected / SEAT, posOfSelected % SEAT + 1,
|
||||
c, p, player_ms / 60000, player_ms / 1000, player_ms % 1000);
|
||||
cmdlist.push_back(string(cmdline));
|
||||
board[pos] = board[posOfSelected];
|
||||
board[posOfSelected] = '\x00';
|
||||
|
@ -494,7 +499,7 @@ bool NineChess::place(int c, int p)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool NineChess::remove(int c, int p)
|
||||
bool NineChess::remove(int c, int p, long time_p /* = -1*/)
|
||||
{
|
||||
// 如果局面为"未开局"或“结局”,返回false
|
||||
if (phase == GAME_NOTSTARTED || phase == GAME_OVER)
|
||||
|
@ -505,6 +510,8 @@ bool NineChess::remove(int c, int p)
|
|||
// 如果去子完成,返回false
|
||||
if (num_NeedRemove <= 0)
|
||||
return false;
|
||||
// 时间的临时变量
|
||||
long player_ms = -1;
|
||||
int pos = cp2pos(c, p);
|
||||
// 对手
|
||||
enum Player opponent = PLAYER2;
|
||||
|
@ -528,7 +535,8 @@ bool NineChess::remove(int c, int p)
|
|||
player2_Remain--;
|
||||
else if (turn == PLAYER2)
|
||||
player1_Remain--;
|
||||
sprintf(cmdline, "-(%1d,%1d)", c, p);
|
||||
player_ms = update(time_p);
|
||||
sprintf(cmdline, "-(%1u,%1u) %02u:%02u.%03u", c, p, player_ms / 60000, player_ms / 1000, player_ms % 1000);
|
||||
cmdlist.push_back(string(cmdline));
|
||||
posOfSelected = 0;
|
||||
num_NeedRemove--;
|
||||
|
@ -630,78 +638,101 @@ bool NineChess::choose(int c, int p)
|
|||
return false;
|
||||
}
|
||||
|
||||
// 打算用个C++的命令行解析库的,简单的没必要,但中文编码有极小
|
||||
// 打算用个C++的命令行解析库的,简单的没必要,但中文编码有极小概率出问题
|
||||
bool NineChess::command(const char *cmd)
|
||||
{
|
||||
int r, s, t;
|
||||
int c1, p1, c2, p2;
|
||||
int args = 0;
|
||||
int mm = 0, ss = 0, mss = 0;
|
||||
long tm = -1;
|
||||
|
||||
// 设置规则
|
||||
if (sscanf(cmd, "r%d s%d t%d", &r, &s, &t) == 3) {
|
||||
if (sscanf(cmd, "r%1u s%3u t%2u", &r, &s, &t) == 3) {
|
||||
if (r <= 0 || r > RULENUM)
|
||||
return false;
|
||||
return setData(&NineChess::RULES[r - 1], s, t);
|
||||
}
|
||||
|
||||
// 选子移动
|
||||
else if (sscanf(cmd, "(%d,%d)->(%d,%d)", &c1, &p1, &c2, &p2) == 4) {
|
||||
args = sscanf(cmd, "(%1u,%1u)->(%1u,%1u) %2u:%2u.%3u", &c1, &p1, &c2, &p2, &mm, &ss, &mss);
|
||||
if (args >= 4) {
|
||||
if (args == 7) {
|
||||
if (mm >= 0 && ss >= 0 && mss >= 0)
|
||||
tm = mm * 60000 + ss * 1000 + mss;
|
||||
}
|
||||
if (choose(c1, p1))
|
||||
return place(c2, p2);
|
||||
return place(c2, p2, tm);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// 去子
|
||||
else if (sscanf(cmd, "-(%d,%d)", &c1, &p1) == 2) {
|
||||
return remove(c1, p1);
|
||||
args = sscanf(cmd, "-(%1u,%1u) %2u:%2u.%3u", &c1, &p1, &mm, &ss, &mss);
|
||||
if (args >= 2) {
|
||||
if (args == 5) {
|
||||
if (mm >= 0 && ss >= 0 && mss >= 0)
|
||||
tm = mm * 60000 + ss * 1000 + mss;
|
||||
}
|
||||
return remove(c1, p1, tm);
|
||||
}
|
||||
|
||||
// 落子
|
||||
else if (sscanf(cmd, "(%d,%d)", &c1, &p1) == 2) {
|
||||
return place(c1, p1);
|
||||
args = sscanf(cmd, "(%1u,%1u) %2u:%2u.%3u", &c1, &p1, &mm, &ss, &mss);
|
||||
if (args >= 2) {
|
||||
if (args == 5) {
|
||||
if (mm >= 0 && ss >= 0 && mss >= 0)
|
||||
tm = mm * 60000 + ss * 1000 + mss;
|
||||
}
|
||||
return place(c1, p1, tm);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool NineChess::update()
|
||||
inline long NineChess::update(long time_p /*= -1*/)
|
||||
{
|
||||
long ret = -1;
|
||||
long *player_ms = (turn == PLAYER1 ? &player1_MS : &player2_MS);
|
||||
long playerNext_ms = (turn == PLAYER1 ? player2_MS : player1_MS);
|
||||
|
||||
// 根据局面调整计时器
|
||||
switch (phase)
|
||||
{
|
||||
case NineChess::GAME_OPENING:
|
||||
case NineChess::GAME_MID:
|
||||
ftime(¤tTimeb);
|
||||
// 超时胜负判断
|
||||
if (turn == PLAYER1) {
|
||||
player1_MS = (long)(currentTimeb.time - startTimeb.time) * 1000
|
||||
+ (currentTimeb.millitm - startTimeb.millitm) - player2_MS;
|
||||
// 如果玩家1超时
|
||||
if (rule.maxTime > 0 && player1_MS > rule.maxTime * 60000) {
|
||||
player1_MS = rule.maxTime * 60000;
|
||||
winner = PLAYER2;
|
||||
phase = GAME_OVER;
|
||||
tip = "玩家1超时,恭喜玩家2获胜";
|
||||
// 更新时间
|
||||
if (time_p >= *player_ms)
|
||||
{
|
||||
*player_ms = ret = time_p;
|
||||
long t = player1_MS + player2_MS;
|
||||
if (t % 1000 <= currentTimeb.millitm)
|
||||
{
|
||||
startTimeb.time = currentTimeb.time - (t / 1000);
|
||||
startTimeb.millitm = currentTimeb.millitm - (t % 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
startTimeb.time = currentTimeb.time - (t / 1000) - 1;
|
||||
startTimeb.millitm = currentTimeb.millitm + 1000 - (t % 1000);
|
||||
}
|
||||
}
|
||||
else if (turn == PLAYER2) {
|
||||
player2_MS = (long)(currentTimeb.time - startTimeb.time) * 1000
|
||||
+ (currentTimeb.millitm - startTimeb.millitm) - player1_MS;
|
||||
// 如果玩家2超时
|
||||
if (rule.maxTime > 0 && player2_MS > rule.maxTime * 60000) {
|
||||
player2_MS = rule.maxTime * 60000;
|
||||
winner = PLAYER1;
|
||||
phase = GAME_OVER;
|
||||
tip = "玩家2超时,恭喜玩家1获胜";
|
||||
}
|
||||
else
|
||||
{
|
||||
*player_ms = ret = (long)(currentTimeb.time - startTimeb.time) * 1000
|
||||
+ (currentTimeb.millitm - startTimeb.millitm) - playerNext_ms;
|
||||
}
|
||||
return true;
|
||||
// 有限时要求则判断胜负
|
||||
if (rule.maxTime > 0)
|
||||
win();
|
||||
return ret;
|
||||
case NineChess::GAME_NOTSTARTED:
|
||||
return true;
|
||||
return ret;
|
||||
case NineChess::GAME_OVER:
|
||||
return true;
|
||||
return ret;
|
||||
default:
|
||||
return true;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -715,10 +746,24 @@ bool NineChess::win()
|
|||
|
||||
// 如果有时间限定
|
||||
if (rule.maxTime > 0) {
|
||||
// 更新时间,判断胜负
|
||||
update();
|
||||
if (winner != NOBODY) {
|
||||
sprintf(cmdline, "Time over. Player%1d win!", winner == PLAYER1 ? 1 : 2);
|
||||
// 这里不能update更新时间,否则会形成循环嵌套
|
||||
// 如果玩家1超时
|
||||
if (player1_MS > rule.maxTime * 60000) {
|
||||
player1_MS = rule.maxTime * 60000;
|
||||
winner = PLAYER2;
|
||||
phase = GAME_OVER;
|
||||
tip = "玩家1超时,恭喜玩家2获胜!";
|
||||
sprintf(cmdline, "Time over. Player2 win!");
|
||||
cmdlist.push_back(string(cmdline));
|
||||
return true;
|
||||
}
|
||||
// 如果玩家2超时
|
||||
else if (player2_MS > rule.maxTime * 60000) {
|
||||
player2_MS = rule.maxTime * 60000;
|
||||
winner = PLAYER1;
|
||||
phase = GAME_OVER;
|
||||
tip = "玩家2超时,恭喜玩家1获胜!";
|
||||
sprintf(cmdline, "Time over. Player1 win!");
|
||||
cmdlist.push_back(string(cmdline));
|
||||
return true;
|
||||
}
|
||||
|
@ -782,7 +827,7 @@ bool NineChess::win()
|
|||
}
|
||||
// 否则让棋,由对手走
|
||||
else
|
||||
{
|
||||
{
|
||||
changeTurn();
|
||||
return false;
|
||||
}
|
||||
|
@ -854,7 +899,7 @@ int NineChess::addMills(int pos)
|
|||
// 迭代器
|
||||
list<long long>::iterator itor;
|
||||
// 遍历
|
||||
for ( itor = millList.begin(); itor != millList.end(); itor++)
|
||||
for (itor = millList.begin(); itor != millList.end(); itor++)
|
||||
{
|
||||
if (mill == *itor)
|
||||
break;
|
||||
|
|
|
@ -145,9 +145,9 @@ public:
|
|||
// 选子,在第c圈第p个位置,为迎合日常,c和p下标都从1开始
|
||||
bool choose(int c, int p);
|
||||
// 落子,在第c圈第p个位置,为迎合日常,c和p下标都从1开始
|
||||
bool place(int c, int p);
|
||||
bool place(int c, int p, long time_p = -1);
|
||||
// 去子,在第c圈第p个位置,为迎合日常,c和p下标都从1开始
|
||||
bool remove(int c, int p);
|
||||
bool remove(int c, int p, long time_p = -1);
|
||||
// 命令行解析函数
|
||||
bool command(const char *cmd);
|
||||
|
||||
|
@ -165,7 +165,7 @@ protected:
|
|||
// 将第c圈,第p位转化为棋盘下标形式,c和p下标都从1开始
|
||||
int cp2pos(int c, int p);
|
||||
// 更新时间和状态,用内联函数以提高效率
|
||||
inline bool update();
|
||||
inline long update(long time_p = -1);
|
||||
// 是否分出胜负
|
||||
bool win();
|
||||
// 清除所有禁点
|
||||
|
|
|
@ -175,12 +175,11 @@ void NineChessWindow::initialize()
|
|||
// 重置游戏规则
|
||||
game->setRule(ruleNo);
|
||||
// 规则提示
|
||||
QString tip_Rule = QString("%1\n%2").arg(tr(NineChess::RULES[ruleNo].name))
|
||||
.arg(tr(NineChess::RULES[ruleNo].info));
|
||||
ui.tab_Rule->setPlainText(tip_Rule);
|
||||
//QString tip_Rule = QString("%1\n%2").arg(tr(NineChess::RULES[ruleNo].name))
|
||||
// .arg(tr(NineChess::RULES[ruleNo].info));
|
||||
|
||||
// 关联列表视图和字符串列表模型
|
||||
ui.tab_Manual->setModel(& game->manualListModel);
|
||||
ui.listView->setModel(& game->manualListModel);
|
||||
}
|
||||
|
||||
void NineChessWindow::actionRules_triggered()
|
||||
|
@ -196,9 +195,8 @@ void NineChessWindow::actionRules_triggered()
|
|||
// 重置游戏规则
|
||||
game->setRule(ruleNo);
|
||||
// 规则提示
|
||||
QString tip_Rule = QString("%1\n%2").arg(tr(NineChess::RULES[ruleNo].name))
|
||||
.arg(tr(NineChess::RULES[ruleNo].info));
|
||||
ui.tab_Rule->setPlainText(tip_Rule);
|
||||
//QString tip_Rule = QString("%1\n%2").arg(tr(NineChess::RULES[ruleNo].name))
|
||||
// .arg(tr(NineChess::RULES[ruleNo].info));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -16,12 +16,23 @@ class SizeHintListView : public QListView
|
|||
{
|
||||
public:
|
||||
SizeHintListView(QWidget * parent = 0) {}
|
||||
QSize sizeHint() const{
|
||||
QSize sizeHint() const {
|
||||
QSize size = QListView::sizeHint();
|
||||
// 缺省宽度设为128,这样就不太宽了
|
||||
size.setWidth(128);
|
||||
return size;
|
||||
}
|
||||
|
||||
protected:
|
||||
// 屏蔽掉双击编辑功能
|
||||
void mouseDoubleClickEvent(QMouseEvent *event) {}
|
||||
// 插入新行后自动选中最后一个
|
||||
void rowsInserted(const QModelIndex &parent, int start, int end) {
|
||||
QModelIndex id = model()->index(model()->rowCount()-1, 0);
|
||||
setCurrentIndex(id);
|
||||
update();
|
||||
scrollToBottom();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SIZEHINTLISTVIEW
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
/* QPlainTextEdit派生类
|
||||
* 之所以要派生这个类,重载sizeHint函数
|
||||
* 只是为了让停靠栏(父窗口)在初始时不至于过宽难看
|
||||
* QDockWidget没有很好的控制初始大小的方法,resize函数没效果
|
||||
* 如果不用派生类,使用固定宽度也可以,如下所示
|
||||
* this->setFixedWidth(108);
|
||||
* 但调节停靠栏宽度后就不好看了
|
||||
*/
|
||||
|
||||
#ifndef SIZEHINTTEXTEDIT
|
||||
#define SIZEHINTTEXTEDIT
|
||||
|
||||
#include <QPlainTextEdit>
|
||||
|
||||
class SizeHintTextEdit : public QPlainTextEdit
|
||||
{
|
||||
public:
|
||||
SizeHintTextEdit(QWidget * parent = 0) {}
|
||||
QSize sizeHint() const{
|
||||
QSize size = QPlainTextEdit::sizeHint();
|
||||
// 缺省宽度设为128,这样就不太宽了
|
||||
size.setWidth(128);
|
||||
return size;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SIZEHINTTEXTEDIT
|
||||
|
70
Readme.md
70
Readme.md
|
@ -1,43 +1,43 @@
|
|||
# 九联棋 NineChess
|
||||
# 涔濊仈妫?NineChess
|
||||
|
||||
#### 项目介绍:
|
||||
本游戏根据作者儿时游戏——“九联棋”编制,加上“成三棋”、“打三棋”和“莫里斯九子棋”,共三种规则玩法。
|
||||
三种规则略有差异,鼠标放在相应菜单项有会有详细的规则提示。
|
||||
#### 椤圭洰浠嬬粛锛?
|
||||
鏈父鎴忔牴鎹綔鑰呭効鏃舵父鎴忊€斺€斺€滀節鑱旀鈥濈紪鍒讹紝鍔犱笂鈥滄垚涓夋鈥濄€佲€滄墦涓夋鈥濆拰鈥滆帿閲屾柉涔濆瓙妫嬧€濓紝鍏变笁绉嶈鍒欑帺娉曘€?
|
||||
涓夌瑙勫垯鐣ユ湁宸紓锛岄紶鏍囨斁鍦ㄧ浉搴旇彍鍗曢」鏈変細鏈夎缁嗙殑瑙勫垯鎻愮ず銆?
|
||||
|
||||
#### 软件构架:
|
||||
+ GUI框架:Qt5.10,Qt5大版本下均可通用。
|
||||
+ 编译器:MSVC2017,MSVC2013及以上版本可用。
|
||||
+ 源文件编码:所有头文件(*.h)和源文件(*.cpp)采用UTF-8+BOM编码格式。pro文件等采用UTF-8无BOM编码。
|
||||
+ 本程序采用MVC(模型——视图——控制器)设计规范,对应类如下:
|
||||
#### 杞欢鏋勬灦锛?
|
||||
+ GUI妗嗘灦锛歈t5.10锛孮t5澶х増鏈笅鍧囧彲閫氱敤銆?
|
||||
+ 缂栬瘧鍣細MSVC2017锛孧SVC2013鍙婁互涓婄増鏈彲鐢ㄣ€?
|
||||
+ 婧愭枃浠剁紪鐮侊細鎵€鏈夊ご鏂囦欢(*.h)鍜屾簮鏂囦欢(*.cpp)閲囩敤UTF-8+BOM缂栫爜鏍煎紡銆俻ro鏂囦欢绛夐噰鐢║TF-8鏃燘OM缂栫爜銆?
|
||||
+ 鏈▼搴忛噰鐢∕VC锛堟ā鍨嬧€斺€旇鍥锯€斺€旀帶鍒跺櫒锛夎璁¤鑼冿紝瀵瑰簲绫诲涓嬶細
|
||||
```
|
||||
MVC
|
||||
├─Model
|
||||
│ └─NineChess:用标准C++写的棋类模型,处理下棋过程
|
||||
├─View
|
||||
│ ├─NineChessWindow:从QMainWindow派生的主窗口类,由Qt自动生成
|
||||
│ ├─SizeHintListView:从QListView派生的列表框
|
||||
│ ├─GameScene:从QGraphicsScene派生的场景类
|
||||
│ ├─GameView:从QGraphicsView派生的视图框
|
||||
│ ├─BoardItem:从QGraphicsItem派生的棋盘图形类
|
||||
│ └─PiecedItem:从QGraphicsItem派生的棋子图形类
|
||||
└─Controller
|
||||
└─GameController:从QObject派生的控制类
|
||||
鈹溾攢Model
|
||||
鈹? 鈹斺攢NineChess锛氱敤鏍囧噯C++鍐欑殑妫嬬被妯″瀷锛屽鐞嗕笅妫嬭繃绋?
|
||||
鈹溾攢View
|
||||
鈹? 鈹溾攢NineChessWindow锛氫粠QMainWindow娲剧敓鐨勪富绐楀彛绫伙紝鐢盦t鑷姩鐢熸垚
|
||||
鈹? 鈹溾攢SizeHintListView锛氫粠QListView娲剧敓鐨勫垪琛ㄦ
|
||||
鈹? 鈹溾攢GameScene锛氫粠QGraphicsScene娲剧敓鐨勫満鏅被
|
||||
鈹? 鈹溾攢GameView锛氫粠QGraphicsView娲剧敓鐨勮鍥炬
|
||||
鈹? 鈹溾攢BoardItem锛氫粠QGraphicsItem娲剧敓鐨勬鐩樺浘褰㈢被
|
||||
鈹? 鈹斺攢PiecedItem锛氫粠QGraphicsItem娲剧敓鐨勬瀛愬浘褰㈢被
|
||||
鈹斺攢Controller
|
||||
鈹斺攢GameController锛氫粠QObject娲剧敓鐨勬帶鍒剁被
|
||||
```
|
||||
+ 这个程序用到了很多Qt特性,其模式后期可以扩展到各种棋类游戏,适合初学者一看。
|
||||
+ 杩欎釜绋嬪簭鐢ㄥ埌浜嗗緢澶歈t鐗规€э紝鍏舵ā寮忓悗鏈熷彲浠ユ墿灞曞埌鍚勭妫嬬被娓告垙锛岄€傚悎鍒濆鑰呬竴鐪嬨€?
|
||||
|
||||
#### 许可协议
|
||||
参见Licence.txt
|
||||
#### 璁稿彲鍗忚
|
||||
鍙傝Licence.txt
|
||||
|
||||
#### 更新历史
|
||||
参见History.txt
|
||||
#### 鏇存柊鍘嗗彶
|
||||
鍙傝History.txt
|
||||
|
||||
#### 作者声明:
|
||||
多年前上大学那会儿,笔者就打算做这么个程序出来。然而,条件比较艰苦:
|
||||
一来没有老师教,课上只学了C语言和VB,C++是笔者自学的,一个人啃晦涩过时的MFC;
|
||||
二来我穷到连个电脑都没有……
|
||||
三嘛,就是贪玩……
|
||||
工作之后有条件了,我又自学了C#和Qt,但都很肤浅,没深入学,只用来做几个小工具而已。
|
||||
从5月末开始消沉到后来步入人生低谷,我终于有大把的时间来思考人生。
|
||||
风雨过后,我想起把时间用在兴趣爱好上。于是,这个小游戏诞生了!
|
||||
如果你发现本程序有什么问题或好的建议,请与本人联系。我的邮箱是:liuweilhy@163.com
|
||||
> ——by liuweilhy 2015年11月6日
|
||||
#### 浣滆€呭0鏄庯細
|
||||
澶氬勾鍓嶄笂澶у閭d細鍎匡紝绗旇€呭氨鎵撶畻鍋氳繖涔堜釜绋嬪簭鍑烘潵銆傜劧鑰岋紝鏉′欢姣旇緝鑹拌嫤锛?
|
||||
涓€鏉ユ病鏈夎€佸笀鏁欙紝璇句笂鍙浜咰璇█鍜孷B锛孋++鏄瑪鑰呰嚜瀛︾殑锛屼竴涓汉鍟冩櫐娑╄繃鏃剁殑MFC;
|
||||
浜屾潵鎴戠┓鍒拌繛涓數鑴戦兘娌℃湁鈥︹€?
|
||||
涓夊槢锛屽氨鏄椽鐜┾€︹€?
|
||||
宸ヤ綔涔嬪悗鏈夋潯浠朵簡锛屾垜鍙堣嚜瀛︿簡C#鍜孮t锛屼絾閮藉緢鑲ゆ祬锛屾病娣卞叆瀛︼紝鍙敤鏉ュ仛鍑犱釜灏忓伐鍏疯€屽凡銆?
|
||||
鍚庢潵娑堟矇杩囦竴娈垫椂闂达紝鎴戠粓浜庢湁澶ф妸鐨勬椂闂存潵鎬濊€冧汉鐢熴€?
|
||||
椋庨洦杩囧悗锛屾垜鎯宠捣鎶婃椂闂寸敤鍦ㄥ叴瓒g埍濂戒笂銆備簬鏄紝杩欎釜灏忔父鎴忚癁鐢熶簡锛?
|
||||
濡傛灉浣犲彂鐜版湰绋嬪簭鏈変粈涔堥棶棰樻垨濂界殑寤鸿锛岃涓庢湰浜鸿仈绯汇€傛垜鐨勯偖绠辨槸锛歭iuweilhy@163.com
|
||||
>銆€銆€銆€銆€銆€銆€銆€銆€銆€銆€鈥斺€攂y liuweilhy 2015骞?1鏈?鏃
|
Loading…
Reference in New Issue