📖 いちばん大事なおはなし
公園で「いま遊びたい人」を集めて、
同じ遊びができそうな友だち同士をチームにする係です。
flowchart LR A["🧒 子どもたち
やりたいこと
あいている時間
いまの場所"] --> B["🧠 コンピュータ"] B --> C["❌ あそべない人"] B --> D["⭐ ふたりの点数"] B --> E["🧩 できたチーム"]
図 — 入ってきた人を分けて、チームをつくる
データベースやネットは使いません。おもちゃ箱ひとつ(このファイルだけ)で動きます。
🧰 ファイルの中は 8 つの引き出し
flowchart TB F["matching_demo.py"] F --> A["① CONFIG
ルールの数字"] F --> B["② TYPES
ものの形"] F --> C["③ SCENARIOS
お話のセット"] F --> D["④ 時間の道具"] F --> E["⑤ 点数の道具"] F --> F5["⑥ 本番の流れ"] F --> G["⑦ 結果プリント"] F --> H["⑧ main
スタートボタン"]
図 — 上から下へ読むと、そのままプログラムの順番
① CONFIG
「何点以上で合格?」などの数字ルール。
PAIR = 0.60 / GROUP = 0.70
③ SCENARIOS
練習用のお話 A〜E。
build_scenarios()
④ 時間の道具
あいている時間のかさなりを計算。
intersect / clip
⑤ 点数の道具
やりたいこと・場所などで星をつける。
*_match_score
⑥〜⑧ 流れ
門番→ペア→グループ→印刷→起動。
run_matching / main
📦 ものの形(クラス / 構造体)
プログラムの「入れもの」です。
ぜんぶ @dataclass(frozen=True)=いったん作ったら中身を書き換えないカードです。
flowchart TB SC["Scenario
お話セット"] --> CA["Candidate
子どもカード"] SC --> BE["Beacon
場所カード"] SC --> PR["Profile
プロフィール"] CA --> TI["TimeInterval
空き時間"] RUN["MatchingResult
結果セット"] --> EX["Exclusion
おやすみ理由"] RUN --> PS["PairScore
ふたりの点数"] RUN --> MG["MatchedGroup
できたチーム"] PS --> FS["FactorScores
7つの星"] MG --> FS
図 — どの入れものが、どの入れものを持つか
TimeInterval
⏱️ 空き時間のひとコマ
「何時から何時まで空いているか」を1本の線で表します。
Candidate
🧒 いま遊びたい人のカード
マッチングに入る「いま」の状態。門番チェックとペア採点の材料になります。
Beacon
📍 遊ぶ場所のカード
図書館・カフェなどの場所。広さや、同時に何組まで遊べるかを書きます。
Profile
🪪 学科と友だち
点数の「学科」「友だち」の材料。Candidate とは別のカードです。
FactorScores
⭐ 7つの星(要因点)
意図・時間・場所など、ひとつずつ 0〜1 の星。
weighted_total() で重みをかけて総合点にします。
PairScore
🤝 ふたりの点数カード
子ども2人についての採点結果。総合点が 0.60 以上なら「線」として残ります。
Exclusion
🚫 おやすみ理由
門番で落ちた人のメモ。点数はつけません。
MatchedGroup
🧩 できたチーム
2〜5人のチーム1つ分。総合点と、選びやすさの点(人数ボーナス込み)を持ちます。
MatchingResult
📋 結果セット
run_matching が返すおみやげ袋。印刷はこの中身を見ます。
Scenario
📖 お話セット A〜E
デモ用の「いま」と参加者・場所をひとまとめにした箱。コマンドで名前を選んで動かします。
flowchart LR
SC["Scenario お話"] --> RUN["run_matching"]
RUN --> MR["MatchingResult 結果"]
MR --> PR["print_report 表示"]
図 — お話 → 実行 → 結果袋 → プリント
🌊 全体の流れ(いちばんの川)
入口は run_matching。ここで全部がつながります。
flowchart TD MAIN["main
シナリオを選ぶ"] --> RUN["run_matching"] RUN --> GATE["filter_eligible
門番チェック"] GATE --> OUT1["除外された人"] GATE --> OK["残った人"] OK --> PAIR["score_pair
ふたりずつ点数"] PAIR --> FORM["form_groups
チームづくり"] FORM --> REP["print_report
3つのお知らせ"] OUT1 --> REP PAIR --> REP
図 — スタートから結果プリントまで
sequenceDiagram
participant あなた
participant main
participant run_matching
participant 門番 as filter_eligible
participant 点数 as score_pair
participant チーム as form_groups
participant 印刷 as print_report
あなた->>main: --scenario A
main->>run_matching: 子どもたちを渡す
run_matching->>門番: 入れる?
門番-->>run_matching: OKの人 / ダメな人
loop ふたりずつ
run_matching->>点数: AとBはなかよし?
点数-->>run_matching: 点数カード
end
run_matching->>チーム: グループにして!
チーム-->>run_matching: できたチーム
main->>印刷: 結果を見せて
印刷-->>あなた: ターミナルに表示
図 — だれがだれに頼むか
🚦 門番さん filter_eligible
遊べない人は、ここで「おやすみ」になります。点数はまだつけません。
flowchart TD
C["🧒 子ども"] --> Q1{"まだ有効?"}
Q1 -->|いいえ| X1["❌ inactive"]
Q1 -->|はい| Q2{"あいている時間ある?"}
Q2 -->|いいえ| X2["❌ NO_AVAILABILITY"]
Q2 -->|はい| Q3{"準備15分あとでも
30分以上ある?"}
Q3 -->|いいえ| X3["❌ 時間たりない"]
Q3 -->|はい| Q4{"あそべる場所ある?"}
Q4 -->|いいえ| X4["❌ 場所なし"]
Q4 -->|はい| OK["✅ 通過!"]
図 — 門番のチェックリスト
なぜ 15 分? → 「集まる準備の時間」。そのあと最低 30 分あそべないとチームにしません。
⭐ 点数タイム score_pair
ふたりを見て「なかよし度」を 0.00〜1.00 でつけます。
0.60 未満は「まだ友だち未満」で、チームの線になりません。
7つの星の大きさ(重み)
flowchart LR
A["🧒 A"] --- S["⭐ score_pair"]
B["🧒 B"] --- S
S --> F["7つの小さな点"]
F --> T["合計点"]
T --> G{"≥ 0.60 ?"}
G -->|Yes| EDGE["線として残す"]
G -->|No| DROP["線にしない"]
図 — ふたりのカードから一本の線ができるか
やりたいこと
おなじ遊びの重なり。勉強どうしなら高い。
overlap_coefficient
時間
かさなる分数。長いほど高い。
time_match_score
場所
同じ場所◎、同じ建物○、遠い×。
location_match_score
友だち / 学科
小さく加点。シナリオ E で差が見える。
friend / department
🧩 チームづくり form_groups
線でつながった人から、2〜5人のチームを探します。
いちばんよさそうなチームから取って、使った人はもう使いません。
flowchart TD
P["合格したペアの線"] --> C["2人,3人,4人,5人の候補"]
C --> S{"グループ点 ≥ 0.70 ?"}
S -->|No| NG["捨てる"]
S -->|Yes| R["いい順に並べる"]
R --> G["貪欲ピック
使った人は再利用しない"]
G --> T1["チーム1"]
G --> T2["チーム2"]
G --> L["あまった人"]
図 — パズルのようにチームを取る(シナリオ C がわかりやすい)
flowchart LR
subgraph Before["まえ"]
U1["u001"]
U2["u002"]
U3["u003"]
U4["u004"]
U5["u005"]
U6["u006"]
end
subgraph After["あと(例: C)"]
G1["チーム1
study 3人"]
G2["チーム2
lunch 2人"]
Alone["ひとり
wellness"]
end
Before --> After
図 — 大勢から複数チーム+あまり、が出る様子
📇 関数いちらん(なにをする係?)
時間の道具
| 関数 | やさしい意味 |
|---|---|
merge_intervals | となり合う時間をくっつけてひとつにする |
intersect_intervals | ふたりの時間が重なるところだけ残す |
clip_intervals_after | 「いま+15分」より前を切り落す |
common_minutes_after_prep | 準備後に何分かさなるか数える |
remaining_minutes_after_prep | ひとりの残り時間を数える |
点数の道具
| 関数 | やさしい意味 |
|---|---|
overlap_coefficient | 同じ好きの重なり具合 |
time_match_score | 分数 → 星(0 / 0.5 / 0.75 / 1) |
location_match_score | 場所の近さの星 |
select_beacon_for_members | チームの遊ぶ場所を選ぶ |
FactorScores.weighted_total | 7つの星を重みつきで合計 |
本番の流れ
| 関数 | やさしい意味 |
|---|---|
filter_eligible | 門番。ダメな人を外す |
score_pair | ふたりの点数カードを作る |
form_groups | チームを貪欲に作る |
run_matching | 上の3つをつなぐキャプテン |
print_report | 除外 / ペア / グループを表示 |
main | コマンドを読んでスタート |
お話セット A〜E
A
うまくいく!チームが1つできる。
B
時間が足りない。門番で止まる。
C
6人。チームが2つ+あまり。
D
すでに予約あり。チームなし。
E
友だち・学科の点の差が見える。
▶️ 動かしてみよう
ターミナルで、お話をひとつ選んで実行します。
flowchart LR CMD["コマンド"] --> OUT1["[1] Exclusions
おやすみの人"] CMD --> OUT2["[2] Pair scores
ふたりの点数"] CMD --> OUT3["[3] Groups
できたチーム"]
図 — いつも同じ3つのお知らせが出る