Siteswap Query Language
サイトスワップ探索言語 SsQL を使用することで、探索方法や結果の表示方法を細かく指定することができます。完全な指定方法は
FROM "パターン" LET 変数定義 WHERE 取得条件 SELECT 表示項目 ORDER BY ソート条件 LIMIT 最大件数
ですが FROM 句以外は省略可能です。省略しない句はこの順番に指定します。LET 句は複数指定が可能です。
FROM 句には探索パターンを記述し、その両側をダブルコーテーションで囲んでください。パターン中にダブルコーテーションを使用する場合はバックスラッシュ \
でエスケープする必要があります。
LIMIT 句に指定できるのは最大件数だけです。制限時間は指定できないので、探索を途中で止めたいときは停止ボタンを押してください。LIMIT 句を省略すると無限に探索を続けます。
取得条件
WHERE 句には
WHERE $0.balls == 3
のように変数、プロパティ、メソッド、演算子を組み合わせて取得条件を指定します。条件が成り立てばその文字列を取得し、成り立たなければ取得しません。WHERE 句を省略すると生成された全ての文字列を取得します。
変数には自動的に定義される変数とユーザーが定義する変数があります。自動変数は $0、$1、$2、... のように $ + 数字で指定します。ユーザー定義変数は後述します。$0 は文字列全体を表し、$1、$2、... は「1番目のグループ」「2番目のグループ」…を表します。$0 は省略して $ と記述することもできます。FROM 句で指定したパターンが (5+)([13]) なら次のように変数に文字列が代入されていきます。
$0 | $1 | $2 | |
---|---|---|---|
1回目 | 51 | 5 | 1 |
2回目 | 53 | 5 | 3 |
3回目 | 551 | 55 | 1 |
4回目 | 553 | 55 | 3 |
5回目 | 5551 | 555 | 1 |
: | : | : | : |
プロパティは変数 $0 などにドット . を続けて指定します。
プロパティ | 意味 | 例 |
---|---|---|
pattern | 文字列そのもの | 315315 |
length | 文字列長 | 6 |
sum | 高さの合計 | 18 |
reverse | 逆順形 | 513513 |
min | 最小形 | 153153 |
max | 最大形 | 531531 |
omission | 省略形 | 315 |
standard | 標準形 | 531 |
jugglable | ジャグリング可能か | 1 |
valid | サイトスワップか | 1 |
balls | ボール数 | 3 |
period | 周期 | 3 |
state | 状態数 | 19 |
int10 | 10進数値 | 315315 |
int36 | 36進数値 | 183315353 |
jugglable はジャグリング可能であれば 1、そうでなければ 0 になります。valid も同様です。balls と state はジャグリング可能でない場合は -1 になります。period は(ジャグリング可能であっても)サイトスワップ以外では -1 になります。int10 は左端から10進整数とみなせるところまでを数値化します。int36 も同様です。プロパティは省略可能で、省略すると pattern が指定されたとみなします。
メソッドもプロパティと同様ですが、$0.at(1) のように括弧に続けて引数を指定します。次の表の例では 12345 という文字列に対してメソッドを適用しています。
メソッド | 意味 | n = 1 | n = -2 |
---|---|---|---|
at(n) | 指定位置の文字 | 2 | 4 |
rotate(n) | ローテーション | 23451 | 45123 |
skip(n) | n 桁をスキップ | 2345 | 123 |
take(n) | n 桁を取得 | 1 | 45 |
いずれのメソッドも引数に 0 または正の数を指定すれば左から、負の数を指定すれば右から数えます。左端の位置は 0 で、右端が -1 です。
メソッドの中には引数としてラムダ式を取る反復メソッドもあります。
反復メソッド | 意味 |
---|---|
every(ラムダ式) | 全てのインデックスで成り立つ |
some(ラムダ式) | いずれかのインデックスで成り立つ |
ラムダ式は
インデックス変数 => 取得条件
または
インデックス変数, 全体変数 => 取得条件
という形式で指定します。ここでインデックス変数と全体変数はともにユーザー定義変数です。ユーザー定義変数は $index、$x1、$_ のように $ + 文字列で指定し、取得条件の中で使うことができます。次に前者の形式の具体例を挙げます。
$0.every($index => $0.at($index) == 1)
$0 の長さ n に対して 0 ~ n-1 が $index に順に代入され、=> の右辺が反復処理されます。右辺では 0 ~ n-1 桁目の文字が 1 かどうかを判定しているので、結局この例全体としては $0 の全ての桁が 1 かどうかを判定しています。
$0.take(2).some($index, $whole => $whole.at($index) == 1)
これは後者の形式の具体例で、$0 の左から2桁目までに 1 が存在するかどうかを判定しています。$whole の代わりに $0.take(2) と書いても同じですが、より簡潔に表現できるようになっています。
次は演算子を優先順位ごとに示したものです。
順 | 演算子 | 意味 |
---|---|---|
1 | . | 右がプロパティまたはメソッド |
2 | * | 掛け算 |
/ | 整数の割り算の商 | |
% | 整数の割り算の余り | |
3 | + | 足し算 |
- | 引き算 | |
& | 文字列の連結 | |
4 | == | 左右の値が等しい |
!= | 左右の値が異なる | |
<> | ||
< | 左が右より小さい | |
<= | 左が右以下 | |
> | 左が右より大きい | |
>= | 左が右以上 | |
IN(...) | 左の値が ... に含まれる | |
NOT IN(...) | 左の値が ... に含まれない | |
5 | NOT | 右の条件が成り立たない |
6 | AND | 左右が共に成り立つ |
7 | OR | 左右いずれかが成り立つ |
同じ優先順位の演算子が並んでいるときは左から順に評価します。優先順位を変更するときは 2*(3+4) のようにその部分を括弧で囲んでください。
数値としては10進整数しか扱いません。文字列に対して数値計算するときは暗黙的に int10 プロパティが指定されているとみなします。比較演算子の結果は「成り立つ」場合が 1、「成り立たない」場合が 0 です。NOT、AND、OR では「成り立たない」を表すのは数値の 0、文字列の "0"、それに空文字列 "" だけで、それ以外は全て「成り立つ」となります。
IN 演算子は
$0.standard IN("71", "62", "53")
のように使います。この場合は変数 $0 の標準形が 71、62、53 のいずれかであれば成り立つ、つまり 1 になります。IN に指定できる各項目は文字列または数値の定数だけです。
表示項目
SELECT 句には
SELECT $0 "(" $0.balls ")"
のように変数や定数などの表示項目を空白で区切って並べます。表示される文字列には空白は含まれませんので、必要ならダブルコーテーションの中に空白を指定してください。ダブルコーテーションで囲まれた文字列はそのまま出力されます。SELECT 句を省略すると生成された文字列全体(項目としては $0.pattern)を表示します。
演算子も使用できます。例えば
SELECT $0.int10 "+1=" $0.int10 + 1
とすれば 3+1=4 などが表示されます。
同じ文字列の出力を抑制するには SELECT に続けて DISTINCT と指定します。生成された文字列の、重複を除いた種類だけを表示したいときは
SELECT DISTINCT $0
のように記述します。DISTINCT は表示件数を絞るという意味で WHERE 句と似ていますが、WHERE は生成された文字列が満たす条件を対象とするのに対して DISTINCT は SELECT で加工された文字列全体が既に存在するかどうかだけを対象とする点が異なります。
ソート条件
ORDER BY 句には条件となる項目をカンマ区切りで指定します。
ORDER BY $0.period DESC, $0
条件の後に DESC を指定すれば降順、ASC を指定するか何も書かなければ昇順となります。上の例は「サイトスワップ周期の降順かつ文字列の昇順」という意味です。生成された文字列が 3、441、531 なら、まずサイトスワップ周期が長い 441 と 531 が前に、周期が短い 3 が後に来ます。441 と 531 では 441 の方が文字列として小さいため前に来て、最終的には 441 531 3 という順番で出力されます。
ORDER BY 句を省略すると生成された順に表示します。
変数定義
LET 句では文全体で使用できる変数を定義します。
LET $const = "123"
イコール = の左が変数名、右が定義内容です。ラムダ式に登場するユーザー定義変数と同様、変数名は $ + 文字列で指定します。文字列の1文字目はアルファベットまたはアンダースコア _ で、2文字目以降はそれに加えて数字も使用できます。大文字と小文字は区別せず、$name も $Name も $NAME も同じ名前として扱われます。同じ名前の変数を複数回定義することはできません。
1つの SsQL 文に対して LET 句はいくつでも記述できます。定義内容には定数だけでなく、他の変数も使用できます。
LET $var1 = $1 LET $var2 = $var1 + 3 LET $var3 = $0.at($index)
未定義変数を使用するとエラーになりますが、定義する順番は問わないため、$var3 についても以下のような使い方をすれば問題ありません。
WHERE $0.every($index => $var3 < 3)
コメントその他
SsQL にはコメントを記述することもできます。
-- 1行コメント /* 複数行に 渡る コメント */
-- から行末までが行コメント、/* から */ までがブロックコメントです。行コメントは1行に1つしか指定できず、複数行に渡ることもできません。一方でブロックコメントは複数行に渡って記述することもできますし、行の途中にいくつも記述することができます(ただしコメントの入れ子はできません)。
SsQL はフリーフォーマットで記述することができ、キーワードとキーワードの間の改行、空白、コメントは無視されます。
入力した文字のうち全角の英数字と記号は半角に、大文字は小文字に変換されます。エラーがあった場合のメッセージも半角小文字に変換された文字列で表示します。
言語仕様
参考までに、受理する SsQL の仕様を HABA 形式 で記しておきます。
Query ::= From Let* Where? Select? Order? Limit? ; From ::= 'FROM' String ; String ::= """(\\""|[^""])*""" ; Let ::= 'LET' User '=' Term ; Where ::= 'WHERE' Condition ; Condition ::= Part ('OR' Part)* ; Part ::= Unit ('AND' Unit)* ; Unit ::= 'NOT'? Expression ; Expression ::= Term (Compare Term | Clause)? ; Term ::= Factor (('+' | '-' | '&') Factor)* ; Factor ::= Value (('*' | '/' | '%') Value)* ; Value ::= Element ('.' (Property | Method | Iterator))* ; Element ::= Auto | User | Literal | '(' Condition ')' ; Auto ::= "\$[0-9]*" ; User ::= "\$[a-z_][a-z_0-9]*" ; Literal ::= String | Integer ; Integer ::= "[0-9]+" ; Property ::= 'pattern' | 'length' | 'sum' | 'reverse' | 'min' | 'max' | 'omission' | 'standard' | 'jugglable' | 'valid' | 'balls' | 'period' | 'state' | 'int10' | 'int36' ; Method ::= ('at' | 'rotate' | 'skip' | 'take') '(' Parameter ')' ; Parameter ::= Term | '-' Value ; Iterator ::= ('every' | 'some') '(' Lambda ')' ; Lambda ::= User (',' User)? '=>' Condition ; Compare ::= '==' | '!=' | '<>' | '<' | '<=' | '>' | '>=' ; Clause ::= 'NOT'? 'IN' '(' List ')' ; List ::= Literal (',' Literal)* ; Select ::= 'SELECT' 'DISTINCT'? View ; View ::= Term+ ; Order ::= 'ORDER' 'BY' Multiple ; Multiple ::= Single (',' Single)* ; Single ::= Value ('ASC' | 'DESC')? ; Limit ::= 'LIMIT' Term ; Space ::= "\s+" ; Line ::= "--[^\n]*(\n|$)" ; Block ::= "/\*((?!\*/)[\s\S])*\*/" ;