Slide 1

Slide 1 text

やり方は一つだけじゃない、 正解だけを目指さず寄り道やその先まで 自分流に楽しむ趣味プログラミングの探求 2025-11-15 YAPC::Fukuoka すぎゃーん (@sugyan) 1

Slide 2

Slide 2 text

自己紹介 use v5.42; use utf8; my $self = { 名前 => ' すぎゃーん (@sugyan)', 所在 => ' 京都', 職業 => ' ソフトウェアエンジニア', 言語 => ['Perl', 'Python', 'Rust', 'Go', 'OCaml', 'TypeScript'], 趣味 => ' プログラミング', }; 2

Slide 3

Slide 3 text

趣味: プログラミング 業務以外の時間を使ってコードを書く アイドル追いかけた遠征先でのライブの合間に 子どもたちを寝かしつけた後に そのとき興味があることに対し自由に取り組む Bot, ディープラーニング, 将棋, OSS, ... 楽しいから飽きずに15年以上続いている 3

Slide 4

Slide 4 text

プログラミングの必要性 AIがコードを書いてくれる時代に突入 人間がわざわざコードを書く必要は無くなっていく 必要無いなら書かなくて良い? 否、楽しいから書く! 4

Slide 5

Slide 5 text

プログラミングの面白さ 計算機の能力を最大限に引き出せる 「動くものを作る」ことが楽しい 自分の発想をコードで形にできる やり方は一つではない (There's More Than One Way To Do It) 小さな工夫が劇的な改善を生むことがある 他の人の書くコードから学びを得られる 5

Slide 6

Slide 6 text

プログラミングの楽しみ方 もちろん人それぞれ OSSを作る Webサービスを作る 新しい言語を学ぶ 競技プログラミング ... 6

Slide 7

Slide 7 text

Advent of Code のすゝめ 7

Slide 8

Slide 8 text

Advent of Code とは http://adventofcode.com/ Eric Wastl 氏によって運営 毎年12月に25日まで毎日出題されるパズルを解く 入力が与えられ、そこから解を導く 2015年から開始していて昨年で10周年 自分は2019年頃から参加 日本の参加者も増えてはいるが、まだ少なめ 8

Slide 9

Slide 9 text

Advent of Code の特徴 パズルは毎日part1とpart2があり、入力は各partで共通 part1を正解するとpart2が解放される 同じ入力に対して異なる解釈・処理をして別の解を求める 例: 2024 Day 4。 part1は"XMAS"を、part2は交差(X)の"MAS"を探す MMMSXXMASM MSAMXMSMSA AMXSXMAAMM MSAMASMSMX XMASAMXAMM XXAMMXXAMA SMSMSASXSS SAXAMASAAA MAMMMXMMMM MXMXAXMASX 9

Slide 10

Slide 10 text

Advent of Code の特徴 入力はユーザーごとに異なる (当然、解も異なる) 競技プログラミングと違ってparseが面倒な場合も 例: 2024 Day 13 Button A: X+94, Y+34 Button B: X+22, Y+67 Prize: X=8400, Y=5400 Button A: X+26, Y+66 Button B: X+67, Y+21 Prize: X=12748, Y=12176 ... 10

Slide 11

Slide 11 text

Advent of Code の特徴 提出するのは解答のみ 競技プログラミングなどと違ってコードは提出しない どのように解を求めても良い どのプログラミング言語を使用しても (プログラミングせずに手計算で解いても!) どれだけ時間をかけて解いても良い 実際には多少のアルゴリズム・データ構造の知識が求められる 再帰、幅or深さ優先探索、最短経路、... 11

Slide 12

Slide 12 text

Advent of Code の面白さ より現実に近い(かもしれない)プログラミング 優しくない入力をparseする 解答を導くのに必要な情報を判断し抽出する part1とpart2に上手く対応する 処理負荷の増大だったり 理不尽な仕様変更だったり 多くの場合は共通化・抽象化が可能 豊富な題材 数学的なもの、ライフゲーム、迷路、エミュレータ、… 12

Slide 13

Slide 13 text

意外性 (例: 2019 Day 13) 「整数値列を扱う独自の処理系を仕様通り実装し、与えられた入力を読 み込み実行するとブロック崩しゲームが起動する。最後まで崩し終わっ た後のスコアが解となる」(!?) 13

Slide 14

Slide 14 text

Advent of Code の楽しみ方 色んなコードの書き方に挑戦できる 新しく学ぶ言語の練習として丁度良い 洗練されたコードを目指したり、Golfや奇抜なものを考えたり Reddit で様々な解法が共有されている 勿論GitHubで公開されているものも多数 日本語の解説記事は少なめ。少しずつ書いて公開中 問題や解を求める過程を可視化すると面白いものも 14

Slide 15

Slide 15 text

私とAdvent of Code 回答をGitHubで公開 https://github.com/sugyan/adventofcode 主にRustで、Python, OCamlなどでも挑戦 pub trait Day { type Input; type Error: std::error::Error + 'static; type Answer1: Display; type Answer2: Display; fn part1(input: &Self::Input) -> Self::Answer1; fn part2(input: &Self::Input) -> Self::Answer2; } 15

Slide 16

Slide 16 text

YAPCで発表するにあたって2024年の問題をPerlでも回答 use v5.38; use feature 'class'; class Base { field $fh : param; field $lines = []; field $input; ADJUST { while ( defined( my $line = <$fh> ) ) { chomp $line; push $lines->@*, $line; } } method input() { return $input //= $self->parse($lines); } method parse($lines) { return $lines; } method part1() { die "Not implemented" } method part2() { die "Not implemented" } } 16

Slide 17

Slide 17 text

やり方は一つだけじゃない (TMTOWTDI) 17

Slide 18

Slide 18 text

例: 2018 Day 5 part1 大文字、小文字のアルファベットからなる長い文字列が与えられる r と R のように隣接する2文字が同じ文字で大文字/小文字が異なる ものを取り除く 最終的に残る文字列の長さを求める dabAcCaCBAcCcaDA -> dabAaCBAcCcaDA -> dabCBAcCcaDA -> dabCBAcaDA 18

Slide 19

Slide 19 text

模範解答 (?) スタックを用意して1文字ずつ読み込んでいく 末尾と次の文字との組み合わせが条件にマッチしたらpop そうでない場合はpush 最後の文字まで読み込んだ後のスタックのサイズが解になる 判定方法も色々 c0 != c1 and c0.upper() == c1.upper() ord(c0) ^ ord(c1) == 32 事前にmappingを作っておく、など 19

Slide 20

Slide 20 text

Perl Mongerなら正規表現でGolf! 効率の悪さなんて気にしない #!perl -pl s/(.)(?!\1)(?i)\1//&&redo;$_=length BEGIN { $/ = "\n"; $\ = "\n"; } LINE: while (defined($_ = readline ARGV)) { chomp $_; redo if s/(.)(?!\1)(?i)\1//; $_ = length $_; } continue { die "-p destination: $!\n" unless print $_; } 20

Slide 21

Slide 21 text

例: 2024 Day 4 part1 Pythonで2次元座標探索を複素数で実現 class Solution: def __init__(self, input) -> None: self.grid = { x + 1j * y: c for y, line in enumerate(input) for x, c in enumerate(line.strip()) } def part1(self) -> int: return Counter( "".join(self.grid.get(p + d * n, "") for n in range(4)) for p in self.grid for d in [1, 1 + 1j, 1j, -1 + 1j, -1, -1 - 1j, -1j, 1 - 1j] )["XMAS"] 21

Slide 22

Slide 22 text

可視化によって見えるもの 22

Slide 23

Slide 23 text

例: 2024 Day 14 part2 2次元平面を動き回る点が クリスマスツリーを描く (!?) p=0,4 v=3,-3 p=6,3 v=-1,-3 p=10,3 v=-1,2 p=2,0 v=2,-1 p=0,0 v=1,3 p=3,0 v=-2,-2 p=7,6 v=-1,-3 p=3,0 v=-1,-2 p=9,3 v=2,3 p=7,3 v=-1,2 ... 23

Slide 24

Slide 24 text

例: 2024 Day 18 part2 2次元平面( 71x71 )上に1つずつ壁が降ってくる 左上から右下に辿り着けなくなるのは何番目のときか? 5,4 4,2 4,5 3,0 2,1 6,3 2,4 1,5 0,6 ... 24

Slide 25

Slide 25 text

これも色々な解法が考えられる 順番にBFSしていって到達確認しても求められる より速く求めるなら二分探索を使う 逆順でUnion-Find、という方法や Widest path problem として解くことも 可視化する必要はないが、やってみると面白い 25

Slide 26

Slide 26 text

Advent of Code のすゝめ まとめ プログラミングを楽しみながら解を導く 競技プログラミングとはまた別軸の鍛錬にもなる 他の参加者の異なる解法も見ていくとより面白い 解答する以外にも楽しみ方がある 多言語で実装してみる、可視化ツールを作ってみる 日本語圏でも盛り上がりたい! 一緒に同じ問題に取り組んでわいわいしましょう 今年からは半分の12日間になるとのこと 26

Slide 27

Slide 27 text

付録: Advent of Code と生成AI Q: AIに解かせるのはどうなの? A: No。人間が解いて楽しむためのパズルです 自分の回答コードをレビューしてもらったり、より良い実装へ改善する ための相談などに使うのは良いと思う If you send a friend to the gym on your behalf, would you expect to get stronger? “ “ 27

Slide 28

Slide 28 text

身近にあるパズルや問題 28

Slide 29

Slide 29 text

Pentomino (ペントミノ) ポリオミノの一種 面積5の12種類のピースを配置して長方形を埋める 多くの解があることは既に知られている 6x10 には 2,339通り 5x12 には 1,010通り 4x15 には 368通り 3x20 には 2通り 29

Slide 30

Slide 30 text

百均で子どもが興味を示したので買ってみた 多くの試行が必要で、人間が解くには難しい… →プログラミングの出番だ! ではどう解く? 30

Slide 31

Slide 31 text

Pentominoを解く 基本的には試行しながらの探索 バックトラッキング 左上から順に配置してみて、ぶつかったり埋められない隙間がで きたら戻る とはいえ計算量が膨大 12種類の選ぶ順番だけで (=479,001,600)通り 効率的に解に辿り着くための工夫が要る 31

Slide 32

Slide 32 text

Bitboardでの判定 各マスが空いているか埋まっているか、の状態をビットで表す 埋めるべきタイル、各ピースをそれぞれ64bit整数値で表現可能 ピースの位置移動はビットシフトで実現できる tile & piece != 0 で衝突判定可能 00000000 00010000 000000000 00000000 00010000 000000000 00000000 00110000 000000000 00011000 00010000 000100000 00011000 & 00000000 -> 000000000 00000000 00000000 000000000 00000000 00000000 000000000 00000000 00000000 000000000 103481868288 & 271585296 == 268435456 (!= 0) 32

Slide 33

Slide 33 text

将棋ライブラリの実装での知識が役に立った 駒の効きの計算などで使用 最も左上で空いているマスの検出もCPU命令を使って取得可能 x86_64なら bsf 命令、aarch64なら clz 命令 Rustなら u64::trailing_ones() あとは対象マスごとの候補ピースを事前計算するなどの工夫 33

Slide 34

Slide 34 text

Pentominoを解けた! …何をもって「解けた」とする? 解のうち1つを導出できたら? それともすべての解を出す? 結果を何らかの形でレンダリングできたら? ターミナルで? パフォーマンスはそれで問題ない? 速いとはいえ数秒〜数十秒かかる 34

Slide 35

Slide 35 text

さらなる高速化、WASM化へ 調査し、より効率的な探索方法を模索 短辺から埋める "X型"を最初に配置する Bitboardの反転/回転 巨大テーブルによるループ効率化 孤立点検出による枝刈り https://memo.sugyan.com/entry/2023/10/11/160000 そしてWebAppへ 35

Slide 36

Slide 36 text

自作Pentomino Solver https://sugyan.com/pentomino-solver-webapp/ ブラウザで動かせる スマホでも 高速 全解答を数十msで列挙 子どもに自慢できる!! フロントエンドは本業ではないがこれくらい作れると便利 36

Slide 37

Slide 37 text

だんご屋のひまつぶし https://be-en.co.jp/products/bog-039 パズルオーディションで最優秀賞し商品化 ハノイの塔の亜種(?) 問題集が同梱、初級(5〜6手)から特級(〜14手)まで掲載 37

Slide 38

Slide 38 text

これもやってみると意外と難しい 最高難度は14手…? 最短解を求めるには…? → プログラミングの出番だ! 38

Slide 39

Slide 39 text

組み合わせの列挙、グラフ問題へ まずは状態が幾つあるのかを考える 数の配置だけで考えると 10通り 3色x2個ずつの塗り分けは で 90通り つまり全部で900通りの状態が存在する だんごの移動1手が、この900通りの中での状態遷移と見なせる 39

Slide 40

Slide 40 text

状態と状態が線(だんごの移動)でつながる 900頂点 3,240辺無向グラフが形成できる 任意の2状態は最短経路を求めれば最短解が出せる! 最高難度の組み合わせは? グラフの直径を求める Floyd–Warshall algorithm または900頂点すべてから最長のものを列挙 実際には16手が最長であることが分かった 40

Slide 41

Slide 41 text

自作Dango Solver https://sugyan.com/hima-dango/ ブラウザで動かせる スマホでも 高速 一瞬で最短解導出 Dangoエディタ搭載 子どもに自慢できる!! 41

Slide 42

Slide 42 text

身近なパズルや問題がプログラミングで解ける アルゴリズムやデータ構造の知識がちゃんと役に立つ 単にパズルを解くだけ、よりも楽しめる 自由な発想を自分で形にできる 子どもに自慢できる!! 42

Slide 43

Slide 43 text

まとめ プログラミングでパズルを解く話を紹介 Advent of Code Pentomino、だんご屋のひまつぶし 正解を導く/目的を達成する、だけがすべてではない 趣味だからこそ、好きなだけ 満足するまで探求できる プログラミングは楽しい 解きたい問題、書きたい/読みたいコードは無限にある 43

Slide 44

Slide 44 text

There's More Than One Way To Enjoy Programming 44

Slide 45

Slide 45 text

ありがとうございました! 45