战舰!
早在2003年(当时我17岁),我就参加了战舰AI编码比赛。 即使我输掉了那场比赛,我也玩得很开心并从中学到了很多东西。
现在,我想在这场比赛中复活,寻找最好的战舰AI。
获奖者将获得+450声望! 比赛将于2009年11月17日开始 。 不接受17日零时以外的参赛作品或编辑。 (中央标准时间)提前提交您的参赛作品,这样您就不会错过机会!
为了保持这个目标 ,请遵循竞争精神。
游戏规则:
游戏将在10x10网格上进行。
每个参赛者将5艘船(长度分别为2,3,3,4,5)放置在其网格上。
没有船只可能重叠,但它们可能相邻。
然后竞争对手轮流对对手开枪。
游戏的一个变种允许每次击球射击多次射击,每个幸存的船只射击一次。
如果击球下沉,命中或未命中,对手将通知对手。
当任何一个玩家的所有船只都沉没时,游戏结束。
比赛规则:
竞争的精神是找到最好的战舰算法。
任何被视为违反竞争精神的东西都将被取消资格。
干扰对手是违背竞争精神的。
多线程可以在以下限制下使用:
在轮到你的时候,不超过一个线程可能正在运行。 (但是,任意数量的线程可能处于“暂停”状态)。
没有线程可以以“正常”以外的优先级运行。
鉴于上述两个限制,您将在转弯期间保证至少3个专用CPU核心。
每个游戏的CPU时间限制为1秒,分配给主线程上的每个竞争对手。
时间不多会导致当前游戏失败。
任何未处理的异常都将导致失去当前的游戏。
允许网络访问和磁盘访问,但您可能会发现时间限制相当令人望而却步。 然而,为了减轻时间紧张,增加了一些设置和拆卸方法。
代码应作为答案发布在堆栈溢出上,或者如果太大则链接。
条目的最大总大小(未压缩)为1 MB。
官方说来,.Net 2.0 / 3.5是唯一的框架要求。
您的条目必须实现IBattleshipOpponent接口。
评分:
101场比赛中最好的51场比赛是一场比赛的胜利者。
所有竞争对手都将相互配对,循环风格。
然后,最好的一半竞争者将参加双重淘汰赛以确定获胜者。 (实际上,2的最小功率大于或等于一半。)
结果将在此处公布。
如果您提交多个条目,则只有您的得分最高的条目才有资格获得双重条目。
祝好运! 玩得开心!
编辑1:
感谢Freed ,他在Ship.IsValid函数中发现了一个错误。 它已被修复。 请下载该框架的更新版本。
编辑2:
由于人们对将统计信息持久存储到磁盘等方面非常感兴趣,因此我添加了一些应该提供所需功能的非定时设置和拆除事件。 这是一个半破坏性的变化 。 也就是说:界面已经过修改以添加功能,但不需要它们。 请下载该框架的更新版本。
编辑3:
错误修复1: GameWon和GameLost只是在超时的情况下被调用。
错误修复2:如果引擎在每场比赛中超时,则比赛永远不会结束。
请下载该框架的更新版本。
编辑4:
比赛结果:
#1楼
这是我的参赛作品! (最天真的解决方案)
“随机1.1”
namespace Battleship
{
using System;
using System.Collections.ObjectModel;
using System.Drawing;
public class RandomOpponent : IBattleshipOpponent
{
public string Name { get { return "Random"; } }
public Version Version { get { return this.version; } }
Random rand = new Random();
Version version = new Version(1, 1);
Size gameSize;
public void NewGame(Size size, TimeSpan timeSpan)
{
this.gameSize = size;
}
public void PlaceShips(ReadOnlyCollection ships)
{
foreach (Ship s in ships)
{
s.Place(
new Point(
rand.Next(this.gameSize.Width),
rand.Next(this.gameSize.Height)),
(ShipOrientation)rand.Next(2));
}
}
public Point GetShot()
{
return new Point(
rand.Next(this.gameSize.Width),
rand.Next(this.gameSize.Height));
}
public void NewMatch(string opponent) { }
public void OpponentShot(Point shot) { }
public void ShotHit(Point shot, bool sunk) { }
public void ShotMiss(Point shot) { }
public void GameWon() { }
public void GameLost() { }
public void MatchOver() { }
}
}
#2楼
你写了:
任何被视为违反竞争精神的东西都将被取消资格。
干扰对手是违背竞争精神的。
请定义“反对竞争精神”和“干扰对手”?
另外 - 为了简化,我建议你:
在对手的CPU插槽中完全不允许使用CPU。
禁止线程并行,而是在单个线程上提供更多CPU秒。 这将简化AI的编程,并且不会伤害任何CPU /内存绑定的人。
PS - 潜伏在这里的CS博士后的问题:这个游戏不是可以解决的(即有一个单一的,最好的策略吗?)。 是的,电路板尺寸和步数使得minimax等强制要求,但我仍然不得不怀疑......它与Go和国际象棋的复杂程度相差甚远。
#3楼
这不是极小极大。 实际上在放置船只之后,每个玩家都不能独自玩耍,导致他转向每一个对手的船只转了几圈? 花费较少的人获胜。
我不认为除了沉没的船只之外还有任何好的一般策略,并试图尽量减少射击次数以覆盖船只可能隐藏的其余可能的地方。
当然,任何不随机的事情都可能存在反策略。 但我不认为有些策略可以对抗所有可能的球员。
#4楼
我预测那个设法逆转他们的对手随机种子和通话模式的人将获胜。
不知道有多大可能。
#5楼
实际上,我认为这个难题的最大问题在于它本质上是两个动作。 一方面是放置你的船只,另一方面是找到敌人的船只(不过第二部分可能分段,除了试图用随机因素击败时钟,它只是'运行你的算法')。 没有任何机制可以试图确定并反击敌人的策略,这就是使基于连续几轮“石头剪刀”的类似比赛非常有趣的原因。
另外,我认为如果你将游戏指定为网络协议然后提供框架来在C#中实现该协议,而不是规定所有解决方案都应该是C#,那我会更酷,但这只是我的意见。
编辑:我取消了我的初始观点,因为我没有仔细阅读比赛规则。