PureNScripterで擬似ハッシュ
今週のスクリプタ便り | FCめがぶーWEBページを読んだ。
ので、気分転換に昔書き散らしたのを清書してみた。
なお、このスクリプトは、拙作の半角全角判定(文字数取得機能追加) - 永字八法をベースにしている。
どういうものか。
一つの文字列変数を構造体と言うよりもハッシュや辞書配列のように扱う何か。
(半角全角ライブラリに加え)四つの命令を追加する。
- getstr
- setstr
- getnum
- setnum
名前だけ見れば機能は推測できると思う。一つの文字列変数をオブジェクトとしてみなし、与えたキーに対応する文字列または数値を取得または設定する。
書式は共通で、三つの引数をとる。
- オブジェクトとみなす文字列変数
- キーに相当する文字列変数
- 設定したい文字列または数値・あるいは、取得した文字列または数値を格納する変数
しかしまあ、速度は度外視してるから、まさかこれでアクションゲームは作らないと思う。RPGのキャラクターを格納したりするにはいいんじゃないかな。
注意点
キーや値との境目に、タブ「\t」を使っているので、キーや値にタブを混入させると色々困ったことになる。
いやまあ、普通にやってれば普通は混入しないとは思うんだけれども、一応指摘しておく。
それと、一旦オブジェクトとしてみなした文字列変数を他の手段でいじったりしたら、どういう挙動をするかの保証はないとする。
スクリプト(Aパート)
define節、game以上に記述。
mov %0,100 ; お好みで。 ; ここからは、http://d.hatena.ne.jp/eiji8pou/20100820/1282234185 を参照のこと numalias is_zen_result,%0:inc %0 numalias is_zen_target,%0:inc %0 numalias is_zen_cmp,%0:inc %0 numalias is_zen_len,%0:inc %0 numalias letter_result,%0:inc %0 numalias letter_base,%0:inc %0 numalias letter_loop,%0:inc %0 numalias letter_len,%0:inc %0 numalias cut_base,%0:inc %0 numalias cut_head,%0:inc %0 numalias cut_rest,%0:inc %0 numalias cut_len,%0:inc %0 numalias cut2_base,%0:inc %0 numalias cut2_left,%0:inc %0 numalias cut2_right,%0:inc %0 numalias cut2_temp,%0:inc %0 defsub is_zenkaku defsub is_hankaku defsub letter_len defsub letter_num defsub cut_head_letter defsub cut_text defsub is_ja ; ここまでは、http://d.hatena.ne.jp/eiji8pou/20100820/1282234185 を参照のこと numalias ob_ob,%0:inc %0 numalias ob_mode,%0:inc %0 numalias ob_key,%0:inc %0 numalias ob_val,%0:inc %0 numalias ob_res,%0:inc %0 numalias ob_res2,%0:inc %0 numalias ob_new,%0:inc %0 numalias ob_k,%0:inc %0 numalias ob_v,%0:inc %0 numalias ob_letter,%0:inc %0 numalias ob_flag,%0:inc %0 numalias ob_temp,%0:inc %0 stralias ob_sp," " defsub getstr defsub setstr defsub getnum defsub setnum
スクリプト(Bパート)
start節end以下に記述
*getnum getparam s%ob_ob,$ob_key,i%ob_res2 getstr $%ob_ob,$ob_key,$ob_temp mov %%ob_res2,0 notif $ob_temp="" atoi %%ob_res2,$ob_temp return *setnum getparam s%ob_ob,$ob_key,%ob_val itoa $ob_val,%ob_val setstr $%ob_ob,$ob_key,$ob_val return *getstr getparam s%ob_ob,$ob_key,s%ob_res mov %ob_mode,0 ; getモード goto *obstr_main *setstr getparam s%ob_ob,$ob_key,$ob_val mov %ob_mode,1 ; setモード goto *obstr_main *obstr_main if %ob_mode=0 mov $%ob_res,"" ; こたえを返す変数を初期化 if %ob_mode=0 if $%ob_ob="" return ; getモードで、オブジェクトが空の時のショートカット if %ob_mode=1 if $%ob_ob="" goto *obstr_before_end mov %ob_flag,0 ; フラグを初期化 mov $ob_new,"" ; 新しいオブジェクトを初期化 *obstr_main_loop mov $ob_k,"" mov $ob_v,"" *obstr_main_get_key cut_head_letter $%ob_ob,$ob_letter,$%ob_ob ; オブジェクトから最初の一文字を取得。 if $ob_letter=ob_sp goto *obstr_main_get_val add $ob_k,$ob_letter goto *obstr_main_get_key *obstr_main_get_val cut_head_letter $%ob_ob,$ob_letter,$%ob_ob ; オブジェクトから最初の一文字を取得。 if $ob_letter=ob_sp goto *obstr_main_get_check add $ob_v,$ob_letter goto *obstr_main_get_val *obstr_main_get_check notif $ob_key=$ob_k goto *obstr_main_get_check2 ; キーが一致しない。 mov %ob_flag,1 ; 指定されたキーとオブジェクトのキーが一致した。 if %ob_mode=0 mov $%ob_res,$ob_v ; getモードなら値を返す。 if %ob_mode=1 mov $%ob_v,$ob_val ; setモードなら値を変更する。 *obstr_main_get_check2 ; オブジェクトを再構成する。 add $ob_new,$ob_k add $ob_new,ob_sp add $ob_new,$ob_v add $ob_new,ob_sp notif $%ob_ob="" goto *obstr_main_loop ; 空になるまで続く。 mov $%ob_ob,$ob_new ; 再構成 if %ob_flag=0 if %ob_mode=0 goto *obstr_end *obstr_before_end add $%ob_ob,$ob_key add $%ob_ob,ob_sp add $%ob_ob,$ob_val add $%ob_ob,ob_sp *obstr_end return ; ここからは、http://d.hatena.ne.jp/eiji8pou/20100820/1282234185 を参照のこと ;================== ; is_zenkaku ;================== ; 文字列を与え、その文字列の先頭の文字が全角かどうか判定する。 ; 第一引数:結果を受け取る数値変数 ; 第二引数:判定対象の文字列(変数) ; 結果は、0が半角、1が全角 ; 依存:なし *is_zenkaku getparam i%is_zen_result,$is_zen_target mov %%is_zen_result,0 cmp %is_zen_cmp,$is_zen_target,"゚": if %is_zen_cmp>0 mov %%is_zen_result,1:return cmp %is_zen_cmp,$is_zen_target,"。":notif %is_zen_cmp<0 return cmp %is_zen_cmp,$is_zen_target,"~": if %is_zen_cmp>0 mov %%is_zen_result,1:return return ;================== ; is_hankaku ;================== ; 文字列を与え、その文字列の先頭の文字が半角かどうか判定する。 ; 第一引数:結果を受け取る数値変数 ; 第二引数:判定対象の文字列(変数) ; 結果は、0が全角、1が半角 ; 依存:is_zenkaku *is_hankaku getparam i%is_zen_result,$is_zen_target is_zenkaku %%is_zen_result,$is_zen_target mov %%is_zen_result,1-%%is_zen_result return ;================== ; letter_len ;================== ; 文字列を与え、その文字列の先頭の文字が、1バイトか2バイトかを判定する。 ; 第一引数:結果を受け取る数値変数 ; 第二引数:判定対象の文字列(変数) ; 結果は、0が文字列無し、1が半角、2が全角 ; 依存:is_zenkaku *letter_len getparam i%is_zen_result,$is_zen_target mov %%is_zen_result,0 if $is_zen_target="" return is_zenkaku %%is_zen_result,$is_zen_target inc %%is_zen_result return ;================== ; letter_num ;================== ; 文字列を与え、その文字列が文字数でどれだけの長さになるかを返す。 ; 第一引数:結果を受け取る数値変数 ; 第二引数:判定対象の文字列(変数) ; 結果は、文字数 ; 依存:letter_len *letter_num getparam i%letter_result,$letter_base mov %%letter_result,0 ; 初期設定 if $letter_base="" return ; 空文字列なら、0を返す。 len %letter_base,$letter_base ; バイト長さを取得 if %letter_base=1 mov %%letter_result,1:return ; 1バイト長さなら、1を返す。 mov %letter_loop,0 ; 初期設定その2 *letter_num_loop mid $letter_loop,$letter_base,%letter_loop,1 ; 一文字を取得 letter_len %letter_len,$letter_loop ; その文字の全角半角判定 inc %%letter_result ; 一文字は一文字 add %letter_loop,%letter_len ; 文字のバイト数分ずらす。 if %letter_loop<%letter_base goto *letter_num_loop return ;================== ; cut_head_letter ;================== ; 文字列を与えると、1バイトか2バイトかを判別して、その先頭の文字を返す。 ; 第一引数:分割したい文字列 ; 第二引数:先頭の文字列を受ける文字列変数 ; 第三引数:先頭の文字を落とした残りを受ける文字列変数 ; 依存:letter_len ; 第一引数と第三引数を同じ文字列変数を使うと便利かも。 *cut_head_letter getparam $cut_base,s%cut_head,s%cut_rest mov $%cut_head,"" ; 初期設定 mov $%cut_rest,"" ; 初期設定 if $cut_base="" return ; ショートカット len %cut_base,$cut_base if %cut_base=1 mov $%cut_head,$cut_base:return ; ショートカットその2 letter_len %cut_len,$cut_base ; 先頭の文字の長さを取得。 if %cut_len=%cut_base mov $%cut_head,$cut_base:return ; ショートカットその3 ; それ以外ならば、 mid $%cut_head,$cut_base,0,%cut_len ; 先頭から1文字ないし2文字を取得 mid $%cut_rest,$cut_base,%cut_len,%cut_base-%cut_len ; 残りを格納 return ;================== ; cut_text ;================== ; 文字列と数値を与えると、その文字数で分割して返す。 ; 第一引数:分割したい文字列 ; 第二引数:何文字で分割するか。 ; 第三引数:先頭から第二引数の文字列 ; 第四引数:残りの文字列 ; 依存:cut_head_letter ; 数値を140にすると、Twitterに使える。 *cut_text getparam $cut2_base,%cut2_base,s%cut2_left,s%cut2_right mov $%cut2_left,"" mov $%cut2_right,"" if $cut2_base="" return ; ショートカット *cut_text_loop cut_head_letter $cut2_base,$cut2_temp,$cut2_base ; 分割して$cut2_tempに入れる。 add $%cut2_left,$cut2_temp if $cut2_base="" return dec %cut2_base if %cut2_base>0 goto *cut_text_loop mov $%cut2_right,$cut2_base ; 残りを入れる。 return ;================== ; is_ja ;================== ; 文字列を与え、その文字列に2byte文字が含まれているかどうかを返す。 ; 第一引数:結果を受け取る数値変数 ; 第二引数:判定対象の文字列(変数) ; 結果は、0が全て半角、1が全角が含まれる。 ; 依存:なし *is_ja getparam i%is_zen_result,$is_zen_target ; 結果を格納する変数,対象の文字列 mov %%is_zen_result,0 ; 結果を0で初期化 len %is_zen_len,$is_zen_target ; 対象の文字列の長さを取得 mov %is_zen_target,-1 ; 対象も文字列へのカーソル *is_ja_loop inc %is_zen_target ; カーソルを一つすすめる。 if %is_zen_len-2 < %is_zen_target return ; 残り文字数が2未満ならば、0で回答 mid $is_zen_len,$is_zen_target,%is_zen_target,2 ; カーソル位置から2文字を取得。 cmp %is_zen_cmp,$is_zen_len,"゚": if %is_zen_cmp>0 mov %%is_zen_result,1:return cmp %is_zen_cmp,$is_zen_len,"。":notif %is_zen_cmp<0 goto *is_ja_loop ; ループする。 cmp %is_zen_cmp,$is_zen_len,"~": if %is_zen_cmp>0 mov %%is_zen_result,1:return goto *is_ja_loop ; ループする。 ; ここまでは、http://d.hatena.ne.jp/eiji8pou/20100820/1282234185 を参照のこと