达加兹:走出迷雾

图片 这一切都是女王黑帮的女王。
她编织在鬃毛的马s里
头发缠结了...

莎士比亚

这是一个漫长的发行版 ,但做了很多工作。 出现了会话管理器 ,使您可以回滚错误的操作。 在某些地方,增加了声音设计。 但是,我想出了一种很酷的方法来为一个游戏中的初始位置提供几种替代选择。 最重要的是-我终于以不完整的信息参加了比赛。

我将说明有什么危险。 在普通的棋类游戏中,例如国际象棋西洋跳棋 ,玩家在游戏中的任何时候都具有有关棋子位置(自己和对手),移动规则,游戏目标等的完整信息。 这些游戏已经被很好地研究,并且属于“ 具有充分信息的游戏 ”类别。 现在,假设某些信息可能对播放器不可见。


《战争迷雾》是该主题的很好例证。 根据“ 盲棋 ”的规则,玩家看不到敌人的所有碎片,而只能看到放置在战场上的那些碎片,只需动动任何一块碎片就可以看到。 我对该规则做了两个补充:

  1. 当然,玩家总是会看到他的棋子,但是通过展示它们的方式-以正常形式还是半透明,他可以判断对手是否看到了它们。
  2. 仅出于装饰目的,我在当前不可见的区域放置了“云”。

掌握了总的原理后 ,我有点不为所动,并且以“战争迷雾”创作了大量游戏。 除了国际象棋本身 ,我还有“暗”选项可用于“ 翔” ,“ 樟宜” ,“ 沙特朗日”,“ 薛图因”和许多其他游戏。 甚至还有“ 盲枪 ”! 所有这些游戏都有一个共同点:

电脑在作弊!
我什至没有尝试更改这些游戏的机器人算法,因为我敢打赌,不平等的条件至少可以部分弥补他们与人类相比极其脆弱的游戏。 正如我之前所写 ,为棋盘游戏开发高质量的AI是一项非常艰巨的任务。 当然,规则也有例外。 即使机器人的游戏非常弱小,一个人也很难玩一个陌生的游戏 ,字面上挤满了陷阱。 我们可以说一下它的“黑暗” 版本

但是,总的来说,这不是一个非常正确的方法。 我想看到一个机器人,它可以完全处理对手的数据-伙计。 为什么这很重要? 一切都很简单-通过机器人的播放方式,有时很容易猜测它是否可以访问隐藏信息(窥视)。 当然,一个人玩一个不会偷窥的机器人会更有趣(和另一个人一起玩更有趣,但这是另外一回事了)。

在这里值得选择一款与国际象棋略有不同的游戏(因为我还没有准备好“盲目”下象棋的“诚实”机器人)。 有很多这样的游戏,不能说它们比国际象棋或西洋跳棋更简单。 它们只是不同而已,需要一种单独的方法。

举个例子
我还没有开发一款机器人儿童游戏。 它被称为“丛林”或“ 豆首奇” 。 游戏的目标是穿透敌人的领土。 每个玩家都有一个“ den”-第一行的中心位置。 如果敌人的任何人物进入该巢穴,他就会赢(您不能用自己的人物占领该巢穴)。


这些数字是按资历排序的。 大象击败所有人物,其次是狮子,老虎,豹,狗,狼,猫和老鼠。 一只老鼠只能打大象和另一只老鼠,此外,这是唯一可以在水中移动的人物(在棋盘中间有两个水库)。 老虎和狮子可以跳过水,但前提是老鼠不能挡水。 除跳跃外,所有图形都以相同的方式移动-垂直或水平移动到一个相邻的字段。 该巢穴被陷阱包围。 陷阱中的人物容易受到任何敌方人物的攻击。

如您所见,规则非常简单。 是什么阻碍了该游戏机器人的开发? 首先是低速数字。 如果存在威胁,我会体会到交流带来的好处,但是在游戏的大部分时间里,这些棋子只是在相当长的距离上一个接一个地跑。 我无法承受大量向前移动的游戏(由于移动计算的持续时间受到限制),因此更改不属于视线范围,所有移动对我来说都是等效的。

首先,我决定呆在BanQi-中国盲棋上。 这是一款非常原始的游戏,具有类似于“丛林”的隐藏信息。 对我来说很重要的一点是,与为该游戏创建机器人相关的开发成果可以用于其他游戏中,例如窦守琪,陆战 Stratego或什至是Tafl


我会告诉你有关规则的。 游戏在“中国象棋”(象棋)的棋盘一半上运行,而棋盘的原始布局不起作用。 棋子被放置在牢房内(与传统棋子一样),而不是在线的交点处(如中国象棋)。 在游戏开始时,将所有棋子彻底混合并面朝下放在棋盘上(因为传统的Syant棋子是某种枪管,并且它们的数量与棋盘一半的场数一致,所以没有困难)。

接下来,玩家改变他们的动作。 进行移动时,玩家可以翻转任何闭合的块,或移动先前打开的颜色。 玩家的颜色由第一步决定。 如果第一个黑色棋子被打开,打开它的玩家将被黑色。 游戏中的所有人物都以相同的方式(除了台湾版的“大炮”,我将在后面讨论),在一个相邻的单元上垂直或水平。 拍摄的可能性由数字的高低顺序决定:

General> Advisor> Elephant> Wagon> Horse> Cannon> Soldier

年龄较大的人物会击败年龄较小或与之相等的人,但有一个例外:一名士兵击中将军(一种“ 剪刀石头布 ”)。 关于台湾板旗还有几句话:

  1. 与中文版不同,在台湾版旗中,将军无法击败士兵。
  2. 机枪按照“ 香气”规则移动,即沿正交低速移动到任何数量的区域(如战车),或在执行攻击动作时跳过“车架”,击中任何敌方人物。

还有一个香港版本,但实际上与中文没有什么不同,只是数字的优先顺序已更改。 我决定将重点放在台湾版本的规则上,这是最有趣的战术。

开发机器人时我应该寻找什么?
首先,游戏看起来非常简单,但事实并非如此。 即使您不考虑与台湾枪支有关的细微差别,这些数字的成本也是违反直觉的。 尽管“顾问”可以击败的数字少于“将军”,但他是游戏中的主要角色。 首先,玩家有两名顾问。 此外,只有一名敌方将军的实力要强于每位顾问,而将军最多可受到五名士兵的攻击! 出于同样的原因,游戏中士兵的费用高于一般士兵的费用。 最终,他可以击败最强的人物! 第二个重要考虑因素是亨利·杜德尼(Henry Dudeney)的“坎特伯雷”难题之一。


这不是一个完整的谜题,而是更多的玩笑任务。 所有图形都可以垂直或水平转到一个相邻的字段。 白色先行,而白色和黑色总是先行两次(以不同的片段)! 在这种情况下,左小丑永远不会抓住左驴,而右小丑永远不会抓住右驴(您可以自己检查)。 当然,右边的小丑可以毫不费力地抓住左边的驴子。 都是关于平价的!

这个问题使我产生了一些想法。 首先,在BanQi或DouShouQi等游戏中,机器人的任务首先是找到最短路径。 从每个活动的棋子(一个人或一个对手),有必要建立通往所有可能目标(包括自己的棋子,以计算可能的交换)的移动链。 之后,需要评估链条,这里可以使用以下选项。

  1. 攻击者击败了被攻击者-通过考虑被攻击者的成本(如果攻击者受到保护,则减去攻击者的成本)估算出了一条有利的(奖励)链,并考虑了链的长度。
  2. 攻击人物击败了被攻击者-不是根据攻击人物的价值估算的可盈利(惩罚性)链。
  3. 棋子互相击败(例如,它们是相等的)-这里的一切都取决于平价,奇数链是有利的,而偶数链则应视为惩罚性的(如果场上没有其他数字,则平价将完全决定比赛的结果)。

当然,一切并不是那么简单。 至少,您应该记住台湾BanQi中的加农炮的特定路线(至于“丛林”,还有更多特殊情况),但这是您可以开始的地方。 借助一套完整的评估链,您可以评估移动。 搬家的成本应包括连锁的成本(奖金和免费),其长度会减少。

首先,重要的是要了解这里不可能有效地使用minimax算法。 揭示先前隐藏的部分的动作也从根本上改变了位置估计。 由于没有隐藏物品的信息,几乎不可能看到许多前进的位置。 但是每朵云都有一线希望,但是我们可以使用更复杂的(就计算而言)启发式方法来评估移动本身!

我已经有了一个机器人,可以通过其启发式评估动作(需要一个有趣的游戏 )。 这是一个非常简单的算法。 所有移动均按启发式降序排序(启发式值为负的移动通常会被丢弃),然后按顺序扫描它们。 如果下一个动作导致一个位置,在该位置上没有敌方反应导致立即获胜,则机器人会认为这是最好的。 使用此算法,您不必为位置估计而烦恼,但是您必须为启发式算法大汗淋漓。

首先,我们建立连锁店
var getChains = function(design, board) { var player = board.getValue(board.player); if (player === null) return []; if (_.isUndefined(board.chains)) { board.chains = []; var pieces = getGoals(design, board); var targets = getTargets(design, board, pieces); _.each(pieces.positions, function(pos) { var goals = pieces; var f = true; var piece = board.getPiece(pos); if (piece === null) return; if (!chinese && (piece.type == 12)) { goals = targets; f = false; } var group = [ pos ]; var level = []; level[pos] = 0; for (var i = 0; i < group.length; i++) { if (_.indexOf(goals.positions, group[i]) >= 0) { //  ... } if ((i > 0) && (board.getPiece(group[i]) !== null)) continue; _.each(design.allDirections(), function(dir) { p = design.navigate(board.player, group[i], dir); while (p !== null) { if (_.indexOf(group, p) >= 0) break; group.push(p); level[p] = level[ group[i] ] + 1; if (f || (board.getPiece(p) !== null)) break; p = design.navigate(board.player, p, dir); } }); } }); } return board.chains; } 

当然,我会在游戏状态下缓存所有中间数据,以免多次读取。 另外,这里使用了一个技巧,这在计算连接区域时非常有用。 我遍历了数组,根据需要将其他元素放入循环中。 所有困难都与枪支有关。 对于他们来说,锁链的目标不是人物本身,而是人物可以从中攻击的领域。

链条的评估完全如我所说
 var getChainPrice = function(design, board, attacker, attacking, len) { var player = board.getValue(board.player); if ((player === null) || (attacker == null) || (attacking === null)) return 0; if (attacker.player == attacking.player) return 0; var isAttacking = isAttacker(design, attacker.type, attacking.type); var isAttacked = isAttacker(design, attacking.type, attacker.type); if (!chinese && (attacker.type == 12)) { isAttacking = true; isAttacked = (attacking.type == attacker.type) && (len == 1); } var price = 0; var f = (len % 2 == 0); if (attacker.player != player) f = !f; if (isAttacking) { if (isAttacked) { price = f ? (len - design.price[attacker.type]) : (design.price[attacking.type] - len); } else { price = design.price[attacking.type] - len; if (f) price = (price / 2) | 0; } } else { if (isAttacked) { price = len - design.price[attacker.type]; } } return price; } 

...取决于链条的长度和奇偶性,以及考虑到攻击者和被攻击者的成本。 但这只是成功的一半! 必须使用构造的链条评估每个可能的移动。 我介绍了另一个中间结构-希望汇总可用数据。 对课程的评估包括对愿望的评估,它满足:

像这样
 var addWish = function(board, comment, price, src, dst) { if (_.isUndefined(board.wish[src])) { board.wish[src] = []; } if (_.isUndefined(dst)) dst = src; if (_.isUndefined(board.wish[src][dst])) { board.wish[src][dst] = price; } else { board.wish[src][dst] += price; } } var getWish = function(design, board) { if (_.isUndefined(board.wish)) { ... } return board.wish; } Dagaz.AI.heuristic = function(ai, design, board, move) { var wish = getWish(design, board); if (move.isSimpleMove() && !_.isUndefined(wish[ move.actions[0][0][0] ]) && !_.isUndefined(wish[ move.actions[0][0][0] ][ move.actions[0][1][0] ])) { return wish[ move.actions[0][0][0] ][ move.actions[0][1][0] ]; } return 0; } 

至于getWish函数本身 ,魔术就从这里开始(这是我很可能多次耕过的地方)。 首先,我分享基于开放信息的移动评估以及在游戏中引入新作品的评估。 这并不完全正确,但是到目前为止,我只是不知道如何调和这种不同的观点。 如果基于公开信息未形成任何愿望,则该机器人将尝试打开新的图形(此处也有一些技巧)。

  1. 如果敌方大炮是打开的,并且被密闭的人物包围,那么打开旁边的一个人物是有道理的,因为在任何情况下它都有可能攻击枪支,并且枪支也无法打败它。
  2. 如果打开了除加农炮以外的其他人形,则可以尝试通过它的“支架”打开一个位于其上的人形,因为它有可能会变成加农炮。
  3. 如果敌方有攻击链,则可以打开链条旁边的碎片之一来拦截攻击。
  4. 如果您无法保护该图形,则可以打开该图形旁边的图形,以尝试将这种情况减少为交流。

当然,评估打开特定图形的可能性很有用。
 var getShadow = function(design, board) { var player = board.getValue(board.player); if (player === null) return []; if (_.isUndefined(board.shadow)) { board.shadow = []; _.each(design.allPositions(), function(pos) { var piece = board.getPiece(pos); if ((piece !== null) && (piece.type < 7)) { var value = piece.type + 7; if (piece.player != player) { value = -value; } board.shadow.push(value); } }); } return board.shadow; } var isFriend = function(design, x) { return x > 0; } var isPiece = function(design, x, y) { return x == y; } var isAttacker = function(design, x, enemy) { if (x < 0) return false; if ((x == 13) && (enemy == 7)) return true; if (!chinese && (x == 7) && (enemy == 13)) return false; if (!chinese && (x == 12)) return false; return x <= enemy; } var isDefender = function(design, x, enemy, friend) { if (!isAttacker(design, x, enemy)) return false; return design.price[friend] <= design.price[enemy]; } var estimate = function(design, board, p, y, z) { var shadow = getShadow(design, board); if (shadow.length == 0) return 0; var r = 0; _.each(shadow, function(x) { if (p(design, x, y, z)) r++; }); return (100 * r) / shadow.length; } 

玩家可以通过跟踪退出游戏的人物来评估概率。 原则上,机器人可以执行相同的操作,但是有一种更简便的方法-批量查看仍未打开的图形,并根据收集的信息评估打开所需图形的可能性。 而且,不能保证所选动作的成功,但是如果有利结果的可能性低,则根本不会选择该动作。

原则上,这种方法是有回报的,但仍有工作要做。
虽然防守动作不是很好。 一些人物勇敢地遇到了更强大的敌人,而不是逃避他(尽管通常情况下逃避已经毫无用处)。 此外,协调各种人物的行动也有困难(这对于“驱赶”敌方人物的残余很有用)。 该方法本身看起来非常有前途,但是仍然必须考虑启发式方法。

基于动作“链”的启发式方法不仅可以在BanQi中使用,而且在许多其他游戏中也很有用,其中主要是“动作缓慢”的部分(如果不是作为定义标准,那么至少可以使用更复杂的算法初步评估动作的质量,至少至少)。 在那些很难或什至不可能使用minimax算法的游戏(例如Yonin Shogi)中 ,尤其需要这种方法。


当然,我将继续研究信息不完整的游戏。 图为菲律宾尚未准备的“ 将军游戏 ”。 这是大型家族中最简单的游戏,包括LuzhanQiStratego之类的游戏。 当然,我仍然希望为“ 丛林 ”做一个能干的机器人!

对于仍在阅读我的人,我可以提供另一种具有隐藏信息的有趣益智游戏:


我小时候就用一个叫做Fox Hunt的可编程计算器玩过它。 八只狐狸被随机隐藏在场上,必须使用“戳方法”找到它们。 当选择一个空白区域时,将显示所有八个方向上的狐狸总数。 不会丢失,但是您可以争取最少的点击次数。 如果您使用耳机播放,请调低声音。 也许我用音效来代替它。

Source: https://habr.com/ru/post/zh-CN422427/


All Articles