8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

🎯Numbers3&4の当選番号を予測する『MAGI』システムを作る - UI&演出編

Posted at

1. はじめに

どうも、趣味でデータ分析している猫背なエンジニアです。

え~宝くじで一攫千金したくないですか?
宝くじの当選番号を予測するシステムを長年愛してやまない『新世紀エヴァンゲリオン』に登場するMAGIシステムをコンセプトに、つくりたい!そうしたい!と思って開発記録を書いていきます。ついに最終章です。この記事ではUI&演出編と題し、既存の投稿プロセスにエヴァぽく装飾作ったことに対して紹介します。

2. これまでの「🎯Numbers3&4の当選番号を予測する『MAGI』システムを作る」

これまでのエヴァンゲリオン.png

西暦2025年。
あるエンジニアは、繰り返される敗北の記録——「宝くじの外れ券」の山に終止符を打つべく、ひとつの意思決定機構を構築する決意を固めた。
その名は―― N-MAGIシステム。
モデル名はMELCHIOR、BALTHASAR、CASPER。
それぞれが異なる思考ロジックを持ち、合議によって“もっともらしい当選数字”を導き出す。
ベースとなったのは、かつて存在した神話と、そして…アニメ『新世紀エヴァンゲリオン』の意志決定AI。
過去のデータ、時系列学習、出現頻度、逆張りアルゴリズム。それらを融合させ、抽選数字の予測という“人類補完計画”にも似た夢を追い求める開発者の姿があった。

すべては「当てたい」という欲望と、「遊びたい」という本能のままに。

っていう茶番はおいといて...本編に入ります👍

3. Outputで装飾は必要なのか?

現時点でのシステムでは、結果をtext表示しています。
これに関しては見やすいという人もいるのですが、背景色がどうしてもXの設定した背景色に依存してしまうので、個人的な意見としては直感的にわかりにくいと思いました。
サービスを提供するうえで視覚的な難があるのは破綻している気がするので、今回はこの部分を改善したいと思います

4. 現状と改善策

■ 現状のUI&演出
現在の出力結果のUIは以下のようになっています。

当初は見やすさと簡易性を重視して作りました。これを作成したときに最大のデメリットとして、文字数制限がある。ということでした。そのため、私が表現したいアウトプットではないし、必要な情報を視覚的に理解するのは悪い...。
また、投稿に関しては結構カツカツの文字数で、試行錯誤してAPIエラーが出ないように頑張りました(笑)
そのため現状のUIを踏まえて一新することとしました。
要求は2つです。

■ 要求1 : 画像で表現する
伝記概要の記事の際に、以下のような画像を作ってポストするというように最終的にしたいと考えていました。

これに近いものを作成したいと思っています。以前の記事でASCIIアートを用いて出力するものがあったと思いますが、その技術を用いて今回も作成していきたいと思います。

■ 要求2 : 2枚の画像で構成
Twitter APIでは基本的に4枚まで同時にツイートできます。
その機能を使って1枚目には本日の予測番号と当選番号を表示したもの。2枚目には明日の予測番号を表示という2枚体制でツイートするように変更したいと思います。※1枚目は次回に実装します(笑)

■ 全体フロー
図で表現すると以下のような全体のフローになります。現状では予測した番号をcsvなどに一時保存して蓄積していくスタイルで設計します。

image.png

4. いざコーディング!

以下のようにASCIIアートを付与したものをコーディングしました。
DOS窓とPythonを混ぜた技術を使っているので、まさに現代の魔物になっており、会社では絶対にできない錬金をしたコードになっています(笑)

UIアーキ
import os
import shutil
from PIL import Image, ImageDraw, ImageFont

def print_right_aligned(text_lines):
    columns = shutil.get_terminal_size().columns
    for line in text_lines:
        print(line.ljust(columns))

def right_pad(text, width):
    return text.rjust(width)

def render_text_to_image(lines, save_path, font_size=17, font_color=(255, 153, 51), bg_color=(0, 0, 0)):
    font_path = "C:\\Windows\\Fonts\\consola.ttf"  # Consolas固定幅フォント
    font = ImageFont.truetype(font_path, font_size)

    # 幅・高さを決める
    max_width = max(len(line) for line in lines)
    img_width = max_width * font_size // 1.7 - 35
    img_height = len(lines) * (font_size + 5)

    # 画像生成
    img = Image.new("RGB", (int(img_width), int(img_height)), color=bg_color)
    draw = ImageDraw.Draw(img)

    y = 0
    for line in lines:
        draw.text((10, y), line, font=font, fill=font_color)
        y += font_size + 5

    img.save(save_path)
    print(f"出力テキストを画像化しました: {save_path}")

def display_numbers(numbers3_casper, numbers3_balthasar, numbers3_melchior,
                    numbers4_casper, numbers4_balthasar, numbers4_melchior):
    os.system("")
    orange = "\033[38;2;255;153;51m"
    reset = "\033[0m"

    logo = [
        "╔══════════════════════════════════════════════════════╗",
        "║ ███╗    ██╗     ███╗   ███╗ █████╗  ██████╗ ███████╗ ║",
        "║ ██╔██╗  ██║     ████╗ ████║██╔══██╗██╔════╝ ██╔════╝ ║",
        "║ ██║╚██╗ ██║████╗██╔████╔██║███████║██║ ████╗█████╗   ║",
        "║ ██║ ╚██╗██║╚═══╝██║╚██╔╝██║██╔══██║██║  ╚██║██╔══╝   ║",
        "║ ██║  ╚████║     ██║ ╚═╝ ██║██║  ██║╚██████╔╝███████╗ ║",
        "║ ╚═╝   ╚═══╝     ╚═╝     ╚═╝╚═╝  ╚═╝ ╚═════╝ ╚══════╝ ║",
        "╚══════════════════════════════════════════════════════╝"
    ]

    os.system("cls")
    # logo 表示
    numbers3_lines = [
        f"╔═NUMBERS3═══════╗",
        f"║ CASPER     {numbers3_casper}",
        f"║ BALTHASAR  {numbers3_balthasar}",
        f"║ MELCHIOR   {numbers3_melchior}",
        f"╚════════════════╝"
    ]

    numbers4_lines = [
        f"╔═NUMBERS4════════╗",
        f"║ CASPER     {numbers4_casper}",
        f"║ BALTHASAR  {numbers4_balthasar}",
        f"║ MELCHIOR   {numbers4_melchior}",
        f"╚═════════════════╝"
    ]

    # 横に並べる
    combined_lines = []
    for l3, l4 in zip(numbers3_lines, numbers4_lines):
        combined_lines.append("         " + l3 + "    " + l4)

    # 画面出力
    for line in combined_lines:
        print(orange + right_pad(line, 60) + reset)

    # スクリーンショット代わりにテキスト画像化
    all_lines = logo + [""] + combined_lines
    image_path = "D:/01.開発/06Numbers3/msdos_screenshot.png"
    render_text_to_image(all_lines, image_path)

■表示結果

6. おわりに

MAGIっぽいUIで投稿できており、久しぶりに良い完成で感極まっています(笑)

7. 次回予告

次回予告_最終章.png

すべての開発者に祝福を。

7. MAGI伝記

1. 【作戦概要】:全体構想と設計方針
  - 全体構想と設計方針
2. 【データ収集編】:過去の当選番号の収集
  - 過去の当選番号をどう集める?
3. 【モデル構築編】:3種のモデル(CASPER / BALTHASAR / MELCHIOR)実装と精度比較
  - CASPER / BALTHASAR / MELCHIORの実装と精度比較
4. 【投稿編】:X APIを用いた投稿
  - X APIを用いて予測を自動投稿
5. 【UI&演出編】:MAGI風UIをMS-DOSで再現して、予測を視覚化!
  - MS-DOSでMAGI風UIを構築

謝辞

今年の10月に30周年を記念すること、誠におめでたく思っております。前回の「庵野秀明展」に引き続き「30周年記念展ALL OF EVANGELION」にもぜひ行きたいと思っております。引き続き応援しています!

8
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?