プロジェクト概要
このプログラムは、競馬のシミュレーションアプリです。静岡大学の峰野研究室での夏休み課題として利用され、ユーザーが競馬のレース予測や馬券購入を楽しめるような機能が実装されています。本プロジェクトでは、GUIによる操作性の向上やAIによる予測機能を備えたユーザーフレンドリーなインターフェースを実現しています。
主な機能の説明
馬券購入画面(AI予想付き)
馬券購入画面では、ユーザーがAIの予測を参考にしながら、好きな馬に賭けることができます。
レース画面(購入馬券のハイライト表示)
購入した馬券の馬がレース中に色付きで表示され、視覚的にレースを楽しめます。
オッズ計算画面(自動差分計算機能)
オッズ計算画面では、異なる馬の組み合わせに対するオッズの差分が自動的に計算され、適切な賭け金の設定に役立ちます。
使用ライブラリ
本プログラムで使用している主なライブラリは以下の通りです。
-
pandas
: レースデータの処理 -
PySimpleGUI
: GUIの構築 -
pickle
: 学習モデルの保存と読み込み -
playsound
: サウンド再生
全ライブラリのインポートは以下のようになっています。
import random
import time
import datetime
import pandas
import PySimpleGUI
import sys
import os
import pickle
import warnings
from playsound import playsound
各機能の詳細
観戦モード
「観戦モード」では、レース予測は行わず、レース観戦のみが可能です。アプリ起動時にモード選択画面が表示され、観戦モードを選ぶとその後のレースは予測不可の観戦モードになります。
def viewing_mode_gui():
layout = [[sg.Text('観戦モードにしますか?')],
[sg.Button('いいえ', button_color=(None, '#dc3545')), sg.Button('はい')]]
window = sg.Window('--競馬シミュレーションアプリ--', layout, size=(400,75), element_justification='center')
event, values = window.read()
if event == sg.WIN_CLOSED:
sys.exit()
window.close()
return event, values
馬情報
レースに参加する馬は各属性(馬番、馬名、騎手、調子、タイプ)の情報を持ちます。各レースには6頭の馬が参加し、それぞれの馬の属性はランダムに設定されます。重複の有無を選択しながら、必要な数の馬情報を生成します。
def random_select(all, num, deplication):
list = []
if deplication == None:
for a in random.sample(all, num):
list.append(a)
elif deplication == True:
for a in range(num):
for b in random.sample(all, 1):
list.append(b)
return list
レース情報
レースの属性(レース長、天気、グラウンドタイプ、レース名)をランダムに設定します。
# レース情報の各属性リスト
all_length = [1000, 1600, 2000, 2500]
all_weather = ['雨', '曇り', '晴れ']
all_ground = ['芝', 'ダート']
all_race_name = ['有馬記念','菊花賞','大阪杯','桜花賞','天皇賞','宝塚記念','皐月賞']
# 使用例
length = random_select(all_length, 1, True)
weather = random_select(all_weather, 1, True)
ground = random_select(all_ground, 1, True)
race_name = random_select(all_race_name, 1, True)
レースの反復処理
レース終了後、所持金があれば次のレースに継続するか確認画面が表示されます。
def Yes_or_No_gui():
layout = [[sg.Text('このまま次のレースに参加しますか?')],
[sg.Button('いいえ'), sg.Button('はい', button_color=(None, '#dc3545'))]]
window = sg.Window('--競馬シミュレーションアプリ--', layout, size=(400,75), element_justification='center')
event, values = window.read()
if event == sg.WIN_CLOSED:
sys.exit()
window.close()
return event, values
サウンド再生
プログラムの要所でサウンドを再生します。playsound
ライブラリを使用し、バックグラウンド再生も可能です。
playsound("XXX.mp3")
playsound("XXX.mp3", None)
激アツモード
5%の確率で「激アツモード」に突入し、そのレースのオッズが5倍になります。確率に応じたサウンドも再生されます。
if random.randint(1,100) >= 95:
playsound("チャンス用サウンド.mp3")
if random.randint(1,5) >= 3:
playsound("激アツモード突入用サウンド.mp3")
gekiatu = 1
馬券の種類
馬券は3種類あり、単勝、複勝、2連複で賭けることができます。不適切な入力がある場合はエラーメッセージを表示し、再入力を促します。
def predict_input_gui(money):
layout = [[sg.Text('予想してください(馬番を入力しないことも可能です)')],
[sg.Text('所持金[¥]: ' + str(money))],
[sg.Text('単勝: '), sg.Input(default_text='馬番', size=(4,5), justification='center'), sg.Text('賭け金[¥]: '), sg.Input(default_text='数字', size=(8,5), justification='center')],
[sg.Text('複勝: '), sg.Input(size=(4,5), justification='center'), sg.Text('賭け金[¥]: '), sg.Input(size=(8,5), justification='center')],
[sg.Text('2連複: '), sg.Input(size=(2,5), justification='center'), sg.Text("—"), sg.Input(size=(2,5), justification='center'), sg.Text('賭け金[¥]: '), sg.Input(size=(8,5), justification='center')],
[sg.Button('次へ')]]
window = sg.Window('--競馬シミュレーションアプリ--', layout, size=(600,170), element_justification='center', text_justification='center')
event, values = window.read()
if event == sg.WIN_CLOSED:
sys.exit()
window.close()
return event, values
オッズ計算アルゴリズム
オッズは馬の能力やレース情報に基づいて決定されます。「激アツモード」が発動するとオッズが変動します。また、馬券の種類ごとに異なるオッズが適用されます。
レース処理アルゴリズム
レースの進行は複数の関数で実現されています。各馬の進行速度やゴールの判定、順位決定のために、データフレームに記録しながら順位を確定します。
AI予想
LightGBMで学習済みのAIモデルを利用し、各馬の勝率を予測します。さらに、レース情報やAIの予測に基づいて、AIがレースに対するコメントを出力します。
def ai_predict(lane, num, size, all_length, gs, output):
ai_predict = []
lane_sum = []
lane_base = 0
max_ai_predict =
-1
comment = ""
# 確率予測
for a in range(num):
sum = 0
for b in range(1, size):
if b == 4:
if race_info[1] == all_length[0]:
sum += 8 - lane[a][b]
elif race_info[1] == all_length[1]:
sum += lane[a][b]
elif race_info[1] == all_length[2]:
sum += 2 * lane[a][b]
elif race_info[1] == all_length[3]:
sum += 2 ** lane[a][b]
else:
sum += lane[a][b]
lane_sum.append(sum * (output[a] + 1))
lane_base += lane_sum[a]
for c in range(num):
ai_predict_lane = round(lane_sum[c] / lane_base, 2)
ai_predict.append(ai_predict_lane)
if ai_predict_lane > max_ai_predict:
max_ai_predict = ai_predict_lane
if max_ai_predict >= 0.35:
comment = "今回は自信ありますよ~!!"
elif max_ai_predict <= 0.25:
comment = "今回は予想するのが難しいですね~"
if gs == 0:
comment += "大波乱の予感がします!!"
elif gs == 1:
comment += "レースは少し荒れそうな感じがします"
elif gs == 2:
comment += "可もなく不可もないレースになりそうです"
elif gs == 3:
comment += "馬場の状態は良さそうですね"
elif gs == 4:
comment += "手堅い結果になると思います!!"
return ai_predict, comment
マイページ