taQu_rule — taQu カスタムルール記述言語リファレンス (v1.12.0)
taQu のカスタムルールを記述するためのインデントベース言語です。Python ライクな構文でクイズ早押しゲームのルールを定義します。
関連資料: tanakata-ro/taQu_algorithm
# 以降の文字はすべて無視されます。"..." および '...' のどちらも使用できます。
def の外側(ファイル先頭付近)に記述します。
| 構文 | 説明 |
|---|---|
rule = "名前" |
ルール名。[定数名] で定数値を展開できます。+ による文字列連結、数値式の文字列化、+= による追記も使えます。name は rule の別名です。 |
description = "説明" |
ルールの説明文。同様に [定数名] 展開、+ 連結、数値式の文字列化、+= 追記が使えます。desc は description の別名です。 |
maxAns = N |
1 問あたりの最大回答人数。デフォルト 1。0 で無制限(エンドレスチャンス)。 |
const NAME = 整数 |
定数を定義します。実行時に必ず定数値で上書きされます。ルール選択 GUI から変更可能。 |
x|y|z|w.label = "文字列" |
変数のラベルを設定します。未設定の変数は画面に表示されません。 |
x|y|z|w.label = "" |
ラベル名を表示せず、数値だけを表示します。例: x.label = "" |
x|y|z|w.color = "CSS color" / correctColor / wrongColor |
数値表示の文字色を設定します。例: x.color = "#ef4444", y.color = "red", z.color = "rgb(59,130,246)", w.color = correctColor。correctColor / wrongColor は正解・誤答色を参照し、色反転設定に追従します。空文字 "" を指定すると通常色に戻ります。 |
x|y|z|w.color = "CSS color" / correctColor / wrongColor inside def / if |
イベント処理中にも数値表示色を変更できます。例: if x % 2 == 0: x.color = correctColor。変更後は全員の画面に反映されます。 |
x|y|z|w.size = normal|small |
数値表示のサイズを設定します。normal(通常)または small(小さめ)。"小さめ" も指定できます。 |
mark.symbol = "マーク" |
mark の表示マークを設定します。未設定時は ×。5個まではマークを並べ、6以上は マーク+数字 で表示します。miss は旧名として引き続き使えます。 |
sync(x|y|z|w) |
変数をチーム内で同期します(詳細は TEAM セクション参照)。 |
keep(x|y|z|w|mark) |
ルール適用時やラウンド切替時に、指定した変数の現在値を保持します。GUI の「保持する変数」チェックでも設定できます。 |
winText = "文字列" |
WIN バッジに表示するテキストを変更します。デフォルトは WIN。トップレベルの if / elif / else と def 内で使用できます。変更後に勝利したプレイヤーから適用され、すでに勝利表示されたプレイヤーの文言は変わりません。 |
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.color = "#ef4444" y.label = "" y.color = "rgb(59,130,246)" w.label = "bonus" w.size = small
rule と description は、トップレベルの if の中でも変更できます。
const TARGET = 10
rule = "Freeze" + TARGET
description = "勝ち抜け: " + TARGET + "問"
if TARGET >= 10:
rule += " hard"
desc += " / 高難度"
数値欄として画面に表示できる変数は x, y, z, w の 4 つです。ラベル未設定の変数は非表示になります。4 つすべてを表示する場合は、プレイヤーカードが 1 変数分だけ横に広がります。miss は数値欄ではなく、カード上の × 表示専用変数です。
| 変数名 | 説明 |
|---|---|
mt |
チームインデックス。チーム名をアルファベット順にソートした順番(1 始まり)。チーム未所属のソロは 0。 |
miss |
プレイヤーカードに × を表示する専用変数です。miss += 1 で×が1つ増えます。値は自動的に 0 以上 5 以下に丸められ、負の値にはなりません。Type Aではフレーバーテキスト横、Type Bでは名前と得点欄の間の専用スペースに表示されます。 |
buttonDelay は各プレイヤーの早押し遅延をミリ秒単位で表します。参照と代入が可能で、値は 0~60000 の整数に丸められます。変更は実際の早押しボタンと設定画面に同期されます。
buttonDelay = 200
def correct():
buttonDelay += 50
def next():
scope(x >= 3):
buttonDelay = 500
scope(x == 0):
my_buttonDelay = 0
x, y, z, miss 以外の任意の名前(例: 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(式) |
小数切り上げ。 |
round(式) |
四捨五入。 |
sqrt(式) |
平方根。 |
pow(式a, 式b) |
式a の 式b 乗。 |
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 未満のランダムな整数を返します。対象プレイヤーごとに独立した乱数が生成されます。 |
random(n) |
0 以上 n 未満のランダムな整数を返します。 |
/(除算)演算子はすでに整数除算(切り捨て)として動作します。floor() / ceil() は複合式の切り捨て・切り上げに使います。
def イベント名(): の形式でイベントハンドラを定義します。def の外側に書いたコードは、プレイヤーが参加した時点の初期化処理として実行されます。
def name(): で引数なしの自作関数を定義し、name() で呼び出せます。
イベント名や組み込み関数名など、予約済みの名前は自作関数として定義できません。
def addCorrectPoint():
x += 1
if x >= 3:
win()
def correct():
addCorrectPoint()
| イベント名 | 実行タイミング | 対象 |
|---|---|---|
def correct(): |
ホストが「正解」を押したとき | 現在の回答者のみ |
def wrong(): |
ホストが「不正解」を押したとき | 現在の回答者のみ |
def through(): |
ホストが「スルー」を押したとき | 回答者がいれば回答者のみ。いなければ誰にも実行されない |
def push(): |
プレイヤーが早押しボタンを押した瞬間 | 押したプレイヤーのみ |
def next(): |
maxAns = 1(またはデフォルト)のとき: correct / wrong / through のいずれかの後maxAns ≠ 1(エンドレス・複数正解など)のとき: correct / through のみ(wrong では発火しない)
|
全プレイヤー(一人ずつ順番に実行) |
def judge(): |
ホストが /judge を実行したとき |
順位が確定していないプレイヤー |
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() で設定した周り線の色をリセットします。 |
setX(式) / setY(式) / setZ(式) / setW(式) | x = 式 などのショートカット。他の変数名と区別したい場合に便利です。 |
addX(式) / addY(式) / addZ(式) / addW(式) | x += 式 などのショートカット。 |
broadcast(var, 式) | 全プレイヤーの変数 var を 式 の値に一括セットします。othersSet と異なり発行者自身にも適用されます。 |
resetVar(var) | カスタム変数 var を初期化ブロックで設定した初期値に戻します。 |
setFlavorText("文字列") | そのプレイヤーのフレーバーテキストを指定した文字列に変更します。チームへの帰属も変化します。最大 8 文字。 |
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() | 処理中の各プレイヤー自身 |
judge() | 処理中の各プレイヤー自身 |
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|w|mark] [値] | 全員の指定変数を値に設定します。mark は0以上の整数になります。 |
/add [x|y|z|w|mark] [値] | 全員の指定変数に値を加算します。mark は0未満にはなりません。 |
/hide [-c] x y z w | 指定変数をプレイヤーには - として表示します。-c を付けると完全に非表示にします。 |
/show x y z w | 非表示にした複数の変数を再表示します。 |
/judge | ルール内の def judge(): を、順位が確定していないプレイヤーへ実行します。 |
/win [人数] 判定... | 指定した判定順で勝ち抜けを確定します。人数を省略した場合は、判定1位の同率者のみ対象になります。 |
/lose [人数] 判定... | 指定した判定順で失格を確定します。例: /win 3 x -y は x が大きい順、同点なら y が小さい順で判定します。 |
外部ストレージの音声 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 status | 現在設定中の URL を確認します。 |
/webhook secret | 現在の署名シークレットを確認します。 |
/webhook https://script.google.com/macros/s/xxxx/exec /webhook status /webhook secret /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": "田中"
}
}
Webhook の POST リクエストには X-Taqu-Signature ヘッダが付与されます。
受信側でこのヘッダを検証することで、taQu サーバーからの正規リクエストであることを確認できます。
sha256= プレフィックス付きで送ります。/webhook <URL> 設定時にチャットに表示されます。/webhook secret で再確認できます。X-Taqu-Signature: sha256=a3f2c1...(64文字の hex)
検証の実装例(Python):
import hmac, hashlib
SECRET = b"your_secret_here"
def is_valid(request):
body = request.body # raw bytes
given = request.headers.get("X-Taqu-Signature", "")
expected = "sha256=" + hmac.new(SECRET, body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, given)
検証の実装例(Node.js):
const crypto = require("crypto");
const SECRET = "your_secret_here";
function isValid(rawBody, signature) {
const expected = "sha256=" + crypto
.createHmac("sha256", SECRET)
.update(rawBody)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}
hmac.compare_digest / crypto.timingSafeEqual)を使用してください。通常の文字列比較ではタイミング攻撃に対して脆弱です。
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');
}
X-Taqu-Signature の検証は行えません。
署名検証が必要な場合は Node.js / Python などのサーバーを受信エンドポイントとして用意してください。
description = "正解で〇、誤答で×が増えるシンプルなルール。" name="Free" maxAns=1 x.label = "〇" y.label = "×" def correct(): x += 1 def wrong(): y += 1 miss += 1 def through(): pass
description = "正解数が偶数なら赤、奇数なら黒。誤答で×表示も増える。"
x.label = "〇"
y.label = "×"
def correct():
x += 1
if x % 2 == 0:
x.color = "red"
else:
x.color = "black"
def wrong():
y += 1
miss += 1 # 0〜5の範囲で×表示が増える
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 に送信してください。
A const value shown in the GUI can have help text. Write it as a trailing comment,
as the comment immediately before the const, or as the comment immediately after it.
These comments are only UI metadata and do not affect rule execution.
const N = 3 # Number of correct answers needed to win
# Number of wrong answers before losing
const W = 2
const P = 1
# P: Points added on a correct answer
taQu ルールテスター — /rule_tester