我这辈子一直在吃不会考试的亏。我坚信自己是个好学生,但就是不会考试。传统的考试科目自己只能拿下语文历史和物理,数学和地理要赌人品,政治化学生物必死。即使出了国,考试还是赌人品。人品好遇到计算题,人品不好遇到论述题和画图的题,死路一条。
即使很多时候自己都很留恋校园,但这份留恋终究拗不过考试的摧残。我可以用代码把它实现,但请别让我用文字描述它怎样实现。在国内我就不好这口儿,中文已如此,英文以何堪?GPA暂且得过且过吧,工作以后就没人管我的GPA了。
春天来了,身边没有可让自己发情的,暂且让我对马伊咪YY吧。我没事就揣摩砸向马伊咪的各种糖衣炮弹:全中国的女演员加起来都没有你漂亮,全乘起来也不如你聪明;我为你倾倒,就像克里奥帕特拉裙下的凯撒;我今天就是为你来的,要么我牵你的手走,要么我一个人离开……等等。当然,我还有there is only love or hate between a man and a woman这样无比煽情的台词,但是她不一定听得懂。
Latest Version: 0.92b Download
新的0.92B版,可以选择棋盘的大小新的0.92B版
AI的源码
[java]
for (int x = 3; x < lines + 3; x++) //比如一个19*19的棋盘,上下左右各再给出3格标记,这样就省得考虑数组溢出了
{
for (int y = 3; y < lines + 3; y++) //遍历棋盘
{
tmp = 50000; //随便给一个初始权,5000
if (m trix[x, y].V lue == 0 || m trix[x, y].V lue == 9) //如果某一格可以落子
{
for (int n = 0; n < w it.Count; n++)
{
if (x == ((Done)w it[n]).x && y == ((Done)w it[n]).y && pl yer == ((Done)w it[n]).pl yer)
{
tmp -= 9000; //如果这个点是属于自己的必挡,扣9000;w it数组里存了所有的必挡
bre k;
}
}
if (m trix[x, y].V lue == 9)
tmp += 50000; //如果这是别人的必挡,+50000
//如果某一格可能给自己形成必挡,形成一个加1000分,一共24种情况
if (m trix[x - 1, y].V lue == pl yer && m trix[x - 1, y].V lue == m trix[x - 2, y].V lue)
{
if (m trix[x + 1, y].V lue == 0)
tmp += 1000;
if (m trix[x - 3, y].V lue == 0)
tmp += 1000;
}
if (m trix[x + 1, y].V lue == pl yer && m trix[x + 1, y].V lue == m trix[x + 2, y].V lue)
{
if (m trix[x - 1, y].V lue == 0)
tmp += 1000;
if (m trix[x + 3, y].V lue == 0)
tmp += 1000;
}
if (m trix[x, y - 1].V lue == pl yer && m trix[x, y - 1].V lue == m trix[x, y - 2].V lue)
{
if (m trix[x, y + 1].V lue == 0)
tmp += 1000;
if (m trix[x, y - 3].V lue == 0)
tmp += 1000;
}
if (m trix[x, y + 1].V lue == pl yer && m trix[x, y + 1].V lue == m trix[x, y + 2].V lue)
{
if (m trix[x, y - 1].V lue == 0)
tmp += 1000;
if (m trix[x, y + 3].V lue == 0)
tmp += 1000;
}
if (m trix[x + 1, y + 1].V lue == pl yer && m trix[x + 1, y + 1].V lue == m trix[x + 2, y + 2].V lue)
{
if (m trix[x - 1, y - 1].V lue == 0)
tmp += 1000;
if (m trix[x + 3, y + 3].V lue == 0)
tmp += 1000;
}
if (m trix[x - 1, y - 1].V lue == pl yer && m trix[x - 1, y - 1].V lue == m trix[x - 2, y - 2].V lue)
{
if (m trix[x + 1, y + 1].V lue == 0)
tmp += 1000;
if (m trix[x - 3, y - 3].V lue == 0)
tmp += 1000;
}
if (m trix[x + 1, y - 1].V lue == pl yer && m trix[x + 1, y - 1].V lue == m trix[x + 2, y - 2].V lue)
{
if (m trix[x - 1, y + 1].V lue == 0)
tmp += 1000;
if (m trix[x + 3, y - 3].V lue == 0)
tmp += 1000;
}
if (m trix[x - 1, y + 1].V lue == pl yer && m trix[x - 1, y + 1].V lue == m trix[x - 2, y + 2].V lue)
{
if (m trix[x + 1, y - 1].V lue == 0)
tmp += 1000;
if (m trix[x - 3, y + 3].V lue == 0)
tmp += 1000;
}
if (m trix[x + 1, y].V lue == pl yer && m trix[x - 1, y].V lue == m trix[x + 1, y].V lue)
{
if (m trix[x - 2, y].V lue == 0)
tmp += 1000;
if (m trix[x + 2, y].V lue == 0)
tmp += 1000;
}
if (m trix[x, y - 1].V lue == pl yer && m trix[x, y + 1].V lue == m trix[x, y - 1].V lue)
{
if (m trix[x, y + 2].V lue == 0)
tmp += 1000;
if (m trix[x, y - 2].V lue == 0)
tmp += 1000;
}
if (m trix[x - 1, y - 1].V lue == pl yer && m trix[x - 1, y - 1].V lue == m trix[x + 1, y + 1].V lue)
{
if (m trix[x + 2, y + 2].V lue == 0)
tmp += 1000;
if (m trix[x - 2, y - 2].V lue == 0)
tmp += 1000;
}
if (m trix[x - 1, y + 1].V lue == pl yer && m trix[x - 1, y + 1].V lue == m trix[x + 1, y - 1].V lue)
{
if (m trix[x + 2, y - 2].V lue == 0)
tmp += 1000;
if (m trix[x - 2, y + 2].V lue == 0)
tmp += 1000;
}
//如果某一格可能形成连二,且前方两格是空的,形成一个连二加100分,一共16种情况
if (m trix[x - 1, y].V lue == pl yer)
{
if (m trix[x + 1, y].V lue == 0 && m trix[x + 2, y].V lue == 0)
tmp += 100;
if (m trix[x - 2, y].V lue == 0 && m trix[x - 3, y].V lue == 0)
tmp += 100;
}
if (m trix[x + 1, y].V lue == pl yer)
{
if (m trix[x - 1, y].V lue == 0 && m trix[x - 2, y].V lue == 0)
tmp += 100;
if (m trix[x + 2, y].V lue == 0 && m trix[x + 3, y].V lue == 0)
tmp += 100;
}
if (m trix[x, y - 1].V lue == pl yer)
{
if (m trix[x, y + 1].V lue == 0 && m trix[x, y + 2].V lue == 0)
tmp += 100;
if (m trix[x, y - 2].V lue == 0 && m trix[x, y - 3].V lue == 0)
tmp += 100;
}
if (m trix[x, y + 1].V lue == pl yer)
{
if (m trix[x, y - 1].V lue == 0 && m trix[x, y - 2].V lue == 0)
tmp += 100;
if (m trix[x, y + 2].V lue == 0 && m trix[x, y + 3].V lue == 0)
tmp += 100;
}
if (m trix[x + 1, y + 1].V lue == pl yer)
{
if (m trix[x - 1, y - 1].V lue == 0 && m trix[x - 2, y - 2].V lue == 0)
tmp += 100;
if (m trix[x + 2, y + 2].V lue == 0 && m trix[x + 3, y + 3].V lue == 0)
tmp += 100;
}
if (m trix[x - 1, y - 1].V lue == pl yer)
{
if (m trix[x + 1, y + 1].V lue == 0 && m trix[x + 2, y + 2].V lue == 0)
tmp += 100;
if (m trix[x - 2, y - 2].V lue == 0 && m trix[x - 3, y - 3].V lue == 0)
tmp += 100;
}
if (m trix[x + 1, y - 1].V lue == pl yer)
{
if (m trix[x - 1, y + 1].V lue == 0 && m trix[x - 2, y + 2].V lue == 0)
tmp += 100;
if (m trix[x + 2, y - 2].V lue == 0 && m trix[x + 3, y - 3].V lue == 0)
tmp += 100;
}
if (m trix[x - 1, y + 1].V lue == pl yer)
{
if (m trix[x + 1, y - 1].V lue == 0 && m trix[x + 2, y - 2].V lue == 0)
tmp += 100;
if (m trix[x - 2, y + 2].V lue == 0 && m trix[x - 3, y + 3].V lue == 0)
tmp += 100;
}
//这部分是防守用的,算法还有待补充
if (m trix[x - 1, y].V lue == m trix[x + 1, y].V lue)
{
if (m trix[x - 2, y].V lue == 0)
tmp += 25;
if (m trix[x + 2, y].V lue == 0)
tmp += 25;
}
if (m trix[x, y + 1].V lue == m trix[x, y - 1].V lue)
{
if (m trix[x, y + 2].V lue == 0)
tmp += 25;
if (m trix[x, y - 2].V lue == 0)
tmp += 25;
}
if (m trix[x - 1, y - 1].V lue == m trix[x + 1, y + 1].V lue)
{
if (m trix[x + 2, y + 2].V lue == 0)
tmp += 25;
if (m trix[x - 2, y - 2].V lue == 0)
tmp += 25;
}
if (m trix[x - 1, y + 1].V lue == m trix[x + 1, y - 1].V lue)
{
if (m trix[x + 2, y - 2].V lue == 0)
tmp += 25;
if (m trix[x - 2, y + 2].V lue == 0)
tmp += 25;
}
tmp -= 5 * System.M th. bs((lines / 2 + 3) – x); //修正权,越靠近中央权越高
tmp -= 5 * System.M th. bs((lines / 2 + 3) – y);
tmp += rd.Next(10); //加一点随机数,增加变化
if (tmp >= max) //赋最大值
{
max = tmp;
xx = x;
yy = y;
}
}
}
}
[/java]
tmp这个变量用得漂亮,我原来设想的就是遍历加棋路的匹配,比你这个会死板很多。防守那边好像还可以再多做几个棋路,然后根据危险程度调整tmp,不一定要都是25。你这个游戏做得不丑,不知道外国人在编程大赛中更看中什么,如果是看产品的话应该能拿个好名次,但如果更看中代码的质量的话我觉得你可以把这个AI写得更加模块化一点,评委未必愿意看这种多层循环加IF的代码。
那些if完全可以重构的只剩几行。你居然把这么多行的拿出来展示。也可能是我工作了段时间,看质量不高的代码就比较反感。tmp你个头啊,权值就是权值,怎么成“临时”了啊。学人工智能的就应搞点稍微专业点的东西行不行,这个叫算法么?这个ai初中生写不出来也能想出来,没有攻防预测,没有递归。。。。建议写个五子棋增加灵感。
to DYF:这个算法我已经跟不少人讨论过,不限于blog,提出改进意见的也有,没有像你这样的。你现在价值观有问题,跟大多数中国程序员成了同类,具体的我也不说什么了。权值的原文是weight,或者翻译为权重。比如说有八个人一起下棋,一个点的权重对于这八个人各有不同,最蠢的方法是分别给每个人一个二维数组;其次蠢的是给一个二维数组,8个人共享反复重写;我这个算第三蠢的,一个变量8个人共享,反反复复重写,全称temp_weight,简称tmp。我不是学人工智能的,我们学校也没有人工智能的方向,我连这门课也没选,因为对找工作没用,我又不想做研究。If重构几行是肯定要做的——就像弄德说的模块化——思路也已经有了。但前提是有软件公司说:你这个程序我有兴趣,给我看看源码。那我就会重写,整个程序都要修。但是现在没必要,我也懒得写。初中生当然能写出来,美国14岁的初中生都给iphone开发程序拿出来卖,比我有钱途的多。俄罗斯方块和贪吃蛇连AI都没有,依然是世界上最流行的游戏。五子棋的AI写得再好也没人愿意跟电脑下。魔兽的AI必然是世界上最顶尖的,还是被人菜。我这个AI或者连算法都称不上,但是下一般人还是足够有挑战性的。至于质量高不高的问题,我敢说:如果要用递归来解,代码必然更简洁,但是同运算量以内效率必然更差——我的代码的运算时间已经是O(n),新的算法无论如何不可能比O(n)更少,系数会少一点,但维度只能是n。攻防转换已经有了,你自己没有仔细看。最后的8个if就是防守,具体我也不解释了。to 弄德:多谢夸奖了~ 如果是围棋五子棋这种的,必然要遍历棋路,但我的程序不大需要大局观,AI也不是重点,暂且不考虑遍历。但是如果要写顶尖的必挡算法,还是要递归穷举的。现在的防守只考虑了一种情况,就是下在对方两个子中间,把潜在的三连断了。最好的情况是一个点可以破坏对方16个必挡,所以有16个if。我认为这16种情况的权是一样的,25或250无所谓,不过根据实战看25是低了。还有很多其他情况没考虑到,比如在对方形成2连的时候就去挡,于是对方形成3连的时候只需要再去挡一次;再比如……文字叙述不清,反正还有很多就是。这个所谓的比赛只是学校校内的,不是上档次的东西。我觉得自己的简历里必须有点在美国的“荣誉”,所以就参加了。按以往的经验是不看代码质量的,他们也没时间看:大概就是二三十个选手集中在一天内,每人演示十分钟——完全没时间说算法。我喜欢这个游戏因为它创意很好,不只是我的创意,是我跟很多463兄弟们一起的创意。
既然写了,就写得完美点呗。防守那边,你说的16种情况在单独出现时的确权值应该一样,但是当它们叠加在一个点上时权值就不应该是单纯的25+25+25…了,比如这个图:<img src = "http://hiphotos.baidu.com/%D1%CC%D4%C6%B9%FD%CD%F9/pic/item/44b6441ef677aec21ad57673.jpg" />左上角那种情况,如果不防的话最少能拿到14分。所以防守那边权值的计算就不应该是用加的关系了,而应该是几何关系(乘,平方等),这样才能有效地根据风险大小做出判断。同理,进攻的时候也可以考虑根据拿分机会的大小调整权值的计算方法。不过这样一来,需要做很多计算才能拿得准具体应该使用的数值。另外,关于代码,我觉得if叠加没问题的,虽然程序长了点,但对运行效率不会有影响。如果if里的条件太过复杂,反而很难看懂且容易出错。再有就是我收回模块化的说法,你这个是c#写的,那就应该用面向对象的方法,将棋盘,落子点,AI都用对象封装起来,那样写出来的代码就很容易读了。
你要是只是推广你的创意,那我没什么可说。你要是因为觉得自己动手能力太生太弱,做个简单可用的小东西增加兴趣,那我没什么可说。你要是觉得自己的水平就定位在说出“新的算法无论如何不可能比O(n)更少”这种水平的话说,那我也没什么可说。试问优秀的算法的目的是为了让了算法O(n)?这个借口太弱了吧,我不觉得预测10步内的局面的10*O(n^2)不可接受。另外你很了解国内程序员么?如果你经常泡技术社区,就该了解到javaeye的气氛,真正的大牛说话比我不客气多了,而且他们都是身在外国多年的资深工程师。好吧有一点我误解你了,我始终感觉你的奋斗目标是ai,不知道是你的哪篇文章给我带来的错觉,既然你对这个不在乎,那我对你的期望就过高了点。如果我期望过高打击了你的兴趣和积极性,那我向你表示歉意
to 弄德:这里的棋盘matrix就是落子点组成的,落子点已经封装了,所以你看到matrix[x, y].Value这样的形式。还有封装的是必挡,在wait数组里,所以你看到(Done)wait[n]).player——表示这是谁的必挡。还有我上次说错了,不是16个是8个,在你截图的左上角落子,直接破坏的是4个必挡(上下左右)。但如果考虑先后手,用乘方表示,似乎太复杂了……尤其是两个以上玩家的话,比如六个玩家,那就疯掉了……to DYF:我以前想做AI,但是现在对现实妥协了。普通的留学生没资格谈理想,尤其是现在找到工作就不容易了。如果真谈理想,我连计算机都不做。javaeye没去过,只是偶尔上csdn,看到大牛喷新人,半瓶醋互相喷。但是我在英文论坛绝少看有人喷其他人的,更极少看到有人说“你应该读读《xxx》”这样的话。老外经常说“Don’t tell other people how to live their lives.”, 类似于孟子说的,“人之患在好为人师”。你说那些在外国多年的资深工程师比你更不客气,我完全能理解。中餐馆和中国超市在达拉斯不是最脏的也是最脏的之一——尽管已经比国内的干净不少,但还是最脏的。所谓南橘北枳,只对种子和幼苗有效,对已经成株的植物是无效的。另外,我觉得遍历十步是O(n^10),不知道我想的对不对
你没明白我意思。。。哪天qq跟你说吧
中国人跟外国人本来就不一样,当然外国人素质高的面多一些,但中国有某些现象也有其存在的价值的。半瓶醋互相喷的基本都存在于对于新理念的理解,比如tdd或者rest之类的,因为本身就没有什么确定的答案。中国人追求新鲜,所以喷的明显点。这个国外也存在,我记得被rest的那篇论文的作者直接喷过的人几乎涵盖了所以努力去应用rest的人,“你们根本没有理解我在说什么,根本就是玷污了rest的理念”,这是他的原话。这方面大家都该改善,尤其是中国的井底之蛙的程序员。不过大牛喷新人,我不清楚你说的外国为什么会没有,但我觉得这个是很必要的。有些程序员之间根本就是在讨论一些非常上不了台面的问题。如果没有大牛给他们拓展视野,他们根本不可能走出自己的圈子。他们之所以在那些问题上过不去坎,深层次的原因就是站的不够高,当撇开那些问题去学习新的东西后,回来再看原来的那些讨论就变得可笑了。我工作中认识的很多人都是在被喷过后,才静下心来提高自己的。正是这样我觉得那些牛人也许只是为了维护自己论坛的水准和内容的清洁,但行为上却给中国程序员的整体提高带来了好处。所以你对于中国餐馆的比喻,也许只是你的猜测,不一定准确。关于这个算法,遍历十步是O(n^10),这个是对的。但我没提过“遍历”这两个字。