AMP
  • 网站

井字棋

简介

这是一个演示如何实现井字棋的示例。包括:

  • 如何使用 amp-state 来维护游戏状态。

  • 如何使用表达式来检测获胜的步骤。

  • 如何使用动作事件来创建交互式游戏玩法。

设置

交互式游戏玩法需要 amp-bind

<script async custom-element="amp-bind" src="https://cdn.ampproject.org/v0/amp-bind-0.1.js"></script>

初始游戏状态

我们使用名为 gameStateamp-state 来保持游戏状态。此外,一些状态值未初始化,但将在下面进行说明

  • currentPlayer:可以是 1 或 -1,分别表示 ⚡ 和 O。
  • board:存储棋盘的状态。此对象具有 9 个属性,从 ai,表示从左上到右下的瓷砖。
  • trmrbrlcmcrcfdbd:读作Top Row(顶行)、Middle Row(中行)等等,这 8 个值保存朝向每个可能的获胜状态的计数
<amp-state id="gameState">
  <script type="application/json">
    {
      "currentPlayer": 1,
      "displayValues": {
        "-1": "O",
        "1": "⚡"
      }
    }
  </script>
</amp-state>

显示获胜

要检测获胜,我们检查是否有任何计数已达到正 3 或负 3。

开始游戏!

⚡ 获胜了!!!

O 获胜了!!!

<div class="results-component">
  <h1 [class]="max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3 ? 'hide' : 'show'">Let's play!</h1>
  <h1 [class]="max(tr,br,lc,rc,fd,bd,mc,mr) == 3 ? 'show' : 'hide'" class="hide">⚡ wins!!!</h1>
  <h1 [class]="min(tr,br,lc,rc,fd,bd,mc,mr) == -3 ? 'show' : 'hide'" class="hide">O wins!!!</h1>
</div>

处理玩家的回合

游戏棋盘的每个瓷砖都是一个按钮。当玩家走一步时,状态会更新

  • 适当的计数会增加或减少。例如,在左上角走一步会改变 3 种可能的获胜状态的计数:trlcbd(顶行、左列和后向对角线)。

  • board 的状态已更新,以记录该瓷砖已被填充。

  • 通过将当前玩家乘以 -1,将游戏切换到另一位玩家。

每个瓷砖的显示属性会根据此状态变化进行更新

  • [text]:每个瓷砖要么不包含任何内容,要么包含来自 board 的相应值。

  • [class]:如果已达到此瓷砖的任何获胜状态,则会相应地更改背景。

  • [disabled]:如果已发生获胜或已玩过该瓷砖,则必须禁用此按钮。

<div class="board-component">
  <table>
    <tr>
      <td class="cell">
        <button on="tap:AMP.setState({
                      tr: tr + gameState.currentPlayer,
                      lc: lc + gameState.currentPlayer,
                      bd: bd + gameState.currentPlayer,
                      board: {
                        a: gameState.displayValues[gameState.currentPlayer]
                      },
                      gameState: {
                        currentPlayer: gameState.currentPlayer * -1
                      }
                    })" [text]="board.a ? board.a : ''" [class]="max(abs(tr),abs(lc),abs(bd)) == 3 ? 'grid-button win' : 'grid-button in-play'" [disabled]="board.a || max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3" class="grid-button in-play">
        </button>
      </td>
      <td class="cell cell-vert">
        <button on="tap:AMP.setState({
                      tr: tr + gameState.currentPlayer,
                      mc: mc + gameState.currentPlayer,
                      board: {
                        b: gameState.displayValues[gameState.currentPlayer]
                      },
                      gameState: {
                        currentPlayer: gameState.currentPlayer * -1
                      }
                    })" [text]="board.b ? board.b : ''" [class]="max(abs(tr),abs(mc)) == 3 ? 'grid-button win' : 'grid-button in-play'" [disabled]="board.b || max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3" class="grid-button in-play">
        </button>
      </td>
      <td class="cell">
        <button on="tap:AMP.setState({
                      tr: tr + gameState.currentPlayer,
                      rc: rc + gameState.currentPlayer,
                      fd: fd + gameState.currentPlayer,
                      board: {
                        c: gameState.displayValues[gameState.currentPlayer]
                      },
                      gameState: {
                        currentPlayer: gameState.currentPlayer * -1
                      }
                    })" [text]="board.c ? board.c : ''" [class]="max(abs(tr),abs(rc),abs(fd)) == 3 ? 'grid-button win' : 'grid-button in-play'" [disabled]="board.c || max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3" class="grid-button in-play">
        </button>
      </td>
    </tr>
    <tr>
      <td class="cell cell-horiz">
        <button on="tap:AMP.setState({
                      mr: mr + gameState.currentPlayer,
                      lc: lc + gameState.currentPlayer,
                      board: {
                        d: gameState.displayValues[gameState.currentPlayer]
                      },
                      gameState: {
                        currentPlayer: gameState.currentPlayer * -1
                      }
                    })" [text]="board.d ? board.d : ''" [class]="max(abs(mr),abs(lc)) == 3 ? 'grid-button win' : 'grid-button in-play'" [disabled]="board.d || max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3" class="grid-button in-play">
        </button>
      </td>
      <td class="cell cell-horiz cell-vert">
        <button on="tap:AMP.setState({
                      mr: mr + gameState.currentPlayer,
                      mc: mc + gameState.currentPlayer,
                      fd: fd + gameState.currentPlayer,bd: bd + gameState.currentPlayer,
                      board: {
                        e: gameState.displayValues[gameState.currentPlayer]
                      },
                      gameState: {
                        currentPlayer: gameState.currentPlayer * -1
                      }
                    })" [text]="board.e ? board.e : ''" [class]="max(abs(mr),abs(mc),abs(fd),abs(bd)) == 3 ? 'grid-button win' : 'grid-button in-play'" [disabled]="board.e || max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3" class="grid-button in-play">
        </button>
      </td>
      <td class="cell cell-horiz">
        <button on="tap:AMP.setState({
                      mr: mr + gameState.currentPlayer,
                      rc: rc + gameState.currentPlayer,
                      board: {
                        f: gameState.displayValues[gameState.currentPlayer]
                      },
                      gameState: {
                        currentPlayer: gameState.currentPlayer * -1
                      }
                    })" [text]="board.f ? board.f : ''" [class]="max(abs(mr),abs(rc)) == 3 ? 'grid-button win' : 'grid-button in-play'" [disabled]="board.f || max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3" class="grid-button in-play">
        </button>
      </td>
    </tr>
    <tr>
      <td class="cell">
        <button on="tap:AMP.setState({
                      br: br + gameState.currentPlayer,
                      lc: lc + gameState.currentPlayer,
                      fd: fd + gameState.currentPlayer,
                      board: {
                        g: gameState.displayValues[gameState.currentPlayer]
                      },
                      gameState: {
                        currentPlayer: gameState.currentPlayer * -1
                      }
                    })" [text]="board.g ? board.g : ''" [class]="max(abs(br),abs(lc),abs(fd)) == 3 ? 'grid-button win' : 'grid-button in-play'" [disabled]="board.g || max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3" class="grid-button in-play">
        </button>
      </td>
      <td class="cell cell-vert">
        <button on="tap:AMP.setState({
                      br: br + gameState.currentPlayer,
                      mc: mc + gameState.currentPlayer,
                      board: {
                        h: gameState.displayValues[gameState.currentPlayer]
                      },
                      gameState: {
                        currentPlayer: gameState.currentPlayer * -1
                      }
                    })" [text]="board.h ? board.h : ''" [class]="max(abs(br),abs(mc)) == 3 ? 'grid-button win' : 'grid-button in-play'" [disabled]="board.h || max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3" class="grid-button in-play">
        </button>
      </td>
      <td class="cell">
        <button on="tap:AMP.setState({
                      br: br + gameState.currentPlayer,
                      rc: rc + gameState.currentPlayer,
                      bd: bd + gameState.currentPlayer,
                      board: {
                        i: gameState.displayValues[gameState.currentPlayer]
                      },
                      gameState: {
                        currentPlayer: gameState.currentPlayer * -1
                      }
                    })" [text]="board.i ? board.i : ''" [class]="max(abs(br),abs(rc), abs(bd)) == 3 ? 'grid-button win' : 'grid-button in-play'" [disabled]="board.i || max(abs(tr),abs(br),abs(lc),abs(rc),abs(fd),abs(bd),abs(mc),abs(mr)) == 3" class="grid-button in-play">
        </button>
      </td>
    </tr>
  </table>
</div>

重置游戏状态

要开始新游戏,board 和 8 个计数将重置为 nullcurrentPlayer 将重置为

<div class="reset-component">
  <button class="reset-button" on="tap:AMP.setState({
              gameState: {
                currentPlayer: 1,
                displayValues: {
                  '-1': 'O',
                  '1': '⚡'
                }
              },
              tr: null,
              mr: null,
              br: null,
              lc: null,
              mc: null,
              rc: null,
              fd: null,
              bd: null,
              board: null
            })">
    Restart game
  </button>
</div>

实用技巧

将 ⚡ 放在中心方格!

需要进一步解释?

如果此页面上的解释没有涵盖您的所有问题,请随时与其他 AMP 用户联系,讨论您的确切用例。

转到 Stack Overflow
未解释的功能?

AMP 项目强烈鼓励您的参与和贡献!我们希望您能成为我们开源社区的长期参与者,但我们也欢迎您针对自己特别关注的问题提供一次性贡献。

在 GitHub 上编辑示例