見出し画像

Puzzle Boss Rush システム屋からの報告

皆さんこんにちは、パズルボスラッシュのシステム屋担当、ゆずっこです。とは言ってもプログラミング未経験で基本的にうちの「えらいひと」の助けを借りて全部組み上げたのですが…
この記事ではパズルボスラッシュの「あの」ページができた経緯とプログラミングが何一つできなくても同様のページが自分で組めるような取扱説明書を提供するものです。ただプログラミングは完全な初心者なので間違っていたりしたら指摘をお願いします。

背景

昨今Twitterではパズル大会がかなりの数行われるようになっており、竹谷さんの一連の記事(① https://note.com/buyaketa/n/n393b0db3b23e 、② https://note.com/buyaketa/n/n5f5a4a524d6b 、③ https://note.com/buyaketa/n/n81bc59b5d0b3 ) を参照すればだれでもgoogle formを利用したパズル大会が主催できるいい時代になってきました。Google formを利用した大会のメリットとして、
・簡単
・時間を区切って一斉に解答させる形式に適している
・誤答即失格という厳しい運用も解答判定も両方できる
あたりが挙げられると思います。

ただデメリットとして、
・自由度が低い
・画像の差し替えなど修正が少し面倒
・解答判定に時間的な拘束がないので総当たりに弱い
・解答判定や経過時間判定を実装すると誤答情報等が積み重なり集計がちょっと大変になる
という点があります。

さて、Puzzle Grand Prix等のプレーオフ(オンサイトで行われる決勝ラウンド)では選手が解答を提出すると1分のsubmission timeを経て正解判定が下される、という総当たり防止システムが搭載されています。今回のパズルボスラッシュを開催するに当たってこのようなシステムはスパムや総当たり防止に非常に重要と考え、どうにかできないかと散々調べましたが、google formに1分待たせるような機能は実装されていませんでした。
進退窮まりうちの「えらいひと」に相談したところ、ページを最初からGASで作ってしまえばいいじゃんと強者の回答が得られました。GASとはGoogle Apps Scriptの略で、全貌は筆者も知りませんがjavascriptを使ったwebページ発行を含む色んなことができるらしいツールとのことです。これを使えば1分待つ、正解判定を出す、正解者にリンクを提供するといったことができるのです。まあ実装できさえすれば大体何でもできますが。
これにより、google formでの大会のデメリット4つが全て解決できそうなので急いでページを作り、なんとか本番に間に合わせました。安定する挙動になったのが5月3日、パズルボスラッシュ襲来4日前のことです。(延期してくれてよかった…)

仕様

世の中はソースを読む人、サイトのチェックをかいくぐる人 (詳しくは https://wadopuresunikiotsukero.wordpress.com/ などを参照) など色々なことを想定しなくてはいけないような作りになっています。もし万が一htmlのソースに「提出したアンサーキーが答えの値○○と一致した場合」や「正解の時はこのリンクを表示させる」のようなうかつなコードを書いてしまえばボスとしては台無しです。よって、外部から絶対見えないところにアンサーキーと正解者用のリンクを保管しておき、呼び出せるようにすることが必要でした。これには、google spreadsheetにアンサーキーの値と正解者用のURLを格納しておき、spreadsheetに紐付いたscriptを作成することで解決しました。

こうしてできあがったコードがこちらです。「動けばいい」の発想で書いたのでvarとletが混在していたり非効率な部分がいっぱいあったりしますが、分かる人は適宜ブラッシュアップして使用してください。コードのあとに取扱説明書があるので分からない人はそちらを参照してください。

onSiteChecker.gs

function doGet(e){
 let judge="";
 let form="";
 let ans="";
 var html = HtmlService.createTemplateFromFile('ProbChecker');
 html.form = form;
 html.judge = judge;
 html.ans = ans;
 return html.evaluate();
}  
function doPost(postdata){
 var html = HtmlService.createTemplateFromFile('ProbChecker');
 const sheet = SpreadsheetApp.getActiveSheet();
 const correct = sheet.getRange('A1').getValue();
 var link = sheet.getRange('A2').getValue();
 var formcor = link;
 var formwrong = '';  
 Logger.log(postdata);
 const ans = postdata.parameter.ans;
 judge = (String(ans) === String(correct))?"やったー!○○を倒したぞ!":"攻撃が全然効いていない!";
 form = (String(ans) === String(correct))?formcor:formwrong;
 Utilities.sleep(60000);
 //ProbChecker.htmlにurlと判定を返す
 html.form = form;
 html.ans = ans;
 html.judge = judge;
 return html.evaluate(); 
}

ProbChecker.html

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
<!DOCTYPE html>
<html lang="ja">
<head>
 <base target="_top">
</head>
<body>
 <div class="container">
   <h1 class="display-4">ページタイトル</h1>
   <div class="problem-area">
    <p>
     <img src="https://drive.google.com/uc?export=view&id=○○&usp=sharing" width="75%" height="75%"><br>
    </p>
    <a href="パズリンクのURL" target="_blank">puzz.linkのリンクはこちら。</a><br>
    <br>
    <p>アンサーキーの説明とか</p>
   </div>
   <form method="post" action="このページのURL ">
     <div class="form">
       <input type="text" name="ans" size="100" value="<?=ans?>" placeholder="アンサーキーを半角英数字で入力してください。">
       <input class="btn-dark" type="submit" value="送信!">
     </div>
     <div class="output_area">
       <input type="text" size="50" name="judge" value="<?=judge?>" placeholder="判定結果" readonly>
       <div class="form-group">
        <input type="text" size="100" name="form" value="<?=form?>" placeholder="正解の場合、正解者登録フォームが出力されます" readonly>
       </div>
     </div>
   </form>
   <div>
    <a href="https://twitter.com/share?ref_src=twsrc%5Etfw" class="twitter-share-button" data-size="large" data-text="<?=judge?> ページタイトル" data-url="このページのURL" data-hashtags="つけたいハッシュタグ" data-lang="ja" data-dnt="true" data-show-count="false">Tweet</a><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>    </div>
   </div>
</body>
</html>

取扱説明書

これを読んでそのまま実行すると単問ラウンドで、パズルボスラッシュと同様のシステム、見た目等になります。見た目を変えたかったらhtmlやcssを勉強してください。複数問にしたい場合はjavascriptを勉強してください。待ち時間を変えたい時はUtilities.sleep()の中身を任意の値に変えてください。ミリ秒表示です。私は (知識が無いので) これ以上のことは対応できません。

実際の操作

Google spreadsheetを新規作成します。
A1にアンサーキー、A2に正解者登録用のフォームのURLを入力します。フォーム作成は竹谷さんの記事を参照してください。ただ正解者登録用なので名前だけあればいいと思います。
アンサーキーの変更はA1の値を変えるだけなのですごく簡単です。
ツール>スクリプト エディタをクリックします。

画像1

そうすると以下のような画面が開きます。GASのスクリプトエディタです。これ以降の操作は全てここで行います。

画像2

まず左上の「無題のプロジェクト」のところをクリックして識別しやすい名前にします。
できたら上にあるonSiteChecker.gsの内容を全てコピペしましょう。

画像3

コード.gsの隣の赤いアスタリスクは「保存してないよ」というお知らせなので保存しましょう。
今度はhtmlの方を作ります。新しいhtmlファイルを作成しましょう。ProbCheckerという名前にします。

画像4

これも同様に上のProbChecker.htmlの内容をコピペします。

画像5

このあと細かいところの調整をしていきます。ProbChecker.htmlを上から見ていきましょう。
ページタイトル、とあるところにつけたいタイトルを記入します。
次に画像の挿入ですが、私はgoogle drive上の画像を表示する方法しか知りません。下図のようにまずは共有リンクを取得してください。

画像6

その後、どこかにコピペして?id=のあとの部分だけを、ProbChecker.htmlの○○の代わりに貼り付けます。これで画像が出るようになります。
その下のパズリンクのURLとあるところにパズルのURLを貼り付けます。別にpuzz.linkでなくてもいいです。

その下の「このページのURL」というところですが、まずこのページを発行しなくてはなりません。左上の公開>ウェブアプリケーションとして導入をクリックします。

画像7

すると以下のような画面が出てきます。

画像8

以下のようにVersionはnew (以降更新する時も必ずnewにすること)、Who has access to the appはAnyone, even anonymousにします。

画像9

ここでDeployを押すと、googleが許可を求めてきます。許可を確認→ログインをすると以下のような画面が出ます。

画像10

デベロッパーは自分なので確認を押したいところです。少々分かりづらいですが左下の「詳細」をクリックするとさらに左下に小さく出てきます。

画像11

これをクリックすると許可する画面が出てきます。

画像12

許可を押すと…

画像13

めでたく、ウェブアプリとして発行ができました。この真ん中のURLがこのサイトのURLです。これをさっきの「このページのURL」というところに貼り付けましょう。このURLは大会開始時まで他人に見せないようにしましょう。
これで再び公開(新しいバージョンとしてDeploy)すると大体できあがりです。
あとはTwitterの投稿ボタンですが、ここ (https://publish.twitter.com/?buttonType=TweetButton&widget=Button ) を参考にしてください。一応上に出てきた「ページタイトル」「このページのURL」や「つけたいハッシュタグ」を置き換えるとうまくいくようにはできていますが…

というわけで単問PBR形式のサイトができあがりました。めでたしめでたし。これであなたもgoogle formじゃない形式でもパズル大会が開けるようになりました(若干めんどくさいですが)。

分からないことなどあれば一応相談には乗りますが、高確率で周りのjavascriptやhtml、cssが書ける人に聞いた方が解決が早くなると思います。

クロスレビュー

広瀬あつみ
google formを作成するのが初めてだった自分にていねいに解説してくれたゆずっこ先生に、この場であらためてお礼を伝えてみます(ありがとうございました)
システム回りをいろいろ整備してもらえて、良い形式のイベントになったのではないかなあと思います。

ここから先は

0字

パズルボスラッシュの各問題について、問題の解説、制作経緯、裏話などを公開します。有料・無料の記事がありますが、有料記事は7記事で各記事10…

この記事が気に入ったらサポートをしてみませんか?