コルネさん主催のイベント、【JPPGB】ゲーム作成コンテスト #0のエントリー作品として、Power Appsでリバーシを作成しました。
アイディア賞を受賞しました!コルネさんをはじめとする運営のみなさまありがとうございました!
今回は、作成したリバーシアプリの仕様を紹介します。
→【制作過程編】Power AppsでChatGPTと協力してリバーシを作ってみた
ローカル対戦機能
ローカルプレイの画面です。一手戻ったり、リセットすることが可能です。
CPU対戦機能の実装
開放度理論を駆使して攻めてくるCPUです。3連敗しました。
オンライン対戦機能
SharePointリストに値を保持させることで、オンライン対戦を可能にしました。
タイマーを使用して、Refresh関数で1秒ごとにSharePointリストを更新しています。
リバーシのゲームロジック
主要なロジックはボタンにまとめ、Select関数で呼び出す処理にしました。
ボードの初期化 (ButtonReset)
ゲーム開始時の処理およびオンラインプレイ以外に押すことのできるボタンです。
ColBoardをギャラリーに表示して盤面を再現しています。
ターン終了時の処理(ButtonTurnEnd)
Visible = falseです。
置ける場所の定義と、各方向ごとに置いた場所によってひっくり返せる石を定義しています。
相手の色の石が置かれているマスに絞って処理を行うことで、処理量の削減をしています。
上方向のコードのみ考え適宜修正し、他の方向はChatGPTに指示してコードを書いてもらいました。
WhileとExitが使えないため、ForAll関数とCollect関数でどうにかしました。
Concurrent(
//方向別コレクション初期化
Clear(ColCanPlace),
Clear(ColTempUp),
Clear(ColTempDown),
Clear(ColTempLeft),
Clear(ColTempRight),
Clear(ColTempUpLeft),
Clear(ColTempUpRight),
Clear(ColTempDownLeft),
Clear(ColTempDownRight),
//ColBoardのCanPlaceを全てfalse
UpdateIf(
ColBoard,
true,
{CanPlace:false}
)
);
//隣接マスをColCanPlaceに格納
ForAll(
Filter(
ColBoard,
Color <> RGBA(0, 0, 0, 0),
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
) As Placed,
ForAll(
ColDirections As Direction,
If(
ComponentLogic_1.GetTile(Placed.Row + Direction.Row, Placed.Column + Direction.Col, ColBoard).Color = RGBA(0, 0, 0, 0),
Collect(
ColCanPlace,
ComponentLogic_1.GetTile(Placed.Row + Direction.Row, Placed.Column + Direction.Col, ColBoard)
)
)
)
);
// 上方向
ForAll(
ColCanPlace As CanPlaceTile,
ForAll(
Sequence(7) As Val,
With(
ComponentLogic_1.GetTile(CanPlaceTile.Row - Val.Value, CanPlaceTile.Column, ColBoard) As ThisTile,
If(
And(
!Last(Filter(ColTempUp, CPTValue = CanPlaceTile.Value)).IsStop,
!IsBlank(ThisTile)
),
If(
ThisTile.Color = RGBA(0, 0, 0, 0), // 空白ならCanFlipをfalseにしてループ終了
Collect(ColTempUp, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
UpdateIf(ColTempUp, CPTValue = CanPlaceTile.Value, {CanFlip: false}),
ThisTile.Color <> _PlayerColor, // 違う色ならコレクションに格納して継続
Collect(ColTempUp, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: false, CanFlip: false}),
ThisTile.Color = _PlayerColor, // 同じ色なら
Collect(ColTempUp, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
// 間に違う色がある場合はCanPlaceとCanFlipをtrueにする
If(
!IsEmpty(Filter(ColTempUp, CPTValue = CanPlaceTile.Value, !IsStop)),
UpdateIf(ColBoard, Value = CanPlaceTile.Value, {CanPlace: true });
UpdateIf(ColTempUp, CPTValue = CanPlaceTile.Value, {CanFlip: true})
)
)
)
)
)
);
// 下方向
ForAll(
ColCanPlace As CanPlaceTile,
ForAll(
Sequence(7) As Val,
With(
ComponentLogic_1.GetTile(CanPlaceTile.Row + Val.Value, CanPlaceTile.Column, ColBoard) As ThisTile,
If(
And(
!Last(Filter(ColTempDown, CPTValue = CanPlaceTile.Value)).IsStop,
!IsBlank(ThisTile)
),
If(
ThisTile.Color = RGBA(0, 0, 0, 0), // 空白ならCanFlipをfalseにしてループ終了
Collect(ColTempDown, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
UpdateIf(ColTempDown, CPTValue = CanPlaceTile.Value, {CanFlip: false}),
ThisTile.Color <> _PlayerColor, // 違う色ならコレクションに格納して継続
Collect(ColTempDown, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: false, CanFlip: false}),
ThisTile.Color = _PlayerColor, // 同じ色なら
Collect(ColTempDown, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
// 間に違う色がある場合はCanPlaceとCanFlipをtrueにする
If(
!IsEmpty(Filter(ColTempDown, CPTValue = CanPlaceTile.Value, !IsStop)),
UpdateIf(ColBoard, Value = CanPlaceTile.Value, {CanPlace: true });
UpdateIf(ColTempDown, CPTValue = CanPlaceTile.Value, {CanFlip: true})
)
)
)
)
)
);
// 左方向
ForAll(
ColCanPlace As CanPlaceTile,
ForAll(
Sequence(7) As Val,
With(
ComponentLogic_1.GetTile(CanPlaceTile.Row, CanPlaceTile.Column - Val.Value, ColBoard) As ThisTile,
If(
And(
!Last(Filter(ColTempLeft, CPTValue = CanPlaceTile.Value)).IsStop,
!IsBlank(ThisTile)
),
If(
ThisTile.Color = RGBA(0, 0, 0, 0), // 空白ならCanFlipをfalseにしてループ終了
Collect(ColTempLeft, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
UpdateIf(ColTempLeft, CPTValue = CanPlaceTile.Value, {CanFlip: false}),
ThisTile.Color <> _PlayerColor, // 違う色ならコレクションに格納して継続
Collect(ColTempLeft, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: false, CanFlip: false}),
ThisTile.Color = _PlayerColor, // 同じ色なら
Collect(ColTempLeft, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
// 間に違う色がある場合はCanPlaceとCanFlipをtrueにする
If(
!IsEmpty(Filter(ColTempLeft, CPTValue = CanPlaceTile.Value, !IsStop)),
UpdateIf(ColBoard, Value = CanPlaceTile.Value, {CanPlace: true });
UpdateIf(ColTempLeft, CPTValue = CanPlaceTile.Value, {CanFlip: true})
)
)
)
)
)
);
// 右方向
ForAll(
ColCanPlace As CanPlaceTile,
ForAll(
Sequence(7) As Val,
With(
ComponentLogic_1.GetTile(CanPlaceTile.Row, CanPlaceTile.Column + Val.Value, ColBoard) As ThisTile,
If(
And(
!Last(Filter(ColTempRight, CPTValue = CanPlaceTile.Value)).IsStop,
!IsBlank(ThisTile)
),
If(
ThisTile.Color = RGBA(0, 0, 0, 0), // 空白ならCanFlipをfalseにしてループ終了
Collect(ColTempRight, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
UpdateIf(ColTempRight, CPTValue = CanPlaceTile.Value, {CanFlip: false}),
ThisTile.Color <> _PlayerColor, // 違う色ならコレクションに格納して継続
Collect(ColTempRight, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: false, CanFlip: false}),
ThisTile.Color = _PlayerColor, // 同じ色なら
Collect(ColTempRight, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
// 間に違う色がある場合はCanPlaceとCanFlipをtrueにする
If(
!IsEmpty(Filter(ColTempRight, CPTValue = CanPlaceTile.Value, !IsStop)),
UpdateIf(ColBoard, Value = CanPlaceTile.Value, {CanPlace: true });
UpdateIf(ColTempRight, CPTValue = CanPlaceTile.Value, {CanFlip: true})
)
)
)
)
)
);
// 左上方向
ForAll(
ColCanPlace As CanPlaceTile,
ForAll(
Sequence(7) As Val,
With(
ComponentLogic_1.GetTile(CanPlaceTile.Row - Val.Value, CanPlaceTile.Column - Val.Value, ColBoard) As ThisTile,
If(
And(
!Last(Filter(ColTempUpLeft, CPTValue = CanPlaceTile.Value)).IsStop,
!IsBlank(ThisTile)
),
If(
ThisTile.Color = RGBA(0, 0, 0, 0), // 空白ならCanFlipをfalseにしてループ終了
Collect(ColTempUpLeft, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
UpdateIf(ColTempUpLeft, CPTValue = CanPlaceTile.Value, {CanFlip: false}),
ThisTile.Color <> _PlayerColor, // 違う色ならコレクションに格納して継続
Collect(ColTempUpLeft, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: false, CanFlip: false}),
ThisTile.Color = _PlayerColor, // 同じ色なら
Collect(ColTempUpLeft, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
// 間に違う色がある場合はCanPlaceとCanFlipをtrueにする
If(
!IsEmpty(Filter(ColTempUpLeft, CPTValue = CanPlaceTile.Value, !IsStop)),
UpdateIf(ColBoard, Value = CanPlaceTile.Value, {CanPlace: true });
UpdateIf(ColTempUpLeft, CPTValue = CanPlaceTile.Value, {CanFlip: true})
)
)
)
)
)
);
// 右上方向
ForAll(
ColCanPlace As CanPlaceTile,
ForAll(
Sequence(7) As Val,
With(
ComponentLogic_1.GetTile(CanPlaceTile.Row - Val.Value, CanPlaceTile.Column + Val.Value, ColBoard) As ThisTile,
If(
And(
!Last(Filter(ColTempUpRight, CPTValue = CanPlaceTile.Value)).IsStop,
!IsBlank(ThisTile)
),
If(
ThisTile.Color = RGBA(0, 0, 0, 0), // 空白ならCanFlipをfalseにしてループ終了
Collect(ColTempUpRight, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
UpdateIf(ColTempUpRight, CPTValue = CanPlaceTile.Value, {CanFlip: false}),
ThisTile.Color <> _PlayerColor, // 違う色ならコレクションに格納して継続
Collect(ColTempUpRight, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: false, CanFlip: false}),
ThisTile.Color = _PlayerColor, // 同じ色なら
Collect(ColTempUpRight, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
// 間に違う色がある場合はCanPlaceとCanFlipをtrueにする
If(
!IsEmpty(Filter(ColTempUpRight, CPTValue = CanPlaceTile.Value, !IsStop)),
UpdateIf(ColBoard, Value = CanPlaceTile.Value, {CanPlace: true });
UpdateIf(ColTempUpRight, CPTValue = CanPlaceTile.Value, {CanFlip: true})
)
)
)
)
)
);
// 左下方向
ForAll(
ColCanPlace As CanPlaceTile,
ForAll(
Sequence(7) As Val,
With(
ComponentLogic_1.GetTile(CanPlaceTile.Row + Val.Value, CanPlaceTile.Column - Val.Value, ColBoard) As ThisTile,
If(
And(
!Last(Filter(ColTempDownLeft, CPTValue = CanPlaceTile.Value)).IsStop,
CanPlaceTile.Row + Val.Value <= 7,
CanPlaceTile.Column - Val.Value >= 0
),
If(
ThisTile.Color = RGBA(0, 0, 0, 0), // 空白ならCanFlipをfalseにしてループ終了
Collect(ColTempDownLeft, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
UpdateIf(ColTempDownLeft, CPTValue = CanPlaceTile.Value, {CanFlip: false}),
ThisTile.Color <> _PlayerColor, // 違う色ならコレクションに格納して継続
Collect(ColTempDownLeft, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: false, CanFlip: false}),
ThisTile.Color = _PlayerColor, // 同じ色なら
Collect(ColTempDownLeft, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
// 間に違う色がある場合はCanPlaceとCanFlipをtrueにする
If(
!IsEmpty(Filter(ColTempDownLeft, CPTValue = CanPlaceTile.Value, !IsStop)),
UpdateIf(ColBoard, Value = CanPlaceTile.Value, {CanPlace: true });
UpdateIf(ColTempDownLeft, CPTValue = CanPlaceTile.Value, {CanFlip: true})
)
)
)
)
)
);
// 右下方向
ForAll(
ColCanPlace As CanPlaceTile,
ForAll(
Sequence(7) As Val,
With(
ComponentLogic_1.GetTile(CanPlaceTile.Row + Val.Value, CanPlaceTile.Column + Val.Value, ColBoard) As ThisTile,
If(
And(
!Last(Filter(ColTempDownRight, CPTValue = CanPlaceTile.Value)).IsStop,
!IsBlank(ThisTile)
),
If(
ThisTile.Color = RGBA(0, 0, 0, 0), // 空白ならCanFlipをfalseにしてループ終了
Collect(ColTempDownRight, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
UpdateIf(ColTempDownRight, CPTValue = CanPlaceTile.Value, {CanFlip: false}),
ThisTile.Color <> _PlayerColor, // 違う色ならコレクションに格納して継続
Collect(ColTempDownRight, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: false, CanFlip: false}),
ThisTile.Color = _PlayerColor, // 同じ色なら
Collect(ColTempDownRight, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
// 間に違う色がある場合はCanPlaceとCanFlipをtrueにする
If(
!IsEmpty(Filter(ColTempDownRight, CPTValue = CanPlaceTile.Value, !IsStop)),
UpdateIf(ColBoard, Value = CanPlaceTile.Value, {CanPlace: true });
UpdateIf(ColTempDownRight, CPTValue = CanPlaceTile.Value, {CanFlip: true})
)
)
)
)
)
)
CPUの処理(ButtonCPU)
Visible = falseです。
開放度理論を用いた重みづけのロジックを実装しました。処理が早く、そこそこ強いです。
無限ループになるためSelect関数が利用できませんでした。コンポーネント化しておけばよかったです。
//Select(ButtonTurnEnd)の処理
Concurrent(
//方向別コレクション初期化
Clear(ColCanPlace),
Clear(ColTempUp),
Clear(ColTempDown),
Clear(ColTempLeft),
Clear(ColTempRight),
Clear(ColTempUpLeft),
Clear(ColTempUpRight),
Clear(ColTempDownLeft),
Clear(ColTempDownRight),
//ColBoardのCanPlaceを全てfalse
UpdateIf(
ColBoard,
true,
{CanPlace:false}
)
);
//隣接マスをColCanPlaceに格納
ForAll(
Filter(
ColBoard,
Color <> RGBA(0, 0, 0, 0),
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
) As Placed,
ForAll(
ColDirections As Direction,
If(
ComponentLogic_1.GetTile(Placed.Row + Direction.Row, Placed.Column + Direction.Col, ColBoard).Color = RGBA(0, 0, 0, 0),
Collect(
ColCanPlace,
ComponentLogic_1.GetTile(Placed.Row + Direction.Row, Placed.Column + Direction.Col, ColBoard)
)
)
)
);
// 上方向
ForAll(
ColCanPlace As CanPlaceTile,
ForAll(
Sequence(7) As Val,
With(
ComponentLogic_1.GetTile(CanPlaceTile.Row - Val.Value, CanPlaceTile.Column, ColBoard) As ThisTile,
If(
And(
!Last(Filter(ColTempUp, CPTValue = CanPlaceTile.Value)).IsStop,
!IsBlank(ThisTile)
),
If(
ThisTile.Color = RGBA(0, 0, 0, 0), // 空白ならCanFlipをfalseにしてループ終了
Collect(ColTempUp, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
UpdateIf(ColTempUp, CPTValue = CanPlaceTile.Value, {CanFlip: false}),
ThisTile.Color <> _PlayerColor, // 違う色ならコレクションに格納して継続
Collect(ColTempUp, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: false, CanFlip: false}),
ThisTile.Color = _PlayerColor, // 同じ色なら
Collect(ColTempUp, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
// 間に違う色がある場合はCanPlaceとCanFlipをtrueにする
If(
!IsEmpty(Filter(ColTempUp, CPTValue = CanPlaceTile.Value, !IsStop)),
UpdateIf(ColBoard, Value = CanPlaceTile.Value, {CanPlace: true });
UpdateIf(ColTempUp, CPTValue = CanPlaceTile.Value, {CanFlip: true})
)
)
)
)
)
);
// 下方向
ForAll(
ColCanPlace As CanPlaceTile,
ForAll(
Sequence(7) As Val,
With(
ComponentLogic_1.GetTile(CanPlaceTile.Row + Val.Value, CanPlaceTile.Column, ColBoard) As ThisTile,
If(
And(
!Last(Filter(ColTempDown, CPTValue = CanPlaceTile.Value)).IsStop,
!IsBlank(ThisTile)
),
If(
ThisTile.Color = RGBA(0, 0, 0, 0), // 空白ならCanFlipをfalseにしてループ終了
Collect(ColTempDown, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
UpdateIf(ColTempDown, CPTValue = CanPlaceTile.Value, {CanFlip: false}),
ThisTile.Color <> _PlayerColor, // 違う色ならコレクションに格納して継続
Collect(ColTempDown, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: false, CanFlip: false}),
ThisTile.Color = _PlayerColor, // 同じ色なら
Collect(ColTempDown, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
// 間に違う色がある場合はCanPlaceとCanFlipをtrueにする
If(
!IsEmpty(Filter(ColTempDown, CPTValue = CanPlaceTile.Value, !IsStop)),
UpdateIf(ColBoard, Value = CanPlaceTile.Value, {CanPlace: true });
UpdateIf(ColTempDown, CPTValue = CanPlaceTile.Value, {CanFlip: true})
)
)
)
)
)
);
// 左方向
ForAll(
ColCanPlace As CanPlaceTile,
ForAll(
Sequence(7) As Val,
With(
ComponentLogic_1.GetTile(CanPlaceTile.Row, CanPlaceTile.Column - Val.Value, ColBoard) As ThisTile,
If(
And(
!Last(Filter(ColTempLeft, CPTValue = CanPlaceTile.Value)).IsStop,
!IsBlank(ThisTile)
),
If(
ThisTile.Color = RGBA(0, 0, 0, 0), // 空白ならCanFlipをfalseにしてループ終了
Collect(ColTempLeft, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
UpdateIf(ColTempLeft, CPTValue = CanPlaceTile.Value, {CanFlip: false}),
ThisTile.Color <> _PlayerColor, // 違う色ならコレクションに格納して継続
Collect(ColTempLeft, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: false, CanFlip: false}),
ThisTile.Color = _PlayerColor, // 同じ色なら
Collect(ColTempLeft, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
// 間に違う色がある場合はCanPlaceとCanFlipをtrueにする
If(
!IsEmpty(Filter(ColTempLeft, CPTValue = CanPlaceTile.Value, !IsStop)),
UpdateIf(ColBoard, Value = CanPlaceTile.Value, {CanPlace: true });
UpdateIf(ColTempLeft, CPTValue = CanPlaceTile.Value, {CanFlip: true})
)
)
)
)
)
);
// 右方向
ForAll(
ColCanPlace As CanPlaceTile,
ForAll(
Sequence(7) As Val,
With(
ComponentLogic_1.GetTile(CanPlaceTile.Row, CanPlaceTile.Column + Val.Value, ColBoard) As ThisTile,
If(
And(
!Last(Filter(ColTempRight, CPTValue = CanPlaceTile.Value)).IsStop,
!IsBlank(ThisTile)
),
If(
ThisTile.Color = RGBA(0, 0, 0, 0), // 空白ならCanFlipをfalseにしてループ終了
Collect(ColTempRight, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
UpdateIf(ColTempRight, CPTValue = CanPlaceTile.Value, {CanFlip: false}),
ThisTile.Color <> _PlayerColor, // 違う色ならコレクションに格納して継続
Collect(ColTempRight, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: false, CanFlip: false}),
ThisTile.Color = _PlayerColor, // 同じ色なら
Collect(ColTempRight, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
// 間に違う色がある場合はCanPlaceとCanFlipをtrueにする
If(
!IsEmpty(Filter(ColTempRight, CPTValue = CanPlaceTile.Value, !IsStop)),
UpdateIf(ColBoard, Value = CanPlaceTile.Value, {CanPlace: true });
UpdateIf(ColTempRight, CPTValue = CanPlaceTile.Value, {CanFlip: true})
)
)
)
)
)
);
// 左上方向
ForAll(
ColCanPlace As CanPlaceTile,
ForAll(
Sequence(7) As Val,
With(
ComponentLogic_1.GetTile(CanPlaceTile.Row - Val.Value, CanPlaceTile.Column - Val.Value, ColBoard) As ThisTile,
If(
And(
!Last(Filter(ColTempUpLeft, CPTValue = CanPlaceTile.Value)).IsStop,
!IsBlank(ThisTile)
),
If(
ThisTile.Color = RGBA(0, 0, 0, 0), // 空白ならCanFlipをfalseにしてループ終了
Collect(ColTempUpLeft, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
UpdateIf(ColTempUpLeft, CPTValue = CanPlaceTile.Value, {CanFlip: false}),
ThisTile.Color <> _PlayerColor, // 違う色ならコレクションに格納して継続
Collect(ColTempUpLeft, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: false, CanFlip: false}),
ThisTile.Color = _PlayerColor, // 同じ色なら
Collect(ColTempUpLeft, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
// 間に違う色がある場合はCanPlaceとCanFlipをtrueにする
If(
!IsEmpty(Filter(ColTempUpLeft, CPTValue = CanPlaceTile.Value, !IsStop)),
UpdateIf(ColBoard, Value = CanPlaceTile.Value, {CanPlace: true });
UpdateIf(ColTempUpLeft, CPTValue = CanPlaceTile.Value, {CanFlip: true})
)
)
)
)
)
);
// 右上方向
ForAll(
ColCanPlace As CanPlaceTile,
ForAll(
Sequence(7) As Val,
With(
ComponentLogic_1.GetTile(CanPlaceTile.Row - Val.Value, CanPlaceTile.Column + Val.Value, ColBoard) As ThisTile,
If(
And(
!Last(Filter(ColTempUpRight, CPTValue = CanPlaceTile.Value)).IsStop,
!IsBlank(ThisTile)
),
If(
ThisTile.Color = RGBA(0, 0, 0, 0), // 空白ならCanFlipをfalseにしてループ終了
Collect(ColTempUpRight, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
UpdateIf(ColTempUpRight, CPTValue = CanPlaceTile.Value, {CanFlip: false}),
ThisTile.Color <> _PlayerColor, // 違う色ならコレクションに格納して継続
Collect(ColTempUpRight, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: false, CanFlip: false}),
ThisTile.Color = _PlayerColor, // 同じ色なら
Collect(ColTempUpRight, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
// 間に違う色がある場合はCanPlaceとCanFlipをtrueにする
If(
!IsEmpty(Filter(ColTempUpRight, CPTValue = CanPlaceTile.Value, !IsStop)),
UpdateIf(ColBoard, Value = CanPlaceTile.Value, {CanPlace: true });
UpdateIf(ColTempUpRight, CPTValue = CanPlaceTile.Value, {CanFlip: true})
)
)
)
)
)
);
// 左下方向
ForAll(
ColCanPlace As CanPlaceTile,
ForAll(
Sequence(7) As Val,
With(
ComponentLogic_1.GetTile(CanPlaceTile.Row + Val.Value, CanPlaceTile.Column - Val.Value, ColBoard) As ThisTile,
If(
And(
!Last(Filter(ColTempDownLeft, CPTValue = CanPlaceTile.Value)).IsStop,
CanPlaceTile.Row + Val.Value <= 7,
CanPlaceTile.Column - Val.Value >= 0
),
If(
ThisTile.Color = RGBA(0, 0, 0, 0), // 空白ならCanFlipをfalseにしてループ終了
Collect(ColTempDownLeft, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
UpdateIf(ColTempDownLeft, CPTValue = CanPlaceTile.Value, {CanFlip: false}),
ThisTile.Color <> _PlayerColor, // 違う色ならコレクションに格納して継続
Collect(ColTempDownLeft, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: false, CanFlip: false}),
ThisTile.Color = _PlayerColor, // 同じ色なら
Collect(ColTempDownLeft, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
// 間に違う色がある場合はCanPlaceとCanFlipをtrueにする
If(
!IsEmpty(Filter(ColTempDownLeft, CPTValue = CanPlaceTile.Value, !IsStop)),
UpdateIf(ColBoard, Value = CanPlaceTile.Value, {CanPlace: true });
UpdateIf(ColTempDownLeft, CPTValue = CanPlaceTile.Value, {CanFlip: true})
)
)
)
)
)
);
// 右下方向
ForAll(
ColCanPlace As CanPlaceTile,
ForAll(
Sequence(7) As Val,
With(
ComponentLogic_1.GetTile(CanPlaceTile.Row + Val.Value, CanPlaceTile.Column + Val.Value, ColBoard) As ThisTile,
If(
And(
!Last(Filter(ColTempDownRight, CPTValue = CanPlaceTile.Value)).IsStop,
!IsBlank(ThisTile)
),
If(
ThisTile.Color = RGBA(0, 0, 0, 0), // 空白ならCanFlipをfalseにしてループ終了
Collect(ColTempDownRight, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
UpdateIf(ColTempDownRight, CPTValue = CanPlaceTile.Value, {CanFlip: false}),
ThisTile.Color <> _PlayerColor, // 違う色ならコレクションに格納して継続
Collect(ColTempDownRight, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: false, CanFlip: false}),
ThisTile.Color = _PlayerColor, // 同じ色なら
Collect(ColTempDownRight, {CPTValue: CanPlaceTile.Value, CFTValue: ThisTile.Value, IsStop: true, CanFlip: false});
// 間に違う色がある場合はCanPlaceとCanFlipをtrueにする
If(
!IsEmpty(Filter(ColTempDownRight, CPTValue = CanPlaceTile.Value, !IsStop)),
UpdateIf(ColBoard, Value = CanPlaceTile.Value, {CanPlace: true });
UpdateIf(ColTempDownRight, CPTValue = CanPlaceTile.Value, {CanFlip: true})
)
)
)
)
)
);
//Weight列を追加したColCPU列の定義
ClearCollect(
ColCPU,
AddColumns(
Filter(ColBoard, CanPlace),
"Weight",
Value(Not(Value in [1, 9, 8, 15, 14, 6, 48 , 49, 57, 54, 55, 62])) * 10
)
);
//開放度理論で重みづけ
ForAll(
Filter(ColBoard, CanPlace) As Board,
ForAll(
ColDirections As Direction,
If(
ComponentLogic_1.GetTile(Board.Row + Direction.Row, Board.Column + Direction.Col, ColBoard).Color = RGBA(0, 0, 0, 0),
With(
LookUp(
ColCPU,
Value = Board.Value
),
Patch(
ColCPU,
ThisRecord,
{Weight:ThisRecord.Weight - 1}
)
)
)
)
);
UpdateIf(ColCPU, Value in [0, 7, 56, 63], {Weight:100});
//ColBoardを一番重みが大きいマスで更新
With(
First(DropColumns(SortByColumns(ColCPU,"Weight", SortOrder.Descending),"Weight")) As CPUPlace,
Patch(
ColBoard,
CPUPlace,
{
Value: CPUPlace.Value,
Row: CPUPlace.Row,
Column: CPUPlace.Column,
Color: _PlayerColor
}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempUp, CPTValue = CPUPlace.Value, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempDown, CPTValue = CPUPlace.Value, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempLeft, CPTValue = CPUPlace.Value, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempRight, CPTValue = CPUPlace.Value, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempUpLeft, CPTValue = CPUPlace.Value, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempUpRight, CPTValue = CPUPlace.Value, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempDownLeft, CPTValue = CPUPlace.Value, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempDownRight, CPTValue = CPUPlace.Value, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
)
);
//プレイヤー交代
Set(_PlayerColor, ComponentLogic_1.GetEnemyColor(_PlayerColor));
Select(ButtonTurnEnd)
盤面 (GalleryBoard)
置いた場所によって事前に処理しておいた各方向のコレクションで石をひっくり返す処理を行います。
If(
_GameMode <> 3,
ClearCollect(
ColPreBoard,
ColBoard
),
//ターンを相手に渡す
With(
LookUp(ReversiOnline, ID = _SessionID) As Session,
Patch(
ReversiOnline,
Session,
{PlaceValue: ThisItem.Value, Turn:If(TextInputUser.Text = Session.BlackUser, Session.WhiteUser, Session.BlackUser)}
)
)
);
Patch(
ColBoard,
ThisItem,
{Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempUp, CPTValue = ThisItem.Value, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempDown, CPTValue = ThisItem.Value, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempLeft, CPTValue = ThisItem.Value, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempRight, CPTValue = ThisItem.Value, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempUpLeft, CPTValue = ThisItem.Value, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempUpRight, CPTValue = ThisItem.Value, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempDownLeft, CPTValue = ThisItem.Value, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempDownRight, CPTValue = ThisItem.Value, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
//プレイヤー交代
Set(_PlayerColor, ComponentLogic_1.GetEnemyColor(_PlayerColor));
//CPU個別処理
If(
_GameMode = 2,
Select(ButtonCPU),
Select(ButtonTurnEnd)
)
オンラインプレイ時に相手からターンを渡された時の処理
Visible = falseです。
Defaultプロパティに自分のターンかどうかの判別式を入れているので、自分のターンになるとOnCheckの数式が発動します。
With(
LookUp(ReversiOnline, _SessionID = ID) As Session,
If(
!IsBlank(Session.PlaceValue),
If(
LookUp(ColBoard, Value = Session.PlaceValue, Color) = RGBA(0, 0, 0, 0),
Refresh(ReversiOnline);
UpdateIf(
ColBoard,
Value = Session.PlaceValue,
{Color:_PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempUp, CPTValue = Session.PlaceValue, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempDown, CPTValue = Session.PlaceValue, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempLeft, CPTValue = Session.PlaceValue, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempRight, CPTValue = Session.PlaceValue, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempUpLeft, CPTValue = Session.PlaceValue, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempUpRight, CPTValue = Session.PlaceValue, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempDownLeft, CPTValue = Session.PlaceValue, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
UpdateIf(
ColBoard,
And(
Value in Filter(ColTempDownRight, CPTValue = Session.PlaceValue, CanFlip).CFTValue,
Color = If(_PlayerColor = RGBA(0, 0, 0, 1), RGBA(255, 255, 255, 1), RGBA(0, 0, 0, 1))
),
{ Color: _PlayerColor}
);
//プレイヤー交代
Set(_PlayerColor, ComponentLogic_1.GetEnemyColor(LookUp(ColBoard, Value = Session.PlaceValue, Color)));,
//相手がパスした時
Set(_PlayerColor, LookUp(ColBoard, Value = Session.PlaceValue, Color))
);
Select(ButtonTurnEnd)
)
)
コンポーネント
コンポーネントを2つ作成しました。共通化はあまり考えなかったです。
GetTile:行、列を入力するとそのタイルの情報を取得できる関数
GetEnemyColor:黒を入力すると白が、白を入力すると黒が返ってくる関数
終わりに
素敵なイベントを企画・運営していただいた、コルネさんをはじめとするみなさま、ありがとうございました!
ぜひ投票をお願いします。
コメント