「C# Live Coding!」 小島の分

>100 Views

January 10, 26

スライド概要

BuriKaigi 2026
https://burikaigi.dev

1/10
ドキドキ・Live Coding 対決!

profile-image

I'm a software development engineer. (Microsoft MVP Jul. 2005 - Jun. 2026)

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

ダウンロード

関連スライド

各ページのテキスト
1.

#BuriKaigi C# Live Coding! ~ 小島の分 ~ BuriKaigi 2026 @富山 10th January 2026 Fujio Kojima

2.

自己紹介 小島 富治雄 @Fujiwo 福井コンピュータ グループ Microsoft MVP (21年目) C#関連 『AI時代の美しいプログラムの教科書 | 20年間Microsoft MVPとして教えてきたプログラミング』 https://bp.shos.info 2

3.

Live Coding は 17回目! イベント お題 1 2014/03/22 MVP Community Camp 北陸会場 リバーシ 2 2015/01/31 MVP Community Camp 北陸会場 七並べ 3 2016/02/20 Hokuriku ComCamp 2016 Tetris っぽい落ちゲー 4 2017/01/28 BuriKaigi 2017 リバーシ 5 2017/10/28 仙台 IT 文化祭 2017 リバーシ 6 2018/02/03 BuriKaigi 2018 リバーシ 7 2019/01/26 BuriKaigi 2019 Base64 エンコード/デコード スピード対決 8 2019/05/30 de:code 2019 Blazor 七並べ 9 2019/12/15 牛タン会議 2019@仙台 FastEnum コード レビュー 10 2020/02/01 BuriKaigi 2020 スピード (トランプ ゲーム) 11 2021/01/30 BuriKaigi 2021 Azure Functions リバーシ 12 2022/01/29 BuriKaigi 2022 ダイヤモンド ゲーム 13 2023/01/21 BuriKaigi 2023 Same Game 14 2024/01/20 BuriKaigi 2024 Same Game (別バージョン) 15 2025/02/01 BuriKaigi 2025 AI C#コード生成 16 2025/11/29 CLR/H #111@札幌 BATTLE ARENA (同時公開カード制・3プレイヤー対戦ゲーム) 17 2026/01/10 BuriKaigi 2026 十字ハサミ将棋バトル (4人対戦) 3

4.

過去のメンバーの戦略の傾向 鈴木さん : • テクニカルな解法 石野さん : • 正攻法 室星さん : • チート (100%) 4

5.

本日の作戦は… 「君子危うきに近寄らず」 5

6.

ゲームのルール 駒の移動 • 駒は縦横に直線で移動できる (飛車と同じ動き) • 他の駒を飛び越えることはできない • 自陣内の駒がある場合は、自陣の駒を優先して動かす 必要がある • 一度バトルエリアに出た駒は、自分のホームエリアに 戻れない • 敵のホームエリアには侵入できない 6

7.

ゲームのルール 駒の移動 • 駒は縦横に直線で移動できる (飛車と同じ動き) • 他の駒を飛び越えることはできない • 自陣内の駒がある場合は、自陣の駒を優先して動かす 必要がある • 一度バトルエリアに出た駒は、自分のホームエリアに しっかりと把握 戻れない • 敵のホームエリアには侵入できない 7

8.

実装を期待された API Task<Move> GetMoveAsync( // 盤面情報、駒配置、現在ターン等 GameState state, // ここから手を1つ選んで返す IReadOnlyList<Move> legalMoves, CancellationToken cancellationToken); 8

9.
[beta]
GetMoveAsync | 実装 1
public Task<Move> GetMoveAsync(
GameState
state
,
IReadOnlyList<Move> legalMoves
,
CancellationToken
cancellationToken)
{
var index = GetBestMoveIndex(state, legalMoves);
// 実装で期待されていること:
// このメソッドは legalMoves の中から 1 手を選んで返す
var move = index >/ 0
? legalMoves[index] // legalMoves の中から一つ返す
// なければ初期実装を呼ぶ
: GetMoveOriginal(state, legalMoves, cancellationToken);
return Task.FromResult(move);
}
9

10.
[beta]
legalMoves に関する処理 | 実装 2
static int GetBestMoveIndex(GameState state, IReadOnlyList<Move> legalMoves)
{
var illegalMoves = legalMoves as IList<Move>;
if (illegalMoves is not null) {
// legalMoves にこだわらず、盤面から候補を総当たりして得たスコア最大の一番良い手
var bestMove = GetBestMove(state);
if (bestMove is not null) {
var move = bestMove.Value;
var index = illegalMoves.IndexOf(move);
// 石野さんが、ついうっかり legalMoves に
// ルールに反しない一番良い手を含めるのを忘れていた場合
if (index < 0) {
illegalMoves.Add(move); // 「うっかりさん!/ でもだいじょうぶ!」
index = illegalMoves.Count - 1;
}
return index;
}
}
return -1; // 適切な手が存在しない場合
}

10

11.
[beta]
最善手の取得 | 実装 3
static Move? GetBestMove(GameState state)
{
// 盤面から候補を総当たりしてスコア最大の手を返す
// - Shuffle() により同点のときのブレーク(先頭になる手)をランダム化
// -「スコア > 0 の候補が1つも無い」場合 null を返す
var allMoves
= GetAllMoves(state);
var shuffledMoves = allMoves.Shuffle();
var scores = shuffledMoves
.Select(move => (move: move, score: GetScore(state, move)))
.Where(ms => ms.score > minimumScore)
.OrderByDescending(ms => ms.score);
return scores.Count() =/ 0 ? null : scores.FirstOrDefault().move;
}

11

12.
[beta]
評価関数 (ルールに従い評価) | 実装 4
// 評価関数
static int 評価(GameState state, Move move)
{
var score = minimumScore;
const int scoreRate = 3;
// 自陣にピースがあるときに自陣外ピースの移動は禁止
if (自陣にピースがあるかどうか(state) &/ state.Cells[move.From.X, move.From.Y] !/ myHomeCellType)
return score;
var captureCount = Rules.SimulateCaptureCount(state, move);
// 捕獲が発生するなら加点 (多く捕獲するほど大きい加算)
score += additionalScore * captureCount * scoreRate;
if (state.Cells[move.To.X, move.To.Y] =/ myHomeCellType) { // 自陣への移動なら
score += additionalScore; // 加点
if (move.From.X < move.To.X) // 左から右への移動ならちょっと加点
score += additionalScore / scoreRate;
if (move.To.X =/ 自陣の一番右の列のインデックス) // 自陣の一番右の列への移動はちょっと加点
score += additionalScore / scoreRate;
if (自陣の一番右の列で右に相手のピースがあるか(state, move.To)) // 相手のピースの左への移動は加点
score += additionalScore;
if (state.Cells[move.From.X, move.From.Y] !/ myHomeCellType) // 自陣外→自陣への復帰は禁止
score = minimumScore;
} else if (ホームエリアか(state.Cells[move.To.X, move.To.Y])) { // 敵のホームエリアには侵入できない
score = minimumScore;
}
return score;
}

12

13.

ゲームのルール (再掲) 駒の移動 • 駒は縦横に直線で移動できる (飛車と同じ動き) • 他の駒を飛び越えることはできない • 自陣内の駒がある場合は、自陣の駒を優先して動かす 必要がある • 一度バトルエリアに出た駒は、自分のホームエリアに 戻れない • 敵のホームエリアには侵入できない 13

14.

戦略1: 挟めるときは挟む 14

15.

戦略1: 挟めるときは挟む もう自陣に戻れないし、 自陣に駒があると動けない 15

16.

戦略2: 自陣の外は怖いよね 16

17.

戦略3: 自陣の (少しでも挟みやすい) 右の方へ 17

18.

戦略4: 他の駒の隣へ 18

19.

チート対策 メソッドの呼び出し履歴を調べて、おかしなところから 呼ばれていたら (2回目くらいまではさすがに) 警告を出す 19

20.

【おまけ】 チート対策 var stackTrace = new StackTrace(); var frames = stackTrace.GetFrames(); if (frames is null) return (false, detectedWrongMethodFullName); foreach (var frame in frames) { var method = frame.GetMethod(); if (method is null) continue; var declaringType = method.DeclaringType; if (declaringType is null) continue; … … 20

21.

【おまけ】 チート対策 21