wassup?

新ブログ→memo.wass80.xyz

SpreadSheetでトランザクションを管理してポーカー大会をした

この記事はSpreadsheets/Excel Advent Calendar 2018の最終日の記事です。

adventar.org

tl;dr

  • Google Spreadsheetにポーカーチップのやり取りを書く。
  • Google Apps Scriptでポーカーチップの変化とランキングをかっこよく出す。

f:id:wass80:20181222230118p:plain

ポーカー

ポーカーをご存知ですか?トランプゲームのやつです。日本で広く知られているのは5枚配られ、1回交換して、強い役を作って楽しむゲームです。または、1枚配ってのインディアン・ポーカーのほうが有名かもしれません。

海外において主流なのはテキサスホールデムポーカーです。 世界で最も賞金の高い大会としても知られています。 積み上がっているお札がやばい。 www.youtube.com

ポーカー大会

というわけでサークルでポーカー大会をすることにしました。 1日でやっても良かったのですが、2時間程度のテーブルを14日開催する形式にしました。

チップのやり取りの管理のために、Spreadsheetの力を借りました。 別の手の抜き方として、Firebaseを使うことも考えましたが、 やり取りの入力をするのが自分だけであることからOverkillな感じがしました。参加者も20人程度だったので大丈夫でしょう。

見た目

セキリュティーやプライバシーのためにサイトそのものの公開はしませんが、見た目はこんな感じです。

f:id:wass80:20181222231134p:plain

Spreadsheetそのものよりは遥かにかっこいいですね。 僕がSpreadsheetをいじることでこのサイトが自動で更新されます。

その下には個別のゲームの結果がずらずらと並びます。 f:id:wass80:20181222231316p:plain

トランザクションを手で書く

新しいシートを作り、トランザクションを手で書きます。 f:id:wass80:20181222231520p:plain

全体シートに1行追加して、シート名を書きます。 f:id:wass80:20181222231632p:plain

関数で頑張っているので、更新はこれで終わりです。 DBとしては正規化が効いていなくて最悪な感じもしますが、使い捨て&楽なので良しとします。

Apps script側

あまり真面目に解説はしません。デプロイなどの仕方は他の記事を見てください。割と力技です。自分だけが入力する以上、汚染されたデータが一切存在しないと考え、セキリュティーについては考えていません。

注意点としては、doGetで処理をするとレスポンスに時間がかかります。 そのため、データを取得するところは別の関数(getData)にして非同期に呼び出しましょう。

//コード.gs抜粋
function doGet() {
  return HtmlService
      .createTemplateFromFile('index')
      .evaluate();
}

function getData() {
  const db = getDB();
  const tbl = getTable(db, "Stack");
  const res = {};
  res.stack = [];
  for (var i = 1; i < tbl.length; i++){
    res.stack.push({user:tbl[i][0], stack:tbl[i][1]});
  }
  
  const tnms = tbl[0].slice(2, -1);
  res.tnms = []
  for (var i = 0; i < tnms.length; i++){
    var tnm = getTable(db, tnms[i]);
    res.tnms.push({name: tnms[i], desc: tnm[0][0], result: tnm.slice(2)});
  }
  Logger.log(res);
  return res;
}
//index.html抜粋
<script>
// The code in this function runs when the page is loaded.
$(function() {
  google.script.run.withSuccessHandler(show).getData();
});

function show(data) {
  const list = $('#ranking');
  const stack = data.stack.sort((a, b)=>b.stack - a.stack);
  for (var i = 0; i < stack.length; i++) {
    const c = Math.max(0, Math.floor((stack[i].stack - 1000) / 100));
    list.append(`<tr><td>${i + 1}`+
                    `<td>${stack[i].user}`+
                    `<td>${stack[i].stack}`+
                    `<td>${c}:${(new Array(1 + c)).join("🍫")}`);
  }
  const tlist = $("#tlist");
  for (let tnm of data.tnms) {
    let table = `<h3>${tnm.desc} (${tnm.name})</h3><table><tr><th>Rank<th>Name<th>Pay<th>Get`;
    const result = tnm.result;//.sort((a,b)=>b[2]-a[2]);
    for (var i = 0; i < result.length; i++) {
      table += `<tr><td>${i + 1}`+
                    `<td>${result[i][0]}`+
                    `<td>${result[i][1]}`+
                    `<td>${result[i][2]}`;
    }
    table += `</table>`
    tlist.append(table);
  }
}
</script>

この部分と、getDataの実装をすれば終わりでした。 とても手軽ですね。 最初に出てきたわけのわからないグラフも、Spreadsheetで作ったグラフを埋め込むだけです。楽ちん。

運営してみて

一番めんどくさいところはやはりトランザクションの入力です。 でもこれはそもそもどうしようもない手間です。 これ以上楽するためにはポーカーチップにチップ埋め込むしかないでしょう。

トランザクションの出入りが釣り合わないときに上にSum関数を書くだけでValidation出来たのはSpreadsheet様様という感じでした。

f:id:wass80:20181222233026p:plain

Slack

Apps Scriptなので、毎日スクリプトを走らせることが出来ます。 ついでにサークルのSlackに今日現在のランキングを流していました。 f:id:wass80:20181223000113p:plain

ところで、

ランキングに書かれていた🍫は、インセンティブでした。最終日がバレンタインデーだったわけです。 「max(0, floor((stack - 1000) / 100))チョコをwass80からプレゼント🍫」 という文言を終わり際になって用意しておきました。(初期stack = 1000)

最適戦略は全チップを他人に譲り渡してその人とチョコを分け合うことになります。もし起こったら悲しかったですが、そうはならなかったです。

これのために初めて人にチョコを包む経験をしました。 中身はフルタの安いけど美味しいチョコレートです。 人によっては外側の袋のほうが高い感じになります。 それでも、袋に包むとめっちゃ良いものに見えるのでおすすめです。 f:id:wass80:20181222233139p:plain

僕は19位/20人という結果に終わりました。精進が必要です。

次回予告

最近はコントラクトブリッジにハマっているので、次はデュプリケートブリッジの大会をしたいですね。 f:id:wass80:20181223020314p:plain

プライムポーカー 100枚セットA

プライムポーカー 100枚セットA