用JavaScript构建纵横字谜生成器

2020-05-08 20:15:36

又到了JavaScript教程的时间了。这将是我到目前为止介绍的最复杂的代码,所以我希望您已经注意到了,而不仅仅是复制和粘贴!在这篇文章中,您将学习如何使用JavaScript构建纵横字谜生成器。

首先,我将介绍这个项目的灵感来源,然后我将讨论不同的组件是什么以及它们是如何组合在一起的,最后我将讨论我所做的性能优化。

您可以通过单击此链接进行试用。不过,在单击按钮后要有耐心,因为有时创建纵横字谜需要一些时间。你很快就会明白为什么。

我已经编程很多年了,一路上犯了很多错误。我喜欢把自己想象成对构建软件略知一二的人。有大量的事情我不知道,但我对我的技能和我学习新概念和技术的能力充满信心。

然而,我并不是一夜之间就有了这样的信心。我曾经相当糟糕,当我有机会查看我多年前的一些代码时,我会对我所做的愚蠢的事情感到畏缩。

所以,如果现在是你,别难过!我们都必须从头做起,才能做好任何有价值的事情。

这给我带来了一个小小的故事。我通过移植一个旧的Java程序创建了这个填字游戏生成器,这个Java程序是我刚从大学毕业时写回的。我已经很多年没有看过它了,我告诉你,它相当粗糙。如果你想嘲笑我,可以在GitHub上看看。

我通过一次使用一个Java方法开始移植过程。我用一个闪亮的新JavaScript函数替换了每一个函数,该函数复制了它的逻辑。随着我的进步,我开始重构它,修复错误,并提高性能。

最终的产品不是完全干净的代码,但它比以前好了很多。

在完成我的纵横填字游戏生成器的JavaScript版本之后,我开始想知道是否值得为它写一篇教程。我百分之百确定有比我使用的算法更好的算法,我也百分之百确定我可以做更多的可读性和效率改进。我不想教你们任何坏习惯。

最后我觉得这是个好主意。有这么多教程真的很琐碎,并且不能让您很好地了解典型的公司代码库是什么样子。这会给你一个更好的近似值。这是多个能力水平各不相同的开发人员多年来在一个相当复杂的问题上的协作。碰巧两个开发人员都是我。😂。

它还会让您有机会添加您自己的改进,这是成长为开发人员的关键。

我们正在构建一个使用JavaScript、HTML和CSS的纵横填字游戏生成器。这个想法是拿出一大串单词,随机挑选一些,然后试着用它们做一个纵横填字游戏。

我们将从在网格上放置一个单词开始。然后,我们将获得另一个可能与该单词相关联的候选单词。那么我们将对另一个单词做同样的操作。我们将在ON上继续此过程,每次放置单词或单词不适合拼图中的任何位置时,都会选择一个不同的单词。

我们什么时候才能停止试着用词呢?这是一个由两个主要因素决定的复杂答案:

一旦做好了纵横字谜,我们就会继续创造更多的纵横字谜。然后我们会找到单词交叉点最多的一个,并将其显示在屏幕上!

在这篇文章中,我不会像在以前的一些教程中那样深入研究杂草。有太多的功能和边缘案例要处理。相反,我认为如果我详细解释我们将创建的高级组件将是最有帮助的。知道所有的部件是如何组合在一起的就是成功的一半。

我真的鼓励您研究每个函数都完成了什么,同时牢记哪些变量正在更改。如果你不明白什么,评论区是一个很好的求助方式。其他人可能会为此感谢你。

在我最初的版本中,我从一个文本文件中调出了詹姆斯国王的圣经。

在更新版本中,我只是制作了一个包含大量单词的JavaScript数组。您可以在这里查看。

要将一个单词放到网格上,我们需要了解一些有关它的事情。显然,我们需要知道单词本身的文本,但我们还需要知道它的位置。我们需要一行和一列来标记它的起始位置。我们还需要一个布尔值来表示单词在方向上是水平的还是垂直的。

我们将使用我们自己创建的Word对象来表示单词。您可以在这里查看。

我们正在创建的纵横填字游戏对象是完全完成的纵横填字游戏的表示形式。每一个都有不同的功能,服务于不同的目的。下面是每个函数及其功能的综合列表:

invadingRegion:确定一个单词是否会在某个位置入侵另一个单词的领土。

覆盖HorizontalWord:确定将字符放在特定行/列是否会覆盖水平单词。

overwrite ingVerticalWord:确定将字符放在特定行/列是否会覆盖垂直字。

一旦我们有能力将单词放在网格上,我们就需要开始制作一大堆纵横填字游戏。然后,我们需要挑选最好的一个并将其显示在屏幕上。执行所有这些操作的顶级函数称为createCrosswordPutle。

createCrosswordPutle函数有几个有助于实现其目标的嵌套函数。下面是每个函数及其功能的综合列表:

temtemptToPlaceWordOnGrid:取一个给定的单词,并尝试将其放在纵横填字游戏上。

isGoodWord:根据黑板上的字母确定一个单词是否适合放在纵横字谜游戏中。

Push UsedWords:将一个单词标记为已使用,并将其字母添加到填字游戏中出现的字母列表中。

除了上述函数外,该文件还包含一些助手函数,用于获取未使用的单词和各种随机值。

我希望前面的几节已经帮助您了解了所有部分是如何组合在一起的。纵横字谜生成器不是一个微不足道的问题,但将其分解为较小的问题是解决它的一个好方法。事实上,对于任何编程任务来说,这都是一种很好的方法。

我想更详细地谈一谈另一个方面。默认情况下,此代码速度不是很快。有非常大量的嵌套循环。

我将与你们分享我为使其更快而采取的步骤。如果你知道更好的算法,我希望你能给我写个评论。这是一门毕生的手艺,我既是一名学生,也是一名教师。

我采取了4个步骤来提高性能。我会把它们称为调整输入,选择智能单词,知道什么时候退出,以及说它足够好。

有两个变量可以对程序的速度产生重大影响。一个控制要创建的网格的数量,另一个控制尝试将单词放入网格的次数。

我发现尝试次数越多,意味着我可以减少要创建的网格总数。高次数的尝试有助于确保纵横填字游戏将密密麻麻地填满单词。

自己操作这些输入,注意它们如何影响程序的速度以及纵横填字游戏的样子。我试图优化以创建一个好看的纵横填字游戏,同时不会导致页面超时。

加快速度的一种方法是将我们的单词选择限制在有机会被放入网格中的单词。

起初,我完全是随机挑选每个单词,但这导致我试图将单词放在网格上,而这些单词没有可能的匹配方式。所以我浪费了大量的时间在网格中循环,我也浪费了在网格上匹配词语的尝试。

为了解决这个问题,我开始保存一个纵横字谜上存在哪些字母的列表。这样,我可以将我的单词选择限制为仅以这些字母中的一个开头的单词。我创建了下面的函数来帮助识别要尝试的好词。它不是完美的,但它防止了一些不必要的循环。

有时候你只需要知道什么时候该放弃。随着更多的单词被添加到纵横填字游戏中,成功放置另一个单词的可能性会降低。它没有那么大的空间,而且对放置的要求也变得更加严格。

最终,我们将开始在很长一段时间内无法将一个词放到网格上。我决定在这一点上结束这件事会更好。如果我们在将单词放到网格上有困难,那么无论如何它都可能是相当满的。

下面是发生这种情况的代码部分。470这个数字相当随意。似乎就在做了一些测试之后。

提高性能的最后一步是,一旦我创建了一个至少有4个单词交叉的纵横填字游戏,就停止生成纵横填字游戏。

一个有4个单词交叉点的纵横填字游戏通常看起来很不错,所以一旦其中一个减少了我们的平均生成时间,就停止游戏。

哇,那是一篇冗长而乏味的帖子。我真的希望真的有人能读到这一步。如果你有,请给我留言。编写所有这些😂会让我感觉更好

我希望您已经能够启动并运行您自己的纵横字谜生成器。这是一个有趣的项目,有很多细节需要考虑。如果您能够自己实现它,并且了解所有部分的工作原理,那么您肯定会成为一个更好的开发人员。

一如既往,感谢您的阅读。你可以订阅我的博客,如果你想要一些关于编写函数的技巧,并希望我的下一篇帖子通过电子邮件发送给你。