rule: Support setting flying piece count
This commit is contained in:
parent
f886c72112
commit
1766e9577d
|
@ -139,7 +139,7 @@ Value Evaluation::value()
|
|||
piece_on_board_count_future_white -= pos.piece_to_remove_count();
|
||||
}
|
||||
|
||||
|
||||
// TODO: flyPieceCount?
|
||||
if (piece_on_board_count_future_black == 3 || piece_on_board_count_future_white == 3) {
|
||||
if (abs(value) < VALUE_KNOWN_WIN) {
|
||||
value = VALUE_DRAW;
|
||||
|
|
|
@ -530,13 +530,13 @@ Depth get_search_depth(const Position *pos)
|
|||
|
||||
// Can fly
|
||||
if (rule.mayFly) {
|
||||
if (pb == rule.piecesAtLeastCount ||
|
||||
pw == rule.piecesAtLeastCount) {
|
||||
if (pb <= rule.flyPieceCount ||
|
||||
pw <= rule.flyPieceCount) {
|
||||
d = flyingDepth;
|
||||
}
|
||||
|
||||
if (pb == rule.piecesAtLeastCount &&
|
||||
pw == rule.piecesAtLeastCount) {
|
||||
if (pb <= rule.flyPieceCount &&
|
||||
pw <= rule.flyPieceCount) {
|
||||
d = flyingDepth / 2;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,18 +52,17 @@ ExtMove *generate<MOVE>(Position &pos, ExtMove *moveList)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (pos.piece_on_board_count(pos.side_to_move()) > rule.piecesAtLeastCount ||
|
||||
!rule.mayFly) {
|
||||
for (auto direction = MD_BEGIN; direction < MD_NB; ++direction) {
|
||||
to = static_cast<Square>(MoveList<LEGAL>::adjacentSquares[from][direction]);
|
||||
if (to && !pos.get_board()[to]) {
|
||||
if (rule.mayFly && pos.piece_on_board_count(pos.side_to_move()) <= rule.flyPieceCount) {
|
||||
// piece count < 3 or 4 and allow fly, if is empty point, that's ok, do not need in move list
|
||||
for (to = SQ_BEGIN; to < SQ_END; ++to) {
|
||||
if (!pos.get_board()[to]) {
|
||||
*cur++ = make_move(from, to);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// piece count < 3 and allow fly, if is empty point, that's ok, do not need in move list
|
||||
for (to = SQ_BEGIN; to < SQ_END; ++to) {
|
||||
if (!pos.get_board()[to]) {
|
||||
for (auto direction = MD_BEGIN; direction < MD_NB; ++direction) {
|
||||
to = static_cast<Square>(MoveList<LEGAL>::adjacentSquares[from][direction]);
|
||||
if (to && !pos.get_board()[to]) {
|
||||
*cur++ = make_move(from, to);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -699,7 +699,7 @@ bool Position::put_piece(Square s, bool updateRecord)
|
|||
#endif // MUEHLE_NMM
|
||||
|
||||
// If illegal
|
||||
if (pieceOnBoardCount[sideToMove] > rule.piecesAtLeastCount ||
|
||||
if (pieceOnBoardCount[sideToMove] > rule.flyPieceCount ||
|
||||
!rule.mayFly) {
|
||||
if ((square_bb(s) & MoveList<LEGAL>::adjacentSquaresBB[currentSquare]) == 0) {
|
||||
return false;
|
||||
|
@ -1259,7 +1259,7 @@ bool Position::is_all_surrounded(Color c
|
|||
return true;
|
||||
|
||||
// Can fly
|
||||
if (pieceOnBoardCount[c] <= rule.piecesAtLeastCount &&
|
||||
if (pieceOnBoardCount[c] <= rule.flyPieceCount &&
|
||||
rule.mayFly) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ struct Rule rule = {
|
|||
// 规则说明
|
||||
"规则与成三棋基本相同,只是在走子阶段,当一方仅剩3子时,他可以飞子到任意空位。",
|
||||
9, // 双方各9子
|
||||
3, // 飞子条件为剩余3颗子
|
||||
3, // 赛点子数为3
|
||||
false, // 没有斜线
|
||||
false, // 没有禁点,摆棋阶段被提子的点可以再摆子
|
||||
|
@ -49,6 +50,7 @@ const struct Rule RULES[N_RULES] = {
|
|||
"6. 把对手棋子提到少于3颗时胜利;\n"
|
||||
"7. 走棋阶段不能行动(被“闷”)算负。",
|
||||
9, // 双方各9子
|
||||
3, // 飞子条件为剩余3颗子
|
||||
3, // 赛点子数为3
|
||||
false, // 没有斜线
|
||||
false, // 没有禁点,摆棋阶段被提子的点可以再摆子
|
||||
|
@ -70,6 +72,7 @@ const struct Rule RULES[N_RULES] = {
|
|||
"5. 同时出现两个“三连”只能提一子;\n"
|
||||
"6. 其它规则与成三棋基本相同。",
|
||||
12, // 双方各12子
|
||||
3, // 飞子条件为剩余3颗子
|
||||
3, // 赛点子数为3
|
||||
true, // 有斜线
|
||||
true, // 有禁点,摆棋阶段被提子的点不能再摆子
|
||||
|
@ -86,6 +89,7 @@ const struct Rule RULES[N_RULES] = {
|
|||
// 规则说明
|
||||
"规则与成三棋基本相同,只是在走子阶段,当一方仅剩3子时,他可以飞子到任意空位。",
|
||||
9, // 双方各9子
|
||||
3, // 飞子条件为剩余3颗子
|
||||
3, // 赛点子数为3
|
||||
false, // 没有斜线
|
||||
false, // 没有禁点,摆棋阶段被提子的点可以再摆子
|
||||
|
@ -107,6 +111,7 @@ const struct Rule RULES[N_RULES] = {
|
|||
"5. 同时出现两个“三连”只能提一子;\n"
|
||||
"6. 其它规则与成三棋基本相同。",
|
||||
12, // 双方各12子
|
||||
3, // 飞子条件为剩余3颗子
|
||||
3, // 赛点子数为3
|
||||
true, // 有斜线
|
||||
false, // 没有禁点,摆棋阶段被提子的点可以再摆子
|
||||
|
|
|
@ -31,6 +31,9 @@ struct Rule
|
|||
// The number of pieces each player has
|
||||
int piecesCount;
|
||||
|
||||
// When a player is reduced to N pieces, his pieces are free to move to any unoccupied point
|
||||
int flyPieceCount;
|
||||
|
||||
int piecesAtLeastCount; // Default is 3
|
||||
|
||||
// Add four diagonal lines to the board.
|
||||
|
@ -58,7 +61,7 @@ struct Rule
|
|||
// Change side to move if this option is disabled.
|
||||
bool isLoseButNotChangeSideWhenNoWay;
|
||||
|
||||
// Player may fly if he is down to three pieces.
|
||||
// Player may fly if he is down to three or four (configurable) pieces.
|
||||
bool mayFly;
|
||||
|
||||
// If a player has only three pieces left,
|
||||
|
|
|
@ -112,7 +112,7 @@ typedef uint32_t Key;
|
|||
|
||||
typedef uint32_t Bitboard;
|
||||
|
||||
constexpr int MAX_MOVES = 64;
|
||||
constexpr int MAX_MOVES = 72; // (24 - 4 - 3) * 4 = 68
|
||||
constexpr int MAX_PLY = 48;
|
||||
|
||||
enum Move : int32_t
|
||||
|
@ -155,7 +155,7 @@ enum class Phase : uint16_t
|
|||
// - Move a piece on the board:
|
||||
// - Slide a piece between two adjacent locations;
|
||||
// - 'Jump' a piece to any empty location if the player has less than
|
||||
// three pieces and mayFly is |true|;
|
||||
// three or four pieces and mayFly is |true|;
|
||||
// - Remove an opponent's piece after successfully closing a mill.
|
||||
enum class Action : uint16_t
|
||||
{
|
||||
|
|
|
@ -87,6 +87,11 @@ void on_piecesCount(const Option &o)
|
|||
rule.piecesCount = (int)o;
|
||||
}
|
||||
|
||||
void on_flyPieceCount(const Option &o)
|
||||
{
|
||||
rule.flyPieceCount = (int)o;
|
||||
}
|
||||
|
||||
void on_piecesAtLeastCount(const Option &o)
|
||||
{
|
||||
rule.piecesAtLeastCount = (int)o;
|
||||
|
@ -175,6 +180,7 @@ void init(OptionsMap &o)
|
|||
|
||||
// Rules
|
||||
o["PiecesCount"] << Option(9, 9, 12, on_piecesCount);
|
||||
o["flyPieceCount"] << Option(3, 3, 4, on_flyPieceCount);
|
||||
o["PiecesAtLeastCount"] << Option(3, 3, 5, on_piecesAtLeastCount);
|
||||
o["HasDiagonalLines"] << Option(false, on_hasDiagonalLines);
|
||||
o["HasBannedLocations"] << Option(false, on_hasBannedLocations);
|
||||
|
|
|
@ -65,6 +65,7 @@ class Config {
|
|||
|
||||
// Rules
|
||||
static int piecesCount = 9;
|
||||
static int flyPieceCount = 3;
|
||||
static int piecesAtLeastCount = 3;
|
||||
static bool hasDiagonalLines = false;
|
||||
static bool hasBannedLocations = false;
|
||||
|
@ -131,6 +132,7 @@ class Config {
|
|||
|
||||
// Rules
|
||||
rule.piecesCount = Config.piecesCount = settings['PiecesCount'] ?? 9;
|
||||
rule.flyPieceCount = Config.flyPieceCount = settings['FlyPieceCount'] ?? 3;
|
||||
rule.piecesAtLeastCount =
|
||||
Config.piecesAtLeastCount = settings['PiecesAtLeastCount'] ?? 3;
|
||||
rule.hasDiagonalLines =
|
||||
|
@ -201,6 +203,7 @@ class Config {
|
|||
|
||||
// Rules
|
||||
settings['PiecesCount'] = Config.piecesCount;
|
||||
settings['FlyPieceCount'] = Config.flyPieceCount;
|
||||
settings['PiecesAtLeastCount'] = Config.piecesAtLeastCount;
|
||||
settings['HasDiagonalLines'] = Config.hasDiagonalLines;
|
||||
settings['HasBannedLocations'] = Config.hasBannedLocations;
|
||||
|
|
|
@ -143,6 +143,7 @@ class NativeEngine extends Engine {
|
|||
await send('setoption name AiIsLazy value ${Config.aiIsLazy}');
|
||||
await send('setoption name Shuffling value ${Config.shufflingEnabled}');
|
||||
await send('setoption name PiecesCount value ${Config.piecesCount}');
|
||||
await send('setoption name FlyPieceCount value ${Config.flyPieceCount}');
|
||||
await send(
|
||||
'setoption name PiecesAtLeastCount value ${Config.piecesAtLeastCount}');
|
||||
await send(
|
||||
|
|
|
@ -472,6 +472,14 @@
|
|||
"@piecesCount_Detail": {
|
||||
"description": "How many pieces does each player have?"
|
||||
},
|
||||
"flyPieceCount": "Anzahl der fliegenden Steine",
|
||||
"@flyPieceCount": {
|
||||
"description": "The number of flying piece"
|
||||
},
|
||||
"flyPieceCount_Detail": "Wenn Fliegen aktiviert ist und ein Spieler auf eine bestimmte Steinzahl reduziert wird, können sich seine Steine frei zu jedem unbesetzten Punkt bewegen, anstatt wie im Rest des Spiels auf benachbarte Punkte beschränkt zu sein.",
|
||||
"@flyPieceCount_Detail": {
|
||||
"description": "If Flying is enabled, when a player is reduced to specific piece count, her pieces are free to move to any unoccupied point, instead of being restricted to adjacent points as in the rest of the game."
|
||||
},
|
||||
"ninePieces": "Neun Steine",
|
||||
"@ninePieces": {
|
||||
"description": "Nine Pieces"
|
||||
|
@ -546,7 +554,7 @@
|
|||
},
|
||||
"mayFly_Detail": "Wenn ein Spieler nur noch drei Steine hat, darf ein Stein an beliebige Punkte gezogen werden.",
|
||||
"@mayFly_Detail": {
|
||||
"description": "If a player has only three pieces left, she can move the piece to any free point."
|
||||
"description": "If a player has only three or four (configurable) pieces left, she can move the piece to any free point."
|
||||
},
|
||||
"maxStepsLedToDraw": "Maximale Schritte bis unentschieden",
|
||||
"@maxStepsLedToDraw": {
|
||||
|
|
|
@ -472,6 +472,14 @@
|
|||
"@piecesCount_Detail": {
|
||||
"description": "How many pieces does each player have?"
|
||||
},
|
||||
"flyPieceCount": "The number of flying piece",
|
||||
"@flyPieceCount": {
|
||||
"description": "The number of flying piece"
|
||||
},
|
||||
"flyPieceCount_Detail": "If Flying is enabled, when a player is reduced to specific piece count, her pieces are free to move to any unoccupied point, instead of being restricted to adjacent points as in the rest of the game.",
|
||||
"@flyPieceCount_Detail": {
|
||||
"description": "If Flying is enabled, when a player is reduced to specific piece count, her pieces are free to move to any unoccupied point, instead of being restricted to adjacent points as in the rest of the game."
|
||||
},
|
||||
"ninePieces": "Nine Pieces",
|
||||
"@ninePieces": {
|
||||
"description": "Nine Pieces"
|
||||
|
@ -544,9 +552,9 @@
|
|||
"@mayFly": {
|
||||
"description": "Flying"
|
||||
},
|
||||
"mayFly_Detail": "If a player has only three pieces left, she can move the piece to any free point.",
|
||||
"mayFly_Detail": "If a player has only three or four (configurable) pieces left, she can move the piece to any free point.",
|
||||
"@mayFly_Detail": {
|
||||
"description": "If a player has only three pieces left, she can move the piece to any free point."
|
||||
"description": "If a player has only three or four (configurable) pieces left, she can move the piece to any free point."
|
||||
},
|
||||
"maxStepsLedToDraw": "Max Steps Led to Draw",
|
||||
"@maxStepsLedToDraw": {
|
||||
|
|
|
@ -472,6 +472,14 @@
|
|||
"@piecesCount_Detail": {
|
||||
"description": "How many pieces does each player have?"
|
||||
},
|
||||
"flyPieceCount": "تعداد قطعه پرواز",
|
||||
"@flyPieceCount": {
|
||||
"description": "The number of flying piece"
|
||||
},
|
||||
"flyPieceCount_Detail": "اگر پرواز کردن فعال باشد ، هنگامی که یک بازیکن به تعداد قطعه های خاص کاهش می یابد ، مهره های او آزاد هستند و به جای محدود شدن به نقاط مجاور ، مانند سایر قسمت های بازی ، به هر نقطه اشغال نشده منتقل می شوند.",
|
||||
"@flyPieceCount_Detail": {
|
||||
"description": "If Flying is enabled, when a player is reduced to specific piece count, her pieces are free to move to any unoccupied point, instead of being restricted to adjacent points as in the rest of the game."
|
||||
},
|
||||
"ninePieces": "9 قطعه",
|
||||
"@ninePieces": {
|
||||
"description": "Nine Pieces"
|
||||
|
@ -544,9 +552,9 @@
|
|||
"@mayFly": {
|
||||
"description": "Flying"
|
||||
},
|
||||
"mayFly_Detail": "اگر به بازیکنی فقط سه قطعه مانده باشد ، می تواند قطعه را به هر نقطه آزاد منتقل کند.",
|
||||
"mayFly_Detail": "اگر به بازیکن فقط سه یا چهار قطعه (با قابلیت تنظیم) باقی مانده باشد ، می تواند قطعه را به هر نقطه آزاد منتقل کند.",
|
||||
"@mayFly_Detail": {
|
||||
"description": "If a player has only three pieces left, she can move the piece to any free point."
|
||||
"description": "If a player has only three or four (configurable) pieces left, she can move the piece to any free point."
|
||||
},
|
||||
"maxStepsLedToDraw": "مراحل حداکثر منجر به قرعه کشی",
|
||||
"@maxStepsLedToDraw": {
|
||||
|
|
|
@ -118,6 +118,8 @@
|
|||
"rules": "棋规",
|
||||
"piecesCount": "棋子数",
|
||||
"piecesCount_Detail": "设置对弈双方分别拥有的棋子数。",
|
||||
"flyPieceCount": "剩余多少子可飞子",
|
||||
"flyPieceCount_Detail": "如允许飞子,则当一方剩余多少枚棋子时可以飞棋。",
|
||||
"ninePieces": "九子",
|
||||
"twelvePieces": "十二子",
|
||||
"piecesAtLeastCount": "少于几个子则输棋",
|
||||
|
@ -136,7 +138,7 @@
|
|||
"isLoseButNotChangeSideWhenNoWay": "当无路可走时输棋",
|
||||
"isLoseButNotChangeSideWhenNoWay_Detail": "走子阶段,当无路可走时输棋,而非转为由对方继续走子。",
|
||||
"mayFly": "飞子",
|
||||
"mayFly_Detail": "当一方剩余三枚棋子时,此方可将棋子移动到棋盘任意空位上。",
|
||||
"mayFly_Detail": "当一方剩余三或四枚(可配置)棋子时,此方可将棋子移动到棋盘任意空位上。",
|
||||
"maxStepsLedToDraw": "连续多少步无吃子则和棋",
|
||||
"rollback": "回滚",
|
||||
"pleaseSelect": "请选择",
|
||||
|
|
|
@ -533,7 +533,7 @@ class Position {
|
|||
}
|
||||
|
||||
// if illegal
|
||||
if (pieceOnBoardCount[sideToMove()]! > rule.piecesAtLeastCount ||
|
||||
if (pieceOnBoardCount[sideToMove()]! > rule.flyPieceCount ||
|
||||
!rule.mayFly) {
|
||||
int md;
|
||||
|
||||
|
@ -929,8 +929,7 @@ class Position {
|
|||
}
|
||||
|
||||
// Can fly
|
||||
if (pieceOnBoardCount[sideToMove()]! <= rule.piecesAtLeastCount &&
|
||||
rule.mayFly) {
|
||||
if (pieceOnBoardCount[sideToMove()]! <= rule.flyPieceCount && rule.mayFly) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ class Rule {
|
|||
String name = "Nine Men's Morris";
|
||||
String description = "";
|
||||
int piecesCount = 9;
|
||||
int flyPieceCount = 3;
|
||||
int piecesAtLeastCount = 3;
|
||||
bool hasDiagonalLines = false;
|
||||
bool hasBannedLocations = false;
|
||||
|
|
|
@ -290,7 +290,8 @@ class _GamePageState extends State<GamePage>
|
|||
var us = Game.instance.sideToMove;
|
||||
if (position.phase == Phase.moving &&
|
||||
rule.mayFly &&
|
||||
Game.instance.position.pieceOnBoardCount[us] == 3) {
|
||||
(Game.instance.position.pieceOnBoardCount[us] ==
|
||||
Config.flyPieceCount || Game.instance.position.pieceOnBoardCount[us] == 3)) {
|
||||
print("[tap] May fly.");
|
||||
if (mounted) {
|
||||
showTip(S.of(context).tipCanMoveToAnyPoint);
|
||||
|
|
|
@ -76,14 +76,6 @@ class _RuleSettingsPageState extends State<RuleSettingsPage> {
|
|||
subtitleString: S.of(context).hasDiagonalLines_Detail,
|
||||
),
|
||||
ListItemDivider(),
|
||||
SettingsSwitchListTile(
|
||||
context: context,
|
||||
value: Config.mayFly,
|
||||
onChanged: setAllowFlyingAllowed,
|
||||
titleString: S.of(context).mayFly,
|
||||
subtitleString: S.of(context).mayFly_Detail,
|
||||
),
|
||||
ListItemDivider(),
|
||||
/*
|
||||
SettingsSwitchListTile(
|
||||
context: context,
|
||||
|
@ -142,6 +134,28 @@ class _RuleSettingsPageState extends State<RuleSettingsPage> {
|
|||
],
|
||||
),
|
||||
SizedBox(height: AppTheme.sizedBoxHeight),
|
||||
Text(S.of(context).mayFly, style: AppTheme.settingsHeaderStyle),
|
||||
SettingsCard(
|
||||
context: context,
|
||||
children: <Widget>[
|
||||
SettingsSwitchListTile(
|
||||
context: context,
|
||||
value: Config.mayFly,
|
||||
onChanged: setAllowFlyingAllowed,
|
||||
titleString: S.of(context).mayFly,
|
||||
subtitleString: S.of(context).mayFly_Detail,
|
||||
),
|
||||
ListItemDivider(),
|
||||
SettingsListTile(
|
||||
context: context,
|
||||
titleString: S.of(context).flyPieceCount,
|
||||
subtitleString: S.of(context).flyPieceCount_Detail,
|
||||
trailingString: Config.flyPieceCount.toString(),
|
||||
onTap: setFlyPieceCount,
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: AppTheme.sizedBoxHeight),
|
||||
Text(S.of(context).removing, style: AppTheme.settingsHeaderStyle),
|
||||
SettingsCard(
|
||||
context: context,
|
||||
|
@ -226,6 +240,49 @@ class _RuleSettingsPageState extends State<RuleSettingsPage> {
|
|||
);
|
||||
}
|
||||
|
||||
// General
|
||||
|
||||
setFlyPieceCount() {
|
||||
callback(int? flyPieceCount) async {
|
||||
print("[config] flyPieceCount = $flyPieceCount");
|
||||
|
||||
Navigator.of(context).pop();
|
||||
|
||||
setState(() {
|
||||
rule.flyPieceCount = Config.flyPieceCount = flyPieceCount ?? 3;
|
||||
});
|
||||
|
||||
print("[config] rule.flyPieceCount: ${rule.flyPieceCount}");
|
||||
|
||||
Config.save();
|
||||
}
|
||||
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (BuildContext context) => Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
RadioListTile(
|
||||
activeColor: AppTheme.switchListTileActiveColor,
|
||||
title: Text('3'),
|
||||
groupValue: Config.flyPieceCount,
|
||||
value: 3,
|
||||
onChanged: callback,
|
||||
),
|
||||
ListItemDivider(),
|
||||
RadioListTile(
|
||||
activeColor: AppTheme.switchListTileActiveColor,
|
||||
title: Text('4'),
|
||||
groupValue: Config.flyPieceCount,
|
||||
value: 4,
|
||||
onChanged: callback,
|
||||
),
|
||||
ListItemDivider(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
setHasDiagonalLines(bool value) async {
|
||||
setState(() {
|
||||
rule.hasDiagonalLines = Config.hasDiagonalLines = value;
|
||||
|
|
Loading…
Reference in New Issue