taQu_rule — taQu カスタムルール記述言語リファレンス (v1.5.0)
taQu のカスタムルールを記述するためのインデントベース言語です。Python ライクな構文でクイズ早押しゲームのルールを定義します。
# 以降の文字はすべて無視されます。"..." および '...' のどちらも使用できます。
def の外側(ファイル先頭付近)に記述します。
| 構文 | 説明 |
|---|---|
rule = "名前" |
ルール名。[定数名] で定数値を展開できます。 |
description = "説明" |
ルールの説明文。同様に [定数名] 展開が使えます。 |
maxAns = N |
1 問あたりの最大回答人数。デフォルト 1。0 で無制限(エンドレスチャンス)。 |
const NAME = 整数 |
定数を定義します。実行時に必ず定数値で上書きされます。ルール選択 GUI から変更可能。 |
x|y|z.label = "文字列" |
変数のラベルを設定します。未設定の変数は画面に表示されません。 |
sync(x|y|z) |
変数をチーム内で同期します(詳細は TEAM セクション参照)。 |
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に積算(代入)
| 構文 | 説明 |
|---|---|
tProd(var) |
チーム全員(自分含む)の指定変数の 積 を返します。 |
| 構文 | 説明 |
|---|---|
rankVal(var, n) |
全プレイヤー中で指定変数 var の値が n 番目(降順)のプレイヤーのその変数値を返します。n が範囲外の場合は 0 を返します。 |
| 構文 | 説明 |
|---|---|
rand(min, max) |
min 以上 max 未満のランダムな整数を返します。対象プレイヤーごとに独立した乱数が生成されます。 |
floor(式) |
式の結果を小数切り捨てして返します。 |
/(除算)演算子はすでに整数除算(切り捨て)として動作します。floor() は複合式の切り捨てに使います。
def イベント名(): の形式でイベントハンドラを定義します。def の外側に書いたコードは、プレイヤーが参加した時点の初期化処理として実行されます。
| イベント名 | 実行タイミング | 対象 |
|---|---|---|
def correct(): |
ホストが「正解」を押したとき | 現在の回答者のみ |
def wrong(): |
ホストが「不正解」を押したとき | 現在の回答者のみ |
def through(): |
ホストが「スルー」を押したとき | 回答者がいれば回答者のみ。いなければ誰にも実行されない |
def push(): |
プレイヤーが早押しボタンを押した瞬間 | 押したプレイヤーのみ |
def next(): |
correct / wrong / through のいずれかの処理が完了した後 | 全プレイヤー(一人ずつ順番に実行) |
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
# ネスト
if x > 0:
if x == 5 and y == 0:
z += 2
else:
z += 1
# 1行 if(インライン形式)
if x >= 10: win()
変数や式の値に応じて処理を切り替えます。マッチしたケースだけが実行され、以降のケースには処理が流れません(フォールスルーなし)。連続する 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() で設定した周り線の色をリセットします。 |
| コマンド | 使用可能なイベント | 説明 |
|---|---|---|
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 内でのカスタム変数への代入は各プレイヤーに正しく保存されます。
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