AI は Power Apps でオセロアプリを作ることができるのか?

Power Apps
この記事は約76分で読めます。

作れました

Claude Code × MCP サーバーを使って、Power Apps のキャンバスアプリでオセロを作りました。

コードは一行も書いていません。「オセロアプリを作って」と日本語で話しかけただけです。

できあがったのは 1 画面構成のアプリで、以下の機能がすべて含まれています。

  • 8×8 ボードと石の描画
  • 合法手のハイライト表示
  • 石をひっくり返す処理(8方向)
  • パスの自動検出
  • 勝敗判定とゲームオーバー画面
  • CPU 対戦(コーナー重視の位置評価あり)

業務アプリでもなく、フォームでもない。ゲームが動いたのは正直驚きました。


生成された YAML

Claude Code が生成した .pa.yaml をそのまま掲載します。 Power Apps Studio のコードビューに貼り付けると動きます。

一番下の部分がかぶっているので押しにくい箇所があります。そこを修正してから提供してもよかったのですが、あえてAIそのままのコードを貼り付けることにしました。(ちょっと盤面上に動かせば実際はOK)

ちなみにCPUはそれなりにできるので、何も考えないで打ったらちゃんと負けられますw

Screens:
  GameScreen:
    Properties:
      Fill: =RGBA(18, 24, 22, 1)
      OnVisible: |-
        =If(
          CountRows(colBoard) = 0,
          ClearCollect(
            colBoard,
            ForAll(
              Sequence(64),
              {
                Row: RoundDown((Value - 1) / 8, 0) + 1,
                Col: Mod(Value - 1, 8) + 1,
                Color: "Empty",
                IsValid: false
              }
            )
          );
          UpdateIf(colBoard, Row = 4 And Col = 4, {Color: "White"});
          UpdateIf(colBoard, Row = 4 And Col = 5, {Color: "Black"});
          UpdateIf(colBoard, Row = 5 And Col = 4, {Color: "Black"});
          UpdateIf(colBoard, Row = 5 And Col = 5, {Color: "White"});
          ClearCollect(
            colDirs,
            {dr: -1, dc: -1}, {dr: -1, dc: 0}, {dr: -1, dc: 1},
            {dr: 0,  dc: -1},                   {dr: 0,  dc: 1},
            {dr: 1,  dc: -1}, {dr: 1,  dc: 0},  {dr: 1,  dc: 1}
          );
          Set(currentPlayer, "Black");
          Set(gameOver, false);
          Set(winnerText, "");
          Set(lastMessage, "")
        );
        If(
          IsBlank(userColor) Or userColor = "",
          Set(userColor, "");
          Set(cpuColor, "");
          Set(sideChosen, false)
        )
    Children:
      - TitleLabel:
          Control: Text@0.0.51
          Properties:
            Align: =Align.Left
            Font: =Font.Georgia
            FontColor: =RGBA(246, 240, 224, 1)
            Height: =56
            Size: =40
            Text: ="OTHELLO"
            VerticalAlign: =VerticalAlign.Middle
            Weight: ='TextCanvas.Weight'.Bold
            Width: =480
            X: =40
            Y: =32
      - TurnBadge:
          Control: Badge@0.0.24
          Properties:
            Appearance: ='BadgeCanvas.Appearance'.Filled
            Content: =Upper(currentPlayer) & " TO MOVE"
            FontSize: =14
            FontWeight: =FontWeight.Semibold
            Height: =36
            Shape: ='BadgeCanvas.Shape'.Rounded
            ThemeColor: ='BadgeCanvas.ThemeColor'.Danger
            Visible: =!gameOver
            Width: =220
            X: =Parent.Width - 260
            Y: =44
      - LastMessageLabel:
          Control: Text@0.0.51
          Properties:
            Align: =Align.Center
            FontColor: =RGBA(180, 172, 150, 1)
            Height: =20
            Size: =12
            Text: =lastMessage
            Visible: =Len(lastMessage) > 0
            Weight: ='TextCanvas.Weight'.Regular
            Width: =560
            X: =(Parent.Width - 560) / 2
            Y: =106
      - BoardBackdrop:
          Control: Rectangle@2.3.0
          Properties:
            BorderStyle: =BorderStyle.None
            Fill: =RGBA(10, 40, 28, 1)
            Height: =600
            Width: =600
            X: =(Parent.Width - 600) / 2
            Y: =130
      - BoardGallery:
          Control: Gallery@2.15.0
          Variant: Horizontal
          Properties:
            BorderStyle: =BorderStyle.None
            Fill: =RGBA(10, 40, 28, 1)
            Height: =560
            Items: =colBoard
            ShowScrollbar: =false
            TemplatePadding: =0
            TemplateSize: =70
            Width: =560
            WrapCount: =8
            X: =(Parent.Width - 560) / 2
            Y: =150
          Children:
            - CellBg:
                Control: Rectangle@2.3.0
                Properties:
                  BorderStyle: =BorderStyle.None
                  Fill: |-
                    =If(
                      ThisItem.Color = "Empty"
                        And Not gameOver
                        And Sum(
                          ForAll(
                            colDirs,
                            {
                              n: With(
                                   {
                                     steps: ForAll(
                                       Sequence(7),
                                       {
                                         i: Value,
                                         color: With(
                                           { rr: ThisItem.Row + dr * Value, cc: ThisItem.Col + dc * Value },
                                           If(
                                             rr < 1 Or rr > 8 Or cc < 1 Or cc > 8,
                                             "Off",
                                             With(
                                               { cell: LookUp(colBoard, Row = rr And Col = cc) },
                                               If(IsBlank(cell), "Off", cell.Color)
                                             )
                                           )
                                         )
                                       }
                                     ),
                                     opp: If(currentPlayer = "Black", "White", "Black")
                                   },
                                   With(
                                     {
                                       stopIdx: First(
                                         Sort(Filter(steps, color <> opp), i, SortOrder.Ascending)
                                       )
                                     },
                                     If(
                                       IsBlank(stopIdx) Or stopIdx.color <> currentPlayer Or stopIdx.i = 1,
                                       0,
                                       stopIdx.i - 1
                                     )
                                   )
                                 )
                            }
                          ),
                          n
                        ) > 0,
                      RGBA(52, 140, 100, 1),
                      RGBA(26, 95, 66, 1)
                    )
                  Height: =68
                  Width: =68
                  X: =1
                  Y: =1
            - CellValidDot:
                Control: Circle@2.3.0
                Properties:
                  BorderStyle: =BorderStyle.None
                  Fill: =RGBA(255, 244, 214, 0.35)
                  Height: =8
                  Visible: |-
                    =ThisItem.Color = "Empty"
                      And Not gameOver
                      And Sum(
                        ForAll(
                          colDirs,
                          {
                            n: With(
                                 {
                                   steps: ForAll(
                                     Sequence(7),
                                     {
                                       i: Value,
                                       color: With(
                                         { rr: ThisItem.Row + dr * Value, cc: ThisItem.Col + dc * Value },
                                         If(
                                           rr < 1 Or rr > 8 Or cc < 1 Or cc > 8,
                                           "Off",
                                           With(
                                             { cell: LookUp(colBoard, Row = rr And Col = cc) },
                                             If(IsBlank(cell), "Off", cell.Color)
                                           )
                                         )
                                       )
                                     }
                                   ),
                                   opp: If(currentPlayer = "Black", "White", "Black")
                                 },
                                 With(
                                   {
                                     stopIdx: First(
                                       Sort(Filter(steps, color <> opp), i, SortOrder.Ascending)
                                     )
                                   },
                                   If(
                                     IsBlank(stopIdx) Or stopIdx.color <> currentPlayer Or stopIdx.i = 1,
                                     0,
                                     stopIdx.i - 1
                                   )
                                 )
                               )
                          }
                        ),
                        n
                      ) > 0
                  Width: =8
                  X: =31
                  Y: =31
            - StoneCircle:
                Control: Circle@2.3.0
                Properties:
                  BorderColor: =If(ThisItem.Color = "Black", RGBA(255, 255, 255, 0.12), RGBA(0, 0, 0, 0.25))
                  BorderThickness: =1
                  Fill: =If(ThisItem.Color = "Black", RGBA(14, 14, 14, 1), RGBA(246, 240, 224, 1))
                  Height: =56
                  Visible: =ThisItem.Color <> "Empty"
                  Width: =56
                  X: =7
                  Y: =7
            - CellClickButton:
                Control: Button@0.0.45
                Properties:
                  Appearance: ='ButtonCanvas.Appearance'.Transparent
                  BorderThickness: =0
                  Height: =70
                  OnSelect: |-
                    =If(
                      gameOver Or ThisItem.Color <> "Empty" Or Not sideChosen Or currentPlayer = cpuColor,
                      false,
                      With(
                        {
                          thisRow: ThisItem.Row,
                          thisCol: ThisItem.Col,
                          player: currentPlayer,
                          opp: If(currentPlayer = "Black", "White", "Black")
                        },
                        With(
                          {
                            flipsByDir: ForAll(
                              colDirs,
                              {
                                dr: dr,
                                dc: dc,
                                count: With(
                                  {
                                    steps: ForAll(
                                      Sequence(7),
                                      {
                                        i: Value,
                                        color: With(
                                          { rr: thisRow + dr * Value, cc: thisCol + dc * Value },
                                          If(
                                            rr < 1 Or rr > 8 Or cc < 1 Or cc > 8,
                                            "Off",
                                            With(
                                              { cell: LookUp(colBoard, Row = rr And Col = cc) },
                                              If(IsBlank(cell), "Off", cell.Color)
                                            )
                                          )
                                        )
                                      }
                                    )
                                  },
                                  With(
                                    {
                                      stopIdx: First(
                                        Sort(Filter(steps, color <> opp), i, SortOrder.Ascending)
                                      )
                                    },
                                    If(
                                      IsBlank(stopIdx) Or stopIdx.color <> player Or stopIdx.i = 1,
                                      0,
                                      stopIdx.i - 1
                                    )
                                  )
                                )
                              }
                            )
                          },
                          If(
                            Sum(flipsByDir, count) <= 0,
                            false,
                            UpdateIf(colBoard, Row = thisRow And Col = thisCol, {Color: player});
                            ForAll(
                              Filter(flipsByDir, count > 0),
                              ForAll(
                                Sequence(count),
                                UpdateIf(
                                  colBoard,
                                  Row = thisRow + dr * Value And Col = thisCol + dc * Value,
                                  {Color: player}
                                )
                              )
                            );
                            Set(currentPlayer, opp);
                            Set(lastMessage, "");
                            If(
                              CountRows(
                                Filter(
                                  colBoard,
                                  Color = "Empty"
                                    And Sum(
                                      ForAll(
                                        colDirs,
                                        {
                                          n: With(
                                               {
                                                 steps: ForAll(
                                                   Sequence(7),
                                                   {
                                                     i: Value,
                                                     color: With(
                                                       { rr: Row + dr * Value, cc: Col + dc * Value },
                                                       If(
                                                         rr < 1 Or rr > 8 Or cc < 1 Or cc > 8,
                                                         "Off",
                                                         With(
                                                           { cell2: LookUp(colBoard, Row = rr And Col = cc) },
                                                           If(IsBlank(cell2), "Off", cell2.Color)
                                                         )
                                                       )
                                                     )
                                                   }
                                                 ),
                                                 opp2: If(currentPlayer = "Black", "White", "Black")
                                               },
                                               With(
                                                 {
                                                   stopIdx2: First(
                                                     Sort(Filter(steps, color <> opp2), i, SortOrder.Ascending)
                                                   )
                                                 },
                                                 If(
                                                   IsBlank(stopIdx2) Or stopIdx2.color <> currentPlayer Or stopIdx2.i = 1,
                                                   0,
                                                   stopIdx2.i - 1
                                                 )
                                               )
                                             )
                                        }
                                      ),
                                      n
                                    ) > 0
                                )
                              ) = 0,
                              With(
                                {
                                  other: If(currentPlayer = "Black", "White", "Black")
                                },
                                If(
                                  CountRows(
                                    Filter(
                                      colBoard,
                                      Color = "Empty"
                                        And Sum(
                                          ForAll(
                                            colDirs,
                                            {
                                              n: With(
                                                   {
                                                     steps: ForAll(
                                                       Sequence(7),
                                                       {
                                                         i: Value,
                                                         color: With(
                                                           { rr: Row + dr * Value, cc: Col + dc * Value },
                                                           If(
                                                             rr < 1 Or rr > 8 Or cc < 1 Or cc > 8,
                                                             "Off",
                                                             With(
                                                               { cell3: LookUp(colBoard, Row = rr And Col = cc) },
                                                               If(IsBlank(cell3), "Off", cell3.Color)
                                                             )
                                                           )
                                                         )
                                                       }
                                                     ),
                                                     opp3: If(other = "Black", "White", "Black")
                                                   },
                                                   With(
                                                     {
                                                       stopIdx3: First(
                                                         Sort(Filter(steps, color <> opp3), i, SortOrder.Ascending)
                                                       )
                                                     },
                                                     If(
                                                       IsBlank(stopIdx3) Or stopIdx3.color <> other Or stopIdx3.i = 1,
                                                       0,
                                                       stopIdx3.i - 1
                                                     )
                                                   )
                                                 )
                                            }
                                          ),
                                          n
                                        ) > 0
                                    )
                                  ) = 0,
                                  Set(gameOver, true);
                                  Set(
                                    winnerText,
                                    With(
                                      {
                                        b: CountRows(Filter(colBoard, Color = "Black")),
                                        w: CountRows(Filter(colBoard, Color = "White"))
                                      },
                                      If(b > w, "BLACK WINS", If(w > b, "WHITE WINS", "DRAW"))
                                    )
                                  ),
                                  Set(
                                    lastMessage,
                                    Upper(currentPlayer) & " had no legal moves — " & Upper(other) & " plays again."
                                  );
                                  Set(currentPlayer, other)
                                )
                              ),
                              false
                            )
                          )
                        )
                      )
                    )
                  Text: =""
                  Width: =70
      - ScoreContainer:
          Control: GroupContainer@1.5.0
          Variant: ManualLayout
          Properties:
            BorderStyle: =BorderStyle.None
            Height: =100
            Width: =560
            X: =(Parent.Width - 560) / 2
            Y: =668
          Children:
            - BlackScoreNumber:
                Control: Text@0.0.51
                Properties:
                  Align: =Align.Left
                  FontColor: =RGBA(246, 240, 224, 1)
                  Height: =72
                  Size: =48
                  Text: =CountRows(Filter(colBoard, Color = "Black"))
                  VerticalAlign: =VerticalAlign.Middle
                  Weight: ='TextCanvas.Weight'.Bold
                  Width: =180
            - BlackScoreCaption:
                Control: Text@0.0.51
                Properties:
                  Align: =Align.Left
                  FontColor: =RGBA(180, 172, 150, 1)
                  Height: =24
                  Size: =12
                  Text: ="BLACK"
                  Weight: ='TextCanvas.Weight'.Semibold
                  Width: =180
                  Y: =70
            - WhiteScoreNumber:
                Control: Text@0.0.51
                Properties:
                  Align: =Align.Right
                  FontColor: =RGBA(246, 240, 224, 1)
                  Height: =72
                  Size: =48
                  Text: =CountRows(Filter(colBoard, Color = "White"))
                  VerticalAlign: =VerticalAlign.Middle
                  Weight: ='TextCanvas.Weight'.Bold
                  Width: =180
                  X: =Parent.Width - 180
            - WhiteScoreCaption:
                Control: Text@0.0.51
                Properties:
                  Align: =Align.Right
                  FontColor: =RGBA(180, 172, 150, 1)
                  Height: =24
                  Size: =12
                  Text: ="WHITE"
                  Weight: ='TextCanvas.Weight'.Semibold
                  Width: =180
                  X: =Parent.Width - 180
                  Y: =70
            - ResetButton:
                Control: Button@0.0.45
                Properties:
                  Appearance: ='ButtonCanvas.Appearance'.Primary
                  BasePaletteColor: =RGBA(246, 240, 224, 1)
                  BorderRadius: =2
                  FontColor: =RGBA(18, 24, 22, 1)
                  FontSize: =14
                  FontWeight: =FontWeight.Semibold
                  Height: =44
                  OnSelect: |-
                    =Clear(colBoard);
                    ForAll(
                      Sequence(64),
                      Collect(
                        colBoard,
                        {
                          Row: RoundDown((Value - 1) / 8, 0) + 1,
                          Col: Mod(Value - 1, 8) + 1,
                          Color: "Empty",
                          IsValid: false
                        }
                      )
                    );
                    UpdateIf(colBoard, Row = 4 And Col = 4, {Color: "White"});
                    UpdateIf(colBoard, Row = 4 And Col = 5, {Color: "Black"});
                    UpdateIf(colBoard, Row = 5 And Col = 4, {Color: "Black"});
                    UpdateIf(colBoard, Row = 5 And Col = 5, {Color: "White"});
                    Set(currentPlayer, "Black");
                    Set(gameOver, false);
                    Set(winnerText, "");
                    Set(lastMessage, "");
                    Set(userColor, "");
                    Set(cpuColor, "");
                    Set(sideChosen, false)
                  Text: ="RESET"
                  Width: =160
                  X: =(Parent.Width - 160) / 2
                  Y: =20
      - GameOverScrim:
          Control: Rectangle@2.3.0
          Properties:
            BorderStyle: =BorderStyle.None
            Fill: =RGBA(0, 0, 0, 0.72)
            Height: =Parent.Height
            Visible: =gameOver
            Width: =Parent.Width
      - GameOverCard:
          Control: GroupContainer@1.5.0
          Variant: ManualLayout
          Properties:
            DropShadow: =DropShadow.Bold
            Fill: =RGBA(246, 240, 224, 1)
            Height: =260
            Visible: =gameOver
            Width: =420
            X: =(Parent.Width - 420) / 2
            Y: =(Parent.Height - 260) / 2
          Children:
            - GameOverEyebrow:
                Control: Text@0.0.51
                Properties:
                  Align: =Align.Center
                  FontColor: =RGBA(220, 68, 52, 1)
                  Height: =24
                  Size: =12
                  Text: ="GAME OVER"
                  Weight: ='TextCanvas.Weight'.Semibold
                  Width: =Parent.Width
                  Y: =40
            - GameOverWinner:
                Control: Text@0.0.51
                Properties:
                  Align: =Align.Center
                  Font: =Font.Georgia
                  FontColor: =RGBA(18, 24, 22, 1)
                  Height: =56
                  Size: =36
                  Text: =winnerText
                  Weight: ='TextCanvas.Weight'.Bold
                  Width: =Parent.Width
                  Y: =72
            - GameOverScores:
                Control: Text@0.0.51
                Properties:
                  Align: =Align.Center
                  FontColor: =RGBA(18, 24, 22, 1)
                  Height: =28
                  Size: =16
                  Text: ="Black " & CountRows(Filter(colBoard, Color = "Black")) & "   ·   White " & CountRows(Filter(colBoard, Color = "White"))
                  Weight: ='TextCanvas.Weight'.Regular
                  Width: =Parent.Width
                  Y: =140
            - GameOverResetButton:
                Control: Button@0.0.45
                Properties:
                  Appearance: ='ButtonCanvas.Appearance'.Primary
                  BasePaletteColor: =RGBA(18, 24, 22, 1)
                  BorderRadius: =2
                  FontColor: =RGBA(246, 240, 224, 1)
                  FontSize: =14
                  FontWeight: =FontWeight.Semibold
                  Height: =44
                  OnSelect: |-
                    =Clear(colBoard);
                    ForAll(
                      Sequence(64),
                      Collect(
                        colBoard,
                        {
                          Row: RoundDown((Value - 1) / 8, 0) + 1,
                          Col: Mod(Value - 1, 8) + 1,
                          Color: "Empty",
                          IsValid: false
                        }
                      )
                    );
                    UpdateIf(colBoard, Row = 4 And Col = 4, {Color: "White"});
                    UpdateIf(colBoard, Row = 4 And Col = 5, {Color: "Black"});
                    UpdateIf(colBoard, Row = 5 And Col = 4, {Color: "Black"});
                    UpdateIf(colBoard, Row = 5 And Col = 5, {Color: "White"});
                    Set(currentPlayer, "Black");
                    Set(gameOver, false);
                    Set(winnerText, "");
                    Set(lastMessage, "");
                    Set(userColor, "");
                    Set(cpuColor, "");
                    Set(sideChosen, false)
                  Text: ="PLAY AGAIN"
                  Width: =180
                  X: =(Parent.Width - 180) / 2
                  Y: =190
      - CpuMoveTimer:
          Control: Timer@2.1.0
          Properties:
            Duration: =600
            Height: =1
            OnTimerEnd: |-
              =If(
                Not sideChosen Or gameOver Or currentPlayer <> cpuColor,
                false,
                With(
                  {
                    legalMoves: Filter(
                      ForAll(
                        Filter(colBoard, Color = "Empty"),
                        {
                          mvRow: Row,
                          mvCol: Col,
                          totalFlips: Sum(
                            ForAll(
                              colDirs,
                              {
                                n: With(
                                     {
                                       steps: ForAll(
                                         Sequence(7),
                                         {
                                           i: Value,
                                           color: With(
                                             { rr: Row + dr * Value, cc: Col + dc * Value },
                                             If(
                                               rr < 1 Or rr > 8 Or cc < 1 Or cc > 8,
                                               "Off",
                                               With(
                                                 { cellA: LookUp(colBoard, Row = rr And Col = cc) },
                                                 If(IsBlank(cellA), "Off", cellA.Color)
                                               )
                                             )
                                           )
                                         }
                                       ),
                                       oppA: If(cpuColor = "Black", "White", "Black")
                                     },
                                     With(
                                       {
                                         stopIdxA: First(
                                           Sort(Filter(steps, color <> oppA), i, SortOrder.Ascending)
                                         )
                                       },
                                       If(
                                         IsBlank(stopIdxA) Or stopIdxA.color <> cpuColor Or stopIdxA.i = 1,
                                         0,
                                         stopIdxA.i - 1
                                       )
                                     )
                                   )
                              }
                            ),
                            n
                          ),
                          posWeight: With(
                            { wr: Row, wc: Col },
                            If(
                              (wr = 1 Or wr = 8) And (wc = 1 Or wc = 8), 120,
                              (wr = 2 Or wr = 7) And (wc = 2 Or wc = 7), -40,
                              ((wr = 1 Or wr = 8) And (wc = 2 Or wc = 7)) Or ((wr = 2 Or wr = 7) And (wc = 1 Or wc = 8)), -20,
                              ((wr = 1 Or wr = 8) And (wc = 3 Or wc = 6)) Or ((wr = 3 Or wr = 6) And (wc = 1 Or wc = 8)), 20,
                              ((wr = 1 Or wr = 8) And (wc = 4 Or wc = 5)) Or ((wr = 4 Or wr = 5) And (wc = 1 Or wc = 8)), 5,
                              (wr = 3 Or wr = 6) And (wc = 3 Or wc = 6), 15,
                              ((wr = 2 Or wr = 7) And (wc >= 3 And wc <= 6)) Or ((wc = 2 Or wc = 7) And (wr >= 3 And wr <= 6)), -5,
                              3
                            )
                          )
                        }
                      ),
                      totalFlips > 0
                    )
                  },
                  If(
                    CountRows(legalMoves) = 0,
                    false,
                    With(
                      {
                        pick: First(Sort(legalMoves, posWeight * 4 + totalFlips, SortOrder.Descending)),
                        player: cpuColor,
                        opp: If(cpuColor = "Black", "White", "Black")
                      },
                      With(
                        {
                          thisRow: pick.mvRow,
                          thisCol: pick.mvCol
                        },
                        With(
                          {
                            flipsByDir: ForAll(
                              colDirs,
                              {
                                dr: dr,
                                dc: dc,
                                count: With(
                                  {
                                    steps: ForAll(
                                      Sequence(7),
                                      {
                                        i: Value,
                                        color: With(
                                          { rr: thisRow + dr * Value, cc: thisCol + dc * Value },
                                          If(
                                            rr < 1 Or rr > 8 Or cc < 1 Or cc > 8,
                                            "Off",
                                            With(
                                              { cellB: LookUp(colBoard, Row = rr And Col = cc) },
                                              If(IsBlank(cellB), "Off", cellB.Color)
                                            )
                                          )
                                        )
                                      }
                                    )
                                  },
                                  With(
                                    {
                                      stopIdxB: First(
                                        Sort(Filter(steps, color <> opp), i, SortOrder.Ascending)
                                      )
                                    },
                                    If(
                                      IsBlank(stopIdxB) Or stopIdxB.color <> player Or stopIdxB.i = 1,
                                      0,
                                      stopIdxB.i - 1
                                    )
                                  )
                                )
                              }
                            )
                          },
                          UpdateIf(colBoard, Row = thisRow And Col = thisCol, {Color: player});
                          ForAll(
                            Filter(flipsByDir, count > 0),
                            ForAll(
                              Sequence(count),
                              UpdateIf(
                                colBoard,
                                Row = thisRow + dr * Value And Col = thisCol + dc * Value,
                                {Color: player}
                              )
                            )
                          );
                          Set(currentPlayer, opp);
                          Set(lastMessage, "CPU played " & Char(64 + thisCol) & thisRow);
                          If(
                            CountRows(
                              Filter(
                                colBoard,
                                Color = "Empty"
                                  And Sum(
                                    ForAll(
                                      colDirs,
                                      {
                                        n: With(
                                             {
                                               steps: ForAll(
                                                 Sequence(7),
                                                 {
                                                   i: Value,
                                                   color: With(
                                                     { rr: Row + dr * Value, cc: Col + dc * Value },
                                                     If(
                                                       rr < 1 Or rr > 8 Or cc < 1 Or cc > 8,
                                                       "Off",
                                                       With(
                                                         { cellC: LookUp(colBoard, Row = rr And Col = cc) },
                                                         If(IsBlank(cellC), "Off", cellC.Color)
                                                       )
                                                     )
                                                   )
                                                 }
                                               ),
                                               oppC: If(currentPlayer = "Black", "White", "Black")
                                             },
                                             With(
                                               {
                                                 stopIdxC: First(
                                                   Sort(Filter(steps, color <> oppC), i, SortOrder.Ascending)
                                                 )
                                               },
                                               If(
                                                 IsBlank(stopIdxC) Or stopIdxC.color <> currentPlayer Or stopIdxC.i = 1,
                                                 0,
                                                 stopIdxC.i - 1
                                               )
                                             )
                                           )
                                      }
                                    ),
                                    n
                                  ) > 0
                              )
                            ) = 0,
                            With(
                              {
                                other: If(currentPlayer = "Black", "White", "Black")
                              },
                              If(
                                CountRows(
                                  Filter(
                                    colBoard,
                                    Color = "Empty"
                                      And Sum(
                                        ForAll(
                                          colDirs,
                                          {
                                            n: With(
                                                 {
                                                   steps: ForAll(
                                                     Sequence(7),
                                                     {
                                                       i: Value,
                                                       color: With(
                                                         { rr: Row + dr * Value, cc: Col + dc * Value },
                                                         If(
                                                           rr < 1 Or rr > 8 Or cc < 1 Or cc > 8,
                                                           "Off",
                                                           With(
                                                             { cellD: LookUp(colBoard, Row = rr And Col = cc) },
                                                             If(IsBlank(cellD), "Off", cellD.Color)
                                                           )
                                                         )
                                                       )
                                                     }
                                                   ),
                                                   oppD: If(other = "Black", "White", "Black")
                                                 },
                                                 With(
                                                   {
                                                     stopIdxD: First(
                                                       Sort(Filter(steps, color <> oppD), i, SortOrder.Ascending)
                                                     )
                                                   },
                                                   If(
                                                     IsBlank(stopIdxD) Or stopIdxD.color <> other Or stopIdxD.i = 1,
                                                     0,
                                                     stopIdxD.i - 1
                                                   )
                                                 )
                                               )
                                          }
                                        ),
                                        n
                                      ) > 0
                                  )
                                ) = 0,
                                Set(gameOver, true);
                                Set(
                                  winnerText,
                                  With(
                                    {
                                      b: CountRows(Filter(colBoard, Color = "Black")),
                                      w: CountRows(Filter(colBoard, Color = "White"))
                                    },
                                    If(b > w, "BLACK WINS", If(w > b, "WHITE WINS", "DRAW"))
                                  )
                                ),
                                Set(
                                  lastMessage,
                                  Upper(currentPlayer) & " had no legal moves — " & Upper(other) & " plays again."
                                );
                                Set(currentPlayer, other)
                              )
                            ),
                            false
                          )
                        )
                      )
                    )
                  )
                )
              )
            Reset: =sideChosen And currentPlayer = userColor
            Start: =sideChosen And Not gameOver And currentPlayer = cpuColor And cpuColor <> ""
            Visible: =false
            Width: =1
      - SideSelectScrim:
          Control: Rectangle@2.3.0
          Properties:
            BorderStyle: =BorderStyle.None
            Fill: =RGBA(0, 0, 0, 0.72)
            Height: =Parent.Height
            Visible: =Not sideChosen
            Width: =Parent.Width
      - SideSelectCard:
          Control: GroupContainer@1.5.0
          Variant: ManualLayout
          Properties:
            BorderStyle: =BorderStyle.None
            DropShadow: =DropShadow.Bold
            Fill: =RGBA(246, 240, 224, 1)
            Height: =340
            Visible: =Not sideChosen
            Width: =480
            X: =(Parent.Width - 480) / 2
            Y: =(Parent.Height - 340) / 2
          Children:
            - SideSelectEyebrow:
                Control: Text@0.0.51
                Properties:
                  Align: =Align.Center
                  FontColor: =RGBA(220, 68, 52, 1)
                  Height: =24
                  Size: =12
                  Text: ="CHOOSE YOUR SIDE"
                  Weight: ='TextCanvas.Weight'.Semibold
                  Width: =Parent.Width
                  Y: =36
            - SideSelectTitle:
                Control: Text@0.0.51
                Properties:
                  Align: =Align.Center
                  Font: =Font.Georgia
                  FontColor: =RGBA(18, 24, 22, 1)
                  Height: =48
                  Size: =30
                  Text: ="Play against CPU"
                  Weight: ='TextCanvas.Weight'.Bold
                  Width: =Parent.Width
                  Y: =68
            - SideSelectSubtitle:
                Control: Text@0.0.51
                Properties:
                  Align: =Align.Center
                  FontColor: =RGBA(100, 94, 80, 1)
                  Height: =22
                  Size: =13
                  Text: ="Black moves first. The opposing color will be played automatically."
                  Weight: ='TextCanvas.Weight'.Regular
                  Width: =Parent.Width - 48
                  X: =24
                  Y: =120
            - PickBlackButton:
                Control: Button@0.0.45
                Properties:
                  Appearance: ='ButtonCanvas.Appearance'.Primary
                  BasePaletteColor: =RGBA(18, 24, 22, 1)
                  BorderRadius: =2
                  FontColor: =RGBA(246, 240, 224, 1)
                  FontSize: =14
                  FontWeight: =FontWeight.Semibold
                  Height: =52
                  OnSelect: |-
                    =Set(userColor, "Black");
                    Set(cpuColor, "White");
                    Set(sideChosen, true)
                  Text: ="PLAY BLACK  (GO FIRST)"
                  Width: =200
                  X: =24
                  Y: =180
            - PickWhiteButton:
                Control: Button@0.0.45
                Properties:
                  Appearance: ='ButtonCanvas.Appearance'.Primary
                  BasePaletteColor: =RGBA(246, 240, 224, 1)
                  BorderRadius: =2
                  FontColor: =RGBA(18, 24, 22, 1)
                  FontSize: =14
                  FontWeight: =FontWeight.Semibold
                  Height: =52
                  OnSelect: |-
                    =Set(userColor, "White");
                    Set(cpuColor, "Black");
                    Set(sideChosen, true)
                  Text: ="PLAY WHITE  (GO SECOND)"
                  Width: =200
                  X: =Parent.Width - 200 - 24
                  Y: =180
            - SideSelectHint:
                Control: Text@0.0.51
                Properties:
                  Align: =Align.Center
                  FontColor: =RGBA(100, 94, 80, 1)
                  Height: =20
                  Size: =11
                  Text: ="You can switch sides any time by tapping RESET."
                  Weight: ='TextCanvas.Weight'.Regular
                  Width: =Parent.Width
                  Y: =260

どうやって作ったか

Claude Code × MCP サーバーという仕組みを使っています。Claude Code に日本語で話しかけると、Power Apps Studio に直接変更が反映される、という構成です。

詳しい仕組みとセットアップ手順は別の動画でまとめています。

コメント

タイトルとURLをコピーしました