Friday JS:0行JS和CSS游戏

也许许多老朋友会记得标题为“ 30行JS中的%something%”这样标题的文章的流行。 随之而来的是史诗般的帖子“ 在纯JS上用0行代码进行游戏 ”,此后该流行病突然消失了。 完全意识到我永远都不会超越这部杰作,但是五年后,我决定完成我的五分钱。

女士们,先生们,我们为您提供JS零行游戏“井字游戏”,并且与上述游戏不同,我们还为您提供CSS零行游戏(包括内联样式)。 只有裸HTML,只有硬核。


链接到游戏

它看起来很难看,但是可以在任何浏览器中使用。 在削减部分,我将在“星期五JS”部分中解释为什么没有JS的游戏为什么会结局,以及其他肮脏的细节。 但是,我不会向任何人开放美国,如果您是一位经验丰富的编码员,您甚至都无法接受。

其实,一切都很愚蠢。 该游戏包含将近6000页的静态HTML,它们相互链接。 当您在运动场的某个单元格上戳戳时,您将转到已移至该单元格的页面。 显然,用手书写6k页面是低于平均水平的乐趣。 因此(惊奇!)页面是使用NodeJS由JS脚本生成的。

抒情离题
写完上一行后,我突然想知道“ JS-script”一词是否像“ CD-ROM”或“ VIP-person”这样的重言式。 一方面,似乎如此。 另一方面,JS仍然不是缩写,而是性质稍有不同的缩写。 但是,该帖子仍然与语言学无关,因为抒情离题结束了,抒情性攻击开始了。

首先,我们建立所谓的游戏树-所有可能的游戏状态以及它们之间的过渡的总和。 我的代码中游戏的初始状态如下:

const initialState = { player: PLAYER_X, field: Array.from(Array(9)).map(() => EMPTY_CELL), moves: {} } 

它包含有关现在轮到谁以及比赛场地的状态的信息。 将来,它还将包含有关可以执行哪些操作以及它们将导致什么状态的信息,以及一些其他令人愉快的事情。

然后,我们从最初的状态开始,对重言式表示歉意,然后执行以下操作:

  1. 我们检查状态是否为最终状态(十字架的胜利,代币的胜利,平局)。
  2. 如果是这样,请将有关此信息添加到状态对象并完成。
  3. 如果不是,请遍历该字段中的所有单元格。
  4. 对于该字段中的每个空单元格,创建一个新的游戏状态,在该状态下,当前玩家移至该单元格,然后移至下一个玩家。
  5. 在当前状态的moves字段中,添加可能移动的记录。 此项的键是单元格索引,值是到新状态的链接。
  6. 我们对所有新出现的状态递归地重复此算法。

实际上,我的代码有点复杂,我习惯于将未展开的递归循环到一个循环中,而不是在moves中引用其他状态,而是moves它们的字符串键存储在某个关联数组中。 但是,所有这些都是细节。

然后,从每个游戏状态对象生成一个HTML页面。 遍历moves对象,我们在字段的空白单元格中填充指向对应于这些单元格中进行的移动的页面的链接。 然后,我们将字段的一维数组转换为二维HTML表。 我们添加了各种令人愉悦的内容,例如播放器走路的指示以及指向主页的链接-瞧!

除了这种模式,当一个人同时放置十字和零点时,在我的大型独立游戏中,也有机会与铁腕对抗。 这可以通过以下方式实现:

  1. 首先,针对每个游戏状态进行递归(实际上不是),计算游戏的预期结果-如果双方都进行得很好,则将获得该结果。
  2. 然后,对游戏树进行如下修改:我们现在一次执行两次移动,而不是玩家移动。 第二步是人工智能。 此外,从玩家行动的所有可能答案中,选择具有最佳预期结果的答案。 因此,在空的笼子上戳后,玩家会立即转到该单元格中出现叉号(或零),而在其他某个单元格中出现零(或叉号)的位置。
  3. 与AI没有做出的动作相对应的所有游戏位置都会被无情地丢弃。
  4. 然后从单独文件夹中的其余位置生成HTML-与两个播放器的情况完全相同。

按照类似的原理,您可以使用不是很大的树来实现任何游戏。 但是,如果我想以这种方式下棋,在我看来,github将拒绝托管此=)

说到github:您可以在其中看到整个代码(链接在游戏的主页上)。 通常,仅此而已。 再见,女孩和男孩。 再见。

PS替换换行符从Windows风格到Unix风格很长时间,涉及到6000个文件。 我很遗憾在编写代码的阶段没有注意这一点,但是仍然勇敢地忍受了git add

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


All Articles