taQu_rule — taQu カスタムルール記述言語リファレンス (v1.6.0)
taQu のカスタムルールを記述するためのインデントベース言語です。Python ライクな構文でクイズ早押しゲームのルールを定義します。
# 以降の文字はすべて無視されます。"..." および '...' のどちらも使用できます。
def の外側(ファイル先頭付近)に記述します。
| 構文 | 説明 |
|---|---|
rule = "名前" |
ルール名。[定数名] で定数値を展開できます。 |
description = "説明" |
ルールの説明文。同様に [定数名] 展開が使えます。 |
maxAns = N |
1 問あたりの最大回答人数。デフォルト 1。0 で無制限(エンドレスチャンス)。 |
const NAME = 整数 |
定数を定義します。実行時に必ず定数値で上書きされます。ルール選択 GUI から変更可能。 |
x|y|z.label = "文字列" |
変数のラベルを設定します。未設定の変数は画面に表示されません。 |
sync(x|y|z) |
変数をチーム内で同期します(詳細は TEAM セクション参照)。 |
winText = "文字列" |
WIN バッジに表示するテキストを変更します。デフォルトは WIN。 |
showWinRank = true|false |
WIN バッジに 1st / 2nd などの順位を表示するかどうかを設定します。デフォルトは true。 |
sortByWinRank = true|false |
ボタン押下時、押したプレイヤーを winRank(勝ち抜け順位)の昇順で並べます。winRank が同じ場合は押下時刻で比較します。デフォルトは false。 |
sortByPressOrder = true|false |
ボタンを押したプレイヤーをリスト先頭に移動し、押下時刻順に並べます。false にすると押下しても並び順が変わりません。デフォルトは true。 |
const TARGET = 7 rule = "セブンス[TARGET]" description = "[TARGET]ポイント先取で勝利" maxAns = 1 x.label = "pts"
画面に表示できる変数は x, y, z の 3 つのみです。ラベル未設定の変数は非表示になります。
| 変数名 | 説明 |
|---|---|
mt |
チームインデックス。チーム名をアルファベット順にソートした順番(1 始まり)。チーム未所属のソロは 0。 |
x, y, z 以外の任意の名前(例: hp, phase)も使用できます。def の外で代入すると初期値として扱われます。画面には表示されません。カスタム変数は各プレイヤーごとに独立して保持され、scope() 内での代入も正しく各プレイヤーに保存されます。
phase = 0 # 全プレイヤーの初期値を 0 に設定
def push():
if phase == 0:
phase = 1
scope(my_mt == mt):
phase = 1 # チームメンバーにも phase=1 が保存される
scope() の条件式・ブロック内、および othersAdd / othersSet / tAdd / tSet の値式の中で使います。
scope() のブロック内で my_x = 式 と書くと、各対象プレイヤーへの処理中に発行者自身の変数へ書き込みます。+= / -= / *= も使用可能です。
othersSet(x, my_x) # 自分以外全員のxに「自分のx値」をセット
scope(mt == my_mt): # 自分と同じチームのプレイヤーに実行
x += my_x # 対象メンバーのxに自分のxを加算(参照)
scope(mt == my_mt and x >= 10):
my_z += 1 # 条件を満たすチームメンバーの数を発行者のzに積算(代入)
| 構文 | 説明 |
|---|---|
tSum(var) |
チーム全員(自分含む)の指定変数の 合計 を返します。 |
tMax(var) |
チーム全員(自分含む)の指定変数の 最大値 を返します。 |
tMin(var) |
チーム全員(自分含む)の指定変数の 最小値 を返します。 |
tCount(var) |
チーム内で指定変数が 0 でないメンバーの数 を返します。引数に 1 を指定するとチームの総人数を返します。 |
tProd(var) |
チーム全員(自分含む)の指定変数の 積 を返します。 |
| 構文 | 説明 |
|---|---|
rankVal(var, n) |
全プレイヤー中で指定変数 var の値が n 番目(降順)のプレイヤーのその変数値を返します。n が範囲外の場合は 0 を返します。 |
countIf(条件式) |
全プレイヤーのうち、条件を満たすプレイヤーの人数を返します。条件には x, y, z およびカスタム変数を使用できます(各プレイヤーの値で評価されます)。 |
| 構文 | 説明 |
|---|---|
floor(式) |
小数切り捨て。 |
ceil(式) |
小数切り上げ。 |
abs(式) |
絶対値。 |
sign(式) |
符号を返します。正なら 1、負なら -1、0 なら 0。 |
max(式a, 式b) |
2 つの値の大きい方を返します。 |
min(式a, 式b) |
2 つの値の小さい方を返します。 |
clamp(式, lo, hi) |
lo 以上 hi 以下に値を制限します。 |
not(式) |
論理否定。式が 0 なら 1、それ以外なら 0。 |
rand(min, max) |
min 以上 max 未満のランダムな整数を返します。対象プレイヤーごとに独立した乱数が生成されます。 |
/(除算)演算子はすでに整数除算(切り捨て)として動作します。floor() / ceil() は複合式の切り捨て・切り上げに使います。
def イベント名(): の形式でイベントハンドラを定義します。def の外側に書いたコードは、プレイヤーが参加した時点の初期化処理として実行されます。
| イベント名 | 実行タイミング | 対象 |
|---|---|---|
def correct(): |
ホストが「正解」を押したとき | 現在の回答者のみ |
def wrong(): |
ホストが「不正解」を押したとき | 現在の回答者のみ |
def through(): |
ホストが「スルー」を押したとき | 回答者がいれば回答者のみ。いなければ誰にも実行されない |
def push(): |
プレイヤーが早押しボタンを押した瞬間 | 押したプレイヤーのみ |
def next(): |
maxAns = 1(またはデフォルト)のとき: correct / wrong / through のいずれかの後maxAns ≠ 1(エンドレス・複数正解など)のとき: correct / through のみ(wrong では発火しない)
|
全プレイヤー(一人ずつ順番に実行) |
push() でキューに積んだコマンドは、ルール実行後に以下の順で処理されます。
scope() — 対象プレイヤーへの変数操作giveAns() — 解答権の付与throughAns() — 解答権の放棄(カーソル前進)updateRoomAnswerState)giveAns() が先に実行されてから throughAns() でカーソルが調整されるため、「他の人に渡して自分は解答権なし」という組み合わせが正しく動作します。
| 演算子 | 意味 |
|---|---|
x = 式 | 代入 |
x += 式 | 加算代入 |
x -= 式 | 減算代入 |
x *= 式 | 乗算代入 |
| 演算子 | 意味 | 備考 |
|---|---|---|
+ | 加算 | |
- | 減算 | |
* | 乗算 | |
/ | 整数除算(切り捨て) | ゼロ除算は 0 を返す |
% | 剰余 | ゼロ除算は 0 を返す |
^ | べき乗 | x ^ 2 → x の 2 乗 |
| 演算子 | 別記法 | 意味 |
|---|---|---|
== | 等しい | |
!= | 等しくない | |
> | より大きい | |
< | より小さい | |
>= | 以上 | |
<= | 以下 | |
and | && | 論理積(両方真のとき 1) |
or | || | 論理和(どちらか真のとき 1) |
# 基本形
if x >= 10:
win()
else:
x += 1
# elif を使った多段分岐
if x >= 10:
win()
elif x >= 5:
z += 1
elif x >= 1:
z += 0
else:
lose()
# ネスト
if x > 0:
if x == 5 and y == 0:
z += 2
else:
z += 1
# 1行 if(インライン形式)
if x >= 10: win()
elif は else if の省略形です。連続して何個でも書けます。switch/case と異なり、前のブロック内で変数を変更すると後続の条件に影響します。
repeat 3:
x += 1 # x を 3 回加算 → x += 3 と等価
# 式も使用可能
repeat N:
othersAdd(y, 1)
repeat の回数は整数に切り捨てられます。1000 回を超える場合は安全のため 1000 回に制限されます。
変数や式の値に応じて処理を切り替えます。マッチしたケースだけが実行され、以降のケースには処理が流れません(フォールスルーなし)。連続する if と異なり、あるケース内で変数を変更しても他のケースに影響しません。
switch phase:
case 0:
x += 3
phase = 1
case 1:
x += 1
phase = 0
default:
pass
if を並べると、1つ目の if 内で変数を書き換えた場合に2つ目の if が意図せず真になることがあります。フェーズ遷移のような「状態で処理を切り替える」用途では switch/case を推奨します。
| コマンド | 説明 |
|---|---|
win() | 勝利状態にします。以降の処理は実行されません。 |
lose() | 敗北状態にします。以降の処理は実行されません。 |
lock() | そのプレイヤーの回答権をロック(ボタンを押せなくする)。 |
unlock() | ロックを解除します。 |
tLock() | チーム全体の回答権をロックします。 |
tUnlock() | チーム全体のロックを解除します。 |
pass | 何もしません(空のブロックで使用)。 |
setBorderColor(色) | そのプレイヤーのカード囲み線の色を設定します。色は #rrggbb、red など CSS に有効な値を指定します。 |
resetBorderColor() | setBorderColor() で設定した周り線の色をリセットします。 |
flashBorderColor(色, ms) | カード囲み線を指定色で ms ミリ秒間点灯させた後、元の色に戻します。ms 省略時は 1000 ms。 |
setX(式) / setY(式) / setZ(式) | x = 式 のショートカット。他の変数名と区別したい場合に便利です。 |
addX(式) / addY(式) / addZ(式) | x += 式 のショートカット。 |
broadcast(var, 式) | 全プレイヤーの変数 var を 式 の値に一括セットします。othersSet と異なり発行者自身にも適用されます。 |
resetVar(var) | カスタム変数 var を初期化ブロックで設定した初期値に戻します。 |
setFlavorText("文字列") | そのプレイヤーのフレーバーテキストを指定した文字列に変更します。チームへの帰属も変化します。最大 50 文字。 |
resetFlavorText() | setFlavorText() で変更したフレーバーテキストを空文字列にリセットします。 |
| コマンド | 使用可能なイベント | 説明 |
|---|---|---|
giveAns(条件) |
すべてのイベント |
条件を満たすプレイヤーの中からランダムに 1 人を選び、解答権を付与します。 push() 内:まだボタンを押していない( isPressed=false)プレイヤーが対象になります。correct / wrong / through 内:その問のリセット後に実行されるため、ボタンを押していたプレイヤーも対象になります。 発行者自身と、ホストは対象外です。 |
throughAns() |
主に push() |
ボタンを押した事実(isPressed)は残したまま、そのプレイヤーの解答権だけを消します。同じターン内で再度ボタンを押すことはできません。giveAns() と組み合わせることで「ボタンを押したら自分ではなくチームメンバーが回答者になる」仕組みを実現できます。
|
# push() でチームメンバーに解答権を渡し、自分は解答しない例
def push():
if phase == 0:
giveAns(my_mt == mt) # 同チームのメンバーに解答権を渡す
throughAns() # 自分の解答権を放棄(isPressed は残る)
scope(my_mt == mt):
phase = 1
throughAns() は push() 以外(correct / wrong / through)でも呼べますが、それらのイベントでは通常のリセット処理と組み合わせるため動作が複雑になります。push() での使用を推奨します。
| コマンド | 対象 | 説明 |
|---|---|---|
othersAdd(var, val) |
自分以外の全員 | var に val を加算します。 |
othersSet(var, val) |
自分以外の全員 | var を val にセットします。 |
uAdd(var, val) |
自分以外の全員 | othersAdd の別名。 |
uSet(var, val) |
自分以外の全員 | othersSet の別名。 |
tAdd(var, val) |
同チームのメンバー(自分以外) | var に val を加算します。 |
tSet(var, val) |
同チームのメンバー(自分以外) | var を val にセットします。 |
プレイヤーは参加時の「フレーバーテキスト」でチーム分けされます。
| フレーバーテキスト | 動作 |
|---|---|
チーム名(コロンなし) |
通常のチーム。同じ文字列のプレイヤーが 1 チームになります。 |
メタ名:サブ名(コロンあり) |
メタチーム構造。同じ「メタ名」を持つプレイヤーが大グループとして扱われます。 |
チーム内で変数を全メンバーに共有したい場合に def の外側に記述します。
sync(x) # x はチーム内で同期(誰かが更新すると全員に反映)
# y, z は同期されず個人の値として保持
scope(条件): は発行者を基準として、全プレイヤーに対して条件付きで処理を実行します。
| 構文 | 説明 |
|---|---|
scope(条件): |
条件が真のプレイヤーに対してブロック内を実行します。 |
my_xxx |
scope 内で発行者の変数を参照します。 |
mt |
scope 内で各プレイヤー自身のチームインデックスを参照します。 |
| イベント | 発行者(scope の基準) |
|---|---|
push() | ボタンを押したプレイヤー |
correct() / wrong() / through() | 現在の回答者(ホストが判定したプレイヤー) |
next() | 処理中の各プレイヤー自身 |
def push():
# 発行者と同じチームのプレイヤーにだけ実行
scope(mt == my_mt):
x += 1
# 全員に実行(条件を常に真にする)
scope(1):
y += my_x
scope 内でも win(), lose(), lock() 等が使えます。ただし othersAdd / othersSet や tAdd などの対他コマンドは scope の外に記述してください。scope 内でのカスタム変数への代入は各プレイヤーに正しく保存されます。
チャット欄にスラッシュで始まるコマンドを入力することで、ホストは各種操作を行えます。 コマンドはチャットには流れず、ホストのみに結果が返ります。
| コマンド | 説明 |
|---|---|
/set [x|y|z] [値] | 全員の指定変数を値に設定します。 |
/add [x|y|z] [値] | 全員の指定変数に値を加算します。 |
/hide [x|y|z] | 指定変数の列をプレイヤーから非表示にします。 |
/show [x|y|z] | 非表示にした列を再表示します。 |
外部ストレージの音声 URL を登録し、参加者全員のブラウザで同時再生します。 サーバーは URL 文字列のみを中継し、音声バイナリは一切保持・転送しません。
| コマンド | 説明 |
|---|---|
/jingle load <名前> <URL> | ジングルを登録します。同じ名前で上書き可。最大 20 個。 |
/jingle play <名前> | 登録済みジングルを全参加者に再生します。 |
/jingle stop | 全参加者のジングルを停止します。 |
/jingle list | 登録済みジングルの一覧をチャットに表示します(ホストのみ表示)。 |
/jingle remove <名前> | 指定したジングルを削除します。 |
/jingle load bgm1 https://dl.dropboxusercontent.com/s/xxxx/music.mp3 /jingle play bgm1 /jingle stop /jingle list /jingle remove bgm1
| サービス | 形式・変換 | 動作 |
|---|---|---|
| Dropbox | 共有リンク(www.dropbox.com/...)をそのまま貼る。dl=1 不要。 |
◎ 推奨 |
| Google Drive | /file/d/{id}/view 形式を自動変換。ただし CORS 制限により再生できない場合あり。 |
△ 環境依存 |
| 直接 URL | 音声ファイル(mp3, ogg, wav 等)への直リンク。CORS 設定が必要。 | ○ |
ゲームイベント(ボタン押下・正誤判定・勝ち抜け・失格)が発生したとき、 指定した URL に JSON で POST 通知を送ります。 スコア集計・外部連携・自動記録などに使えます。
| コマンド | 説明 |
|---|---|
/webhook <URL> | Webhook を設定します。HTTPS の URL のみ有効。 |
/webhook off | Webhook を解除します。 |
/webhook https://script.google.com/macros/s/xxxx/exec /webhook off
| event | 説明 | data の主なフィールド |
|---|---|---|
buttonPressed | 解答ボタンが押された | userId, name |
judged | 正誤判定が下された | action (correct / incorrect / through), userId, name |
playerWon | プレイヤーが勝ち抜けた | userId, name, rank |
playerLost | プレイヤーが失格になった | userId, name |
{
"event": "judged",
"roomId": 1,
"roomName": "クイズ大会",
"ts": 1710000000000,
"data": {
"action": "correct",
"userId": "abc123",
"name": "田中"
}
}
Google Apps Script でウェブアプリを作成すると、無料でスプレッドシートに自動記録できます。
/webhook <URL> で登録
function doPost(e) {
const sheet = SpreadsheetApp.getActiveSheet();
const body = JSON.parse(e.postData.contents);
const row = [
new Date(body.ts),
body.roomId + ': ' + body.roomName,
body.event,
(body.data.action || ''),
(body.data.name || ''),
(body.data.rank || '')
];
sheet.appendRow(row);
return ContentService.createTextOutput('ok');
}
description = "正解で〇、誤答で×が増えるシンプルなルール。" name="Free" maxAns=1 x.label = "〇" y.label = "×" def correct(): x += 1 def wrong(): y += 1 def through(): pass
rule="[M]〇[N]×" description = "[M]回正解で勝ち抜け、[N]回誤答で失格" maxAns=1 x.label = "〇" y.label = "×" const M = 7 const N = 3 def correct(): x += 1 def wrong(): y += 1 def through(): pass def next(): if x >= M: win() if y >= N: lose()
rule="Freeze[N]"
description = "[N]回正解で勝ち抜け、n回目の誤答でn回休み"
maxAns=1
x.label = "〇"
y.label = "×"
z.label = "Lock"
const N = 10
def correct():
x += 1
def wrong():
y += 1
z = y + 1
lock()
def through():
pass
def next():
if z > 0:
z -= 1
if z == 0:
unlock()
if x >= N: win()
rule="Attack Survival"
description = "持ち点[M]が無くなると失格、正解で他のプレイヤー-1pt、誤答で自身が-[N]pt"
const M = 20
const N = 1
x.label = "Pts"
x = M
def correct():
othersAdd(x, -1)
def wrong():
x -= N
def next():
if x <= 0:
x = 0
lose()
description = "チーム内の正解数の積が[N]以上で勝ち。誤答でその人のPtsが1にリセット。2回誤答でロック。ただし誰かが2回誤答すると、他の全チームの2回目の誤答が1回に戻り、ロックも解除される。"
rule = "10by10by10mini"
x.label = "Pts"
y.label = "×"
z.label = "Prod"
const N = 200
x = 1
z = 1
sync(z)
def correct():
x += 1
z = tProd(x)
if z >= N:
win()
def wrong():
x = 1
y += 1
z = tProd(x)
if y >= 2:
lock()
scope(mt != my_mt):
if y == 2:
y = 1
unlock()
wrong() / correct() では switch/case を使うことで、あるケース内で phase を変更しても別のケースが意図せず実行されることを防げます。
下のプロンプトをコピーし、[要望] を書き換えてから、このページ全体(Ctrl+A で全選択)と一緒に AI に送信してください。
taQu ルールテスター — /rule_tester