0:00 MX テレビは葛西臨海公園の映像か。これはいい。 江戸川区はあまりにも広いので探索していなかった。特に南西部は未踏だ。 番組をほとんど観て寝る。

8:15 起床。午前中に現金書留が来るように手配したので、それまでは部屋にいる必要がある。 あとは洗濯日であるので、汚れ物を放り込んで洗濯機を回す。 朝飯は納豆とレーズンロール。

スッキリを観ながら待つ。プログラムを書き始めると没頭して呼び鈴に気づかないということがあり得る。

麻雀牌リテラルオブジェクトの表現があまりにも面倒なのを解決しないと行けない気がする。 字牌の東を表すのに TILE_EAST_WIND とかいちいちタイプするのはつらい。 結局インタビューでよく見る

3899m3457p88s南白発

のようなパターンから牌を生成するテスト用の関数を実装。

11:15 配達人到着。ズッシリとした書留を受け取る。急いで福祉事務所に行って午後の面会を取り消さねば。 小銭が入った現金書留とはいかにも訳ありだ。

というわけで外出する。隅田公園経由で区役所三階へ。 受付で S 氏への伝言を頼むが、係員が気を利かせて本人を呼ぼうとする。 S 氏が昨日の面会で時刻指定の約束をしたということは、この時間帯は何か仕事が入っていると推測する。 私はその邪魔をしたくない。したがって伝言で済ませたい。しかしこの意図を窓口で汲んでもらうのは至難。 代理の人を呼ぶと言って待っていると、結局 S 氏本人が窓口に現れる。いや申し訳ない。

書留が配達されたことを伝えて区役所を出る。いいンコが出たからよしとするか。

蒸し暑いのと、散歩用のタオルを物干し竿に忘れてきたこともあり、部屋に戻って少し休む。 少しのつもりがコードを書き殴っていると午後寸前になる。

14:00 ビッグエー墨田業平店。144 円。

  • メンチカツドッグ
  • コッペパンホイップ&カス

柳島児童遊園で食ってから横川コミュニティー会館図書室に行く。 新聞ときのうまでと別の確率本を読む。

ハローワーク墨田で求人検索。16:15 ファミリーマート江東橋一丁目店でコピー。20 円。 またハローワークに戻って二階で現金書留を開封。封筒の中に見慣れた封筒が入っている。 生活扶助費ウン万円を確かに受領した。

このタイミングでタイトー F ステーションオリナス錦糸町店に移動して 4 クレ遊ぶと日記に書かねばならないのはバツが悪い。 面接が流れたので浮いた交通費で遊んだと思って欲しい。

ビートマニア ARENA モード。ダブル B3 で同段位二人とマッチメイク。 2-2-2-1 でなんとトップ。シングル皆伝に勝った……。

このゲーセンは配置換えをしたらしく、MJ コーナーが音楽コーナーの隣になっている。 これは移動が楽だ。裏がダンスラッシュでプレイ中だと爆音で他家の発声が聞こえない?

【SCORE】
合計SCORE:-11.9

【最終段位】
四人打ち段位:魔神 幻球:16

【7/7の最新8試合の履歴】
1st|-*------
2nd|--**-*--
3rd|----*--*
4th|------*-
old         new

【順位】
1位回数:1(14.29%)
2位回数:3(42.86%)
3位回数:2(28.57%)
4位回数:1(14.29%)
平均順位:2.43

プレイ局数:32局

【打ち筋】
アガリ率:21.88%(7/32)
平均アガリ翻:3.43翻
平均アガリ巡目:10.71巡
振込み率:18.75%(6/32)

【7/7の最高役】
・跳満

18:40 カスミオリナス錦糸町店。336 円。鶏カシューナッツ麻婆豆腐丼。

19:05 ビッグエー墨田業平店。227 円。

  • シュークリーム
  • 大きなおむすび鮭
  • ふっくらおむすび明太子

19:20 向島の部屋に戻る。白ブリーフ一丁になって晩飯。 しばらくしてから PC を電話ボックスへ持ち込みに行く。

今日はカンニング。シャンテン数のアルゴリズムを自分で考えるのはもう疲れた。 一般的なシャンテン数の求め方を調べる。数式があるらしい。 シャンテン数、出来面子の数、搭子対子の個数をそれぞれ $s$, $m$, $p$ とすると次の式が成り立つ。

\[s = 2m - p.\]

そこまでは理解できる。問題は搭子の選択方法で、一度組み合わせに取った牌は除外して考えるべきとある。 あー、ほとんどゴールの前まで来ていたのか。

23:30 シャンテン数ほぼ完成。残りは字牌パートの処理。テストケースをもっと増やそう。 というか、まだ涼しくならないので消灯の機運が高まらない。

Technical Notes

Python のコードを書くときには pdb の(短縮)命令名とカブる識別子を使ってはならない。

Programming Notes

シャンテン数を計算するロジックを記す。見えない部分は collections.Counter を駆使した簡単な探索コードだ。

def count_shanten_std(player_hand: Union[Counter, Iterable]) -> int:
    """Count the shanten number of player's hand to 4-melds-1-pair form.

    >>> count_shanten_std(tiles.tiles('3899m3457p88s南白発'))
    4
    >>> count_shanten_std(tiles.tiles('3899m3457p88s南発発'))
    3
    >>> count_shanten_std(tiles.tiles('389m3457p888s南発発'))
    2
    >>> count_shanten_std(tiles.tiles('89m23457p888s南発発'))
    1
    >>> count_shanten_std(tiles.tiles('88m23457p888s南発発'))
    1

    >>> count_shanten_std(tiles.tiles('112233m258p39s西中'))
    4

    >>> count_shanten_std(tiles.tiles('1112345678999s'))
    0
    """

    if not isinstance(player_hand, Counter):
        player_hand = Counter(player_hand)

    if sum(player_hand.values()) != 13:
        raise NotImplementedError

    part_m = player_hand & FILTER_CHARACTERS
    part_p = player_hand & FILTER_CIRCLES
    part_s = player_hand & FILTER_BAMBOOS
    part_m, part_p, part_s = (tiles.convert_suit_to_number(suit_part)
                              for suit_part in (part_m, part_p, part_s))

    melds_m, melds_p, melds_s = (
        remove_melds(suit_part, _all_melds_suit) for suit_part in (
            part_m, part_p, part_s))
    pairs_m, pairs_p, pairs_s = (
        remove_pairs(suit_part, _all_pairs_suit) for suit_part in (
            part_m, part_p, part_s))

    hand_h = player_hand & FILTER_HONORS
    melds_h = remove_melds(hand_h, _all_melds_honor)
    pairs_h = remove_pairs(hand_h, _all_pairs_honor)

    num_shanten = 8
    num_shanten -= sum(len(melds) for melds in (
        melds_m, melds_p, melds_s, melds_h)) * 2
    num_shanten -= sum(len(pairs) for pairs in (
        pairs_m, pairs_p, pairs_s, pairs_h))

    return num_shanten