Bird是带有Rails API的Word React应用程序

对于我在Flatiron学校的最终项目,我决定构建我一直以来最喜欢的棋盘游戏之一-Scrabble。

我没有意识到整个事情会变得多么复杂。 因此,这里简要介绍了我为实现它所做的工作。

Rails API

我从创建具有四个模型的Rails API应用开始: GameUserTurnGamePlayer。

每个游戏都初始化为:

  1. 一个表示为散列数组阵列的板,以模拟行和列,并创建用于放置图块的x和y坐标系
  2. 表示为哈希数组的游戏图块
  3. 包含游戏图块中尚未使用的ID的“袋子”

联接GamePlayer表包含user_id,game_id,机架(用户当前的图块,表示为图块ID的数组),player_number和得分,以及通过具有与Turn模型的has_many关联的转向。

自己的回合模型(haha)记录着每个回合的记录,包括形成的新单词和所获得的积分。

React App

对于应用程序的客户端,我创建了一个React App并安装了Redux来管理状态。 我首先创建一个Board组件-一个包含多个Row组件实例的表,这些实例又由15个Square组件组成。 当遍历Board的行数组时,Board组件将y坐标分配给每个Row组件,然后再遍历数组数组中的每个项目以分配x坐标。 因此,最后每个Square组件最终都有x和y坐标,以后可以将其分配给放置在其上方的Tile组件。 在页面上呈现时,整个董事会看起来像这样。

我创建了第二张桌子,其中包含7个Square元素,用以表示玩家的机架。 它还具有坐标,但是它们与板的坐标不同,因此,可以在板和机架之间来回移动磁贴,而不会在其“地址”中产生混淆。 用户的完整机架看起来像这样:

我从这里采取的下一个步骤(可能也是最棘手的步骤之一)是配置React Drag and Drop,以使用户可以方便地将图块从机架移动到电路板上以及整个电路板上。 为了实现这一点,我使用了Redux Dan Abramov的发明者创建的React DnD库 。 如果您想为自己的应用程序实现拖放功能,我建议您编写一份有用的国际象棋应用程序教程 。 它说明了“拖动源和放置目标”的基本概念,可用的Monitor功能,例如didDrop()和canDrop(),这些功能旨在完全自定义应用程序的拖放机制。 例如,在我的情况下,瓦片的canDrop()条件不能堆叠在其他瓦片之上,而canDrag()取决于组件的“可拖动”属性是true还是false。 为了使此功能按我想要的方式工作,需要经过反复试验,但结果绝对值得!

作为放置动作的结果,以前具有与机架正方形坐标对应的x和y道具的Tile组件现在将接收与船上正方形坐标对应的新的x和y道具。

使React App和Rails API相互交谈

为了实现这一点,必须进行简单的CORS配置,可以在Rails App的config / initializers文件夹中找到该文件。 这有助于与您的客户端应用程序建立连接。 对于React App,可以在.env文件中设置可访问API的地址,以便通过操作轻松访问。 根据Redux文档,我创建了一些reducer和操作来处理来自API的数据发送和接收,然后设置应用程序组件的状态。

JWT认证

我认为如果用户能够保存他们的游戏并随时回到他们身边继续玩游戏,那就太好了,因此我决定实施身份验证。 结果也比预期的要复杂一些。 对于如何完成此任务似乎有很多歧义,但实际上并没有针对此问题的单一防故障解决方案。 我决定采用JWT身份验证 ,该方法不被认为是最安全的,但是在我的情况下,不会在数据库中存储任何敏感的个人用户信息(只是任何虚构的用户名和哈希密码),因此它可以达到目的仅允许用户保存游戏并与其他用户联系在一起玩游戏。

Rails端实现JWT身份验证包括创建一个自定义Auth库,该库能够生成令牌,然后再对其进行解码以对用户进行身份验证。 我还创建了一个包含登录和刷新操作的Auth控制器。

在客户端上处理身份验证需要创建一个单独的会话简化程序和一组必要的会话操作,以处理登录,注册,页面刷新和注销方案。

评分算法

计算所得积分的第一步是通过将所有已播放的图块放置在已排序的play_tiles数组中并分析其x和y坐标来定义主要播放的单词是水平放置还是垂直放置。 接下来,如果任何图块位于带有x2或x3字乘数(红色或橙色正方形)的正方形上,则将word_multiplier设置为大于1的值。

接下来,我从played_tiles数组中选择了第一个图块,并创建了两个循环来上下循环迭代垂直单词,或者创建左右两个循环以获取构成单词的所有图块,然后针对played_tiles数组检查它们,然后查看是否有应使用x2或x3字母乘法器(蓝色或绿色正方形)。

在计算了主要单词的分数之后,我遍历了play_tiles数组,并在与主要单词相反的方向上检查了每个图块中是否有相邻的图块。 因此,如果说主要单词是垂直的,那么我将通过遍历该单词左右两侧的相邻木板正方形来检查它是否包含水平单词。 而且,再次,如果有必要,在此过程中,我将字母和单词乘法器应用于这些附加的形成单词。

游戏

现在,用户可以注册并登录到应用程序,我创建了一种仪表板,其中显示了其他用户启动的所有可用游戏以及该用户正在进行的游戏。

至于游戏页面,我添加了几个重要的按钮:“ WORD”(单词)—提交单词并轮流使用,“ Skip Turn”和“ Exchange Tiles”。 这些按钮具有onClick事件处理程序,这些处理程序向后端发出请求,并具有由Rails中的游戏控制器处理的相应路线和动作。 “ WORD”按钮带有能够提交您的举动的条件:显然,您必须等待对手回合后才可以再次走。

如前所述,我在应用程序后端的“转弯”模型存储有关形成的单词和每次转弯后得分的信息。 这使我可以创建GameLog组件以呈现在游戏的页面上,这是一个可折叠的元素,用于显示游戏的历史记录。

这是“游戏”页面的最终版本:

截至目前,该游戏具有以下功能:

  1. 用户可以注册/登录。
  2. 用户可以创建游戏。
  3. 用户可以查看并加入现有游戏。
  4. 用户可以根据需要轮流,提交单词或交换磁贴。
  5. 用户可以赢得游戏,也可以输掉游戏。
  6. 用户可以与他们的朋友和陌生人玩无限数量的游戏!

总之,我想列出一些我计划将来实现的主要改进:

  1. 添加动作电缆,以便页面自动刷新,并且所有用户都订阅了游戏中的更改,因为在按下刷新按钮100次后,等待更改的声音听起来就像十年前一样。
  2. 为游戏添加更多规则/限制,因为目前它主要基于“信任”。 对照字典检查每个创建的单词,仅在单词在木板中心形成的情况下才允许第一轮,仅当磁贴连接到木板上现有的瓦片时才允许翻转。