経緯
フロントエンドの勉強を始める
→息抜きにポーカーの勉強を始める
→とりあえずエド・ミラーのポーカースクール ──ライブゲームで勝つを読み始める
→図表が全くないし、文章だけだとスターティングハンド表を覚えにくい
→ちょうど勉強していたNext.jsで作りました!
PC版 | SP版 |
---|---|
目的
ポーカーのスターティングハンド表を作成します。ハンド表はエド・ミラーのポーカースクールを参考にします。
Webアプリとして実装し、PCやスマホのブラウザからいつでも閲覧できるものを作成します。
参考:ポーカーのスターティングハンドとは
ポーカーの一般的なルールの1つであるテキサスホールデムにおいては、各プレイヤーに最初に配られる2枚の手持ちカード(スターティングハンド) と、3枚→1枚→1枚の順でめくられる5枚の場のカード(コミュニティカード)の全7枚から5枚を選んで役を作ります。
うち、プリフロップと呼ばれる最初の段階では、配られた2枚のカードだけを元にゲームを降りるか(フォールド)、ゲームに参加するか(コール)、賭け金を吊り上げてゲームに参加するか(レイズ)を決めます。
この段階では場のカードが公開されておらず情報が少ないため、ある程度決まった戦略が確立されています。スターティングハンド表は、手持ちのハンド2枚をインプットに、初手でFold/Call/Raiseのどれを行うべきかを示した表となります。
スターティングハンド表 イメージ図
要件定義(ざっくり)
- 動的コンテンツを含まないため、フロントエンドのみで作成します。
Next.js
で実装し、Vercel
にデプロイします。APIやDBは建てません。 - スターティングハンド表のデータ部分は「エド・ミラーのポーカースクール ──ライブゲームで勝つ」を情報源とし、jsonファイルに書き起こして一緒にデプロイします。
- 巷のスターティングハンド表には、自分の手番等の情報が考慮されていない、もしくは考慮されていてもその分表が増えて記憶・比較しづらいものなどがあります。本アプリでは、同書籍に倣って 「自分がどの手番か(アーリー/ボタン/...」「前の手番のレイズ有無とその傾向(タイト/ルース)を考慮に入れ、かつラジオ選択により容易に比較できるようにすることを目指します。
- 大会の途中でこっそり見ることも考慮し、スマホ/PC両方に対応させます。
実装
1. 簡易データベース作成(SpreadSheet)
本に記載されているプリフロップ戦略をcsvファイルとして書き起こします。今回はGoogle SpreadSheetを使って整理しました。
ポケットの情報(pocket
列)と自分のポジション(position
列)をキーとして、前の手番毎の戦略(sNoRaise
, sRaiseTight
, ...)を転記します。他、レンダリング位置を決めるのに参照するX, Y座標(axisX
列, axisY
列)も記載します。
2. プロトタイプ作成(d3.js)
データの可視化によく使われるフレームワークd3.js
を用いてプロトタイプを作ります。
実装先はobservablehq.comとしました。ノートブックの公開機能だけでなく、簡単なUIを作成できたり、便利な可視化のテンプレ集があるなど、簡易な可視化プラットフォームとしては十分すぎる機能を持っています。
※本来これができた時点で開発を終了する予定でしたが、凡例配置の難しさやスマホから見る利便性を考えて、結局Webアプリ化することにしました。
https://observablehq.com/d/bcb9c186f7495591
3. 本実装(Next. js)
本番のWebアプリを実装します。以下、詰まったりこだわったりしたポイントを記載します。
- 書き起こしたcsvファイルを
Next.js
で読み込む方法を模索しましたが、結局CSVからJSONコンバータを使って事前変換する方針を採用しました。 - cssは
tailwind css
を導入し、jsxファイルの各コンポーネントのクラスにそのまま記載しました。PCの2カラム編成をSPでは1カラムにするレスポンシブ対応は、通常のクラスにsm
やlg
プレフィックスをつけることで対応します。
{/* 抜粋 */}
<div className='container mx-auto'>
<div className="grid xs:grid-cols-1 lg:grid-cols-6 lg:gap-3">
<div className="lg:col-start-1 lg:col-span-5"><Grid/></div>
<div className="lg:col-start-6 lg:col-span-1"><Form /><Legends /></div>
</div>
</div>
{/* 抜粋 */}
- 状態管理は
React Hooks
を使いました。useContext()
とuseState()
を駆使することで、異なるコンポーネント間での状態の連携をpropsリレーなしにシンプルに実装することができます。 - ページ読み込み時のアニメーションは
framer-motion
を使って実装しました。
残りの改善点
- 各セルが、スート(同じ柄の手札)かオフスート(別の柄の手札)かどっちなのかがパッと見でわかりにくい。現在は既存の表と同様に右上をスート、左下をオフスートとしているが、より視覚的に分かりやすくなるような工夫をしたい。
- ファビコンをいい感じにしたいが方法がよく分からない
終わりに
PokerSnowieや他有料サービスにはもっといい感じのものがあるだろうな、、と思いつつ、やはり書くことで覚えられると信じて作りました。リングゲームの片手間に見ていただけると嬉しいです
参考資料