12.DLLを使わずにCSVをメモリノートに変換するモジュール
22.ウィンドウの端まで来たら自動で折り返す文字列表示モジュール
29.標準命令だけでllmod.asのcharlower,charupperと同じことをする
01.閏年かどうか調べる
知らない方はいないでしょうが一応説明。閏年とは4年に1度ズレを修正するために2月に1日プラスされる年です。
カレンダー関係のプログラムを組む方はコレに気を付けないと「2月29日問題」が生じてしまいます。
4年に1度2月29日があるわけですが、実は例外があります。
100で割り切れる年(1900年,2100年など)は閏年にはならないのです。
さらに例外があり100で割り切れて400でも割り切れる年(1600年,2000年)は閏年になるのです。
少々面倒くさいですが取り入れましょう。「2100/02/29」とならないように。。。
(例)年を入力し閏年かをチェックする
screen 0,200,50
pos 5,10 : input year,60,30,4 ; 年を入力するボックス
objsize 100,30
pos 80,10 : button"チェック",*seach
stop
*seach
flg=0 ; フラグを初期化する
if year\4=0{ ; 4で割り切れるかチェック
flg=1 ; 4で割り切れたらとりあえず閏年の候補とする
if year\100=0{ ; さらに100で割り切れるかチェック
flg=0 ; 100で割り切れたら閏年候補を取り消す
if year\400=0{ ; さらに400で割り切れるかチェック
flg=1 ; 400で割り切れたらまた候補にする(必ず閏年ですが)
}
}
}
if flg=1{ ; 閏年の候補ならダイアログボックスを表示
dialog ""+year+"年はうるう年です"
}else{
dialog ""+year+"年はうるう年ではないです"
}
stop
02.変数内の数値・文字列を別の変数の内容と交換する
変数Aの内容(例としてabcde)と変数B(xyz)をAにxyz、Bにabcdeと入れ替えるには、
それぞれの交換する変数と一時変数の3つを使用します。
このアルゴリズムは基本ですので知らない方は覚えておいて損はないです。
(例)inputの内容を入れ替える
a="文字列1"
b="文字列2"
input a,200,25,64
input b,200,25,64
button"change",chg
stop
*chg
tmp=a
a=b
b=tmp
objprm 0,a
objprm 1,b
stop
論理演算を行えば2つだけで行うことが出来ますが数値のみです。
a=123 : b=987
mes "変換前 a="+a+" b="+b
a=a^b
b=b^a
a=a^b
mes "変換後 a="+a+" b="+b
stop
03.文字列を暗号化する
サウンドノベルのシナリオ等のデータがエディターで簡単に開けてしまうと
先の展開が分かってしまって面白くなくなってしまいます。
対策として、こういったテキストファイルは他人が見ても分からないように暗号化して、
ソフト側からロードする際に復号化して利用することで回避できると思います。
暗号化したモノをmesbox等に表示する場合、注意すべきポイントは、
文字列内にNULL文字が存在するとNULL文字以降の内容は表示されないことです。
NULL文字を検索し、NULL文字を別の文字に変更したものを別の変数に代入し表示しましょう。
(例)ビット反転による暗号化
sdim buf,64000,2 ;実際の文字列が入る変数とNULLを別の文字に変更したのが入る変数、二つ用意する
sdim file,256
key=100 ; 暗号鍵(0〜255の間の数値にしましょう)
objsize 640,25
button"暗号 / 復号",cipher
mesbox buf.1,640,455 ;書き換え不可のテキストボックス
dialog "txt",16
if stat=0 : end
bload refstr,buf
file=refstr
size=strsize
if size>64000 : dialog"サイズが大きすぎます" : end ;サイズが約64KB以上なら終了する
goto *disp
*cipher
repeat size
peek tmp,buf,cnt
tmp=tmp^key ; ココがビット反転
poke buf,cnt,tmp
loop
*disp
repeat size
peek tmp,buf,cnt
if tmp=0 : tmp=' ' ;取り出した文字がNULLなら半角スペースに置き換える
poke buf.1,cnt,tmp ;NULLをスペースに置き換えながら一文字ずつ表示用変数に入れていく
loop
objprm 1,buf.1
stop
04.DLLを使わずにソート(並べ替え)をする
文字列の並べ替えは少々面倒くさいですが、DLLなしで実現できます。
(例)文字列の先頭文字を見比べて大小を決めソートする
sdim m,64,2 ; 比較する文字列
sdim moji,256 ; 比較される文字列
moji="asd33z\nasd32499\nasd324あ\nasd3A\nasd33z\nasd3249989"
mes ""+moji+"\n---------------------"
notesel moji
notemax kazu ; 最終行までソートを繰り返せるように行数を取得
i=0 ; 比較する文字列の行数
repeat kazu-1
repeat kazu-1-i
noteget m.0,i
peek m1,m.0,ichi ; ichiは比較対照文字の位置(初めは0)
noteget m.1,i+cnt+1
peek m2,m.1,ichi
if m1>m2{ ; 比較する側が大きければ入れ替える(m1<m2とすると降順でソート)
notedel i
noteadd m.1,i
notedel i+cnt+1
noteadd m.0,i+cnt+1
}
if m1=m2{ ; 比較対照文字が同じ文字だった場合の処理
ichi++ ; 次の文字を比較対照に変更
continue cnt ; 先ほどの繰り返しをやり直す
}
ichi=0 ; 比較対照文字を1文字目に戻しておく
loop
i++
loop
mes moji
stop
05.数値の桁そろえをする
数値を画面上に表示すると文字列と同じように左詰で表示されてしまいます。
strを使えば「00250」のようにゼロを入れて桁をそろえることが出来ます。
ゼロが入るのが嫌と言う方は下のサンプルをお試しください。
(例)桁そろえをする
dim ten,3
ten=250,10,1024 ; 「ten.0=250:ten.1=10:ten.2=1024」と書いたのと同じ意味
repeat 3
tmp=" "+ten.cnt ; (そろえたい桁数-1)個スペースを用意
strmid tmp,tmp,-1,4 ; 最後の「4」の所に揃えたい桁数を指定
mes tmp
loop
stop
06.rndで重複しない数値を取り出す
変数や配列を100個用意し、それぞれに0〜99の数値を重複することなく入れていくには、
1度使った値を記憶させて行けばよいわけです。
同じ数値が以前に使われたかチェックし、使われていたらもう一度乱数を取り出す。
コレを繰り返すことによりすべてに違った値を入れることが出来るのです。
(例)重複しない乱数を作成する(0〜200の数値)
dim buf,2,200 ; 200個入れる変数を二つ用意(0は乱数を入れる,1は重複のチェック用)
randomize
*random
repeat 200
await 0 ; タスクを回す(数が多くなると終了するまで操作ができなくなる為)
rnd rand,200 ; とりあえず乱数作成
buf.0.cnt=rand ; 「buf.0.(0〜順に199まで)」に乱数を入れる
if buf.1.rand=1 : continue cnt ; 「 buf.1.(乱数)」に1が入っているとやり直し
buf.1.rand=1 ; 「buf.1(乱数)」に1を入れて同じ数値を使えないようにする
prg=cnt/2 ; 必要なし(現在の進行状態を入れる変数です)
title ""+prg+"%完了" ; 必要なし(タイトルバーに進行状態を表示する)
loop
*print_num
title "100%完了"
dialog"ランダムな数値を表示させますか?",3,"完了"
if stat=7 : end
x=35:y=5
font "MS ゴシック",12,0
color 200,0,0 : pos 5,5:mes "番号"
color 0,0,0 : pos 5,20:mes "乱数"
repeat 200
num=cnt ; 必要なし(番号表示)
str num,3 ; 必要なし(番号を3けたに合わせる)
color 200,0,0 : pos x,y : mes num
color 0,0,0 : pos x,y+15 : mes buf.0.cnt
x+=25
if x>610 : x=35 : y+=45 ; 画面の右端に来た時に左端の一段下にカレントポジション移動
loop
stop
07.英小文字・大文字変換
アルファベットを小文字化or大文字化するにはアスキーコードと呼ばれる文字を数値で表したモノに一度変換します。
HSP内部ではもともとこのアスキーコードで管理しているわけですが・・・。
| コード表 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 30 | 空白 | ! | " | # | $ | % | & | ' | ||
| 40 | ( | ) | * | + | , | - | . | / | 0 | 1 |
| 50 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; |
| 60 | < | = | > | ? | @ | A | B | C | D | E |
| 70 | F | G | H | I | J | K | L | M | N | O |
| 80 | P | Q | R | S | T | U | V | W | X | Y |
| 90 | Z | [ | \ | ] | ^ | _ | ` | a | b | c |
| 100 | d | e | f | g | h | i | j | k | l | m |
| 110 | n | o | p | q | r | s | t | u | v | w |
| 120 | x | y | z | { | | | } | ~ |
(例)小文字←変換→大文字
buf="ABCdeFghIJklm"
objsize 100,25
input buf,300,25,30
button "変換",*change
stop
*change
strlen len,buf
repeat len
peek moji,buf,cnt
if (moji>=65)&(moji<=90) : moji+=32 : else : if (moji>=97)&(moji<=122) : moji-=32
poke buf,cnt,moji
loop
color 255,255,255 : boxf
color
pos 10,100 : mes buf
stop
08.1バイト2バイト文字の判別
文字には1バイト文字と2バイト文字が存在します。そう全角・半角文字と呼ばれる奴ですね。
peek命令を使用すれば気づきますが、2バイト文字の1バイト目の値は必ず「129から159、または224以上」となります。
これを覚えておけば、例えば文字数を数えることなどが容易にできます。
(例)文字を数える
buf="1byte、2byte文字混合の文字数を調べる"
mes buf
repeat
peek tmp,buf,ichi
if tmp>128&(tmp<160)|(tmp>223) : ichi+=2 : else : ichi+
if tmp==0 : break
moji+
loop
mes "文字数は"+moji+"文字です"
stop
09.時間挿入
メモ帳等の時間の挿入はどうするのでしょうか?
gettime命令で時間を取得し、08の方法でクリップボードを操作して貼り付けてみましょう。
(例)文字を数える
sdim buf,16000
buf=""
mesbox buf,640,460,1
objsize 640,20
button "時間貼り付け",now
pos 0,-20 : input clip,100,20
stop
*now
gettime time.0,4 ; 時間
gettime time.1,5 ; 分
gettime time.2,6 ; 秒
clip=""+time+":"+time.1+"."+time.2
strlen mojiend,clip
objprm 2,clip
a=0
objsend 2,$b1,0,mojiend,1 ; 取得時間を選択
objsend 2,$300,0,a,1 ; クリップボードに送る
objsend 0,$302,0,a,1 ; キャレット位置にクリップボード内容貼り付け
stop
10.時間取得モジュール
gettime命令で日付・時間を毎回取得するのは意外と面倒ですよね。
こういう時は何度でも再利用できるようにモジュールにしてしまいましょう。
時間まとめて取得する命令の書式は「now 取得したものを入れる変数,取得するもの」です。
p2の取得するものは
1で年
2で月
4で曜日
8で日
16で時
32で分
64で秒
128でミリ秒を取得し、取得したい物が複数ある場合は取得したい物の値を足してください。
(例)時間取得
;************ 概要説明 ************
;
; now p1,p2
;
; p1=変数 : 取得した日時を代入する変数
; p2=1〜 : 取得するもの
;
;**********************************
#module "time"
#deffunc now val,int
mref time,24
mref get,1
sdim day,3,7
day="日","月","火","水","木","金","土"
time=""
if get&1 : gettime tmp,0 : time+=""+tmp+"年"
if get&2 : gettime tmp,1 : time+=""+tmp+"月"
if get&8 : gettime tmp,3 : time+=""+tmp+"日"
if get&4 : gettime tmp,2 : time+="("+day.tmp+")"
if get&16 : gettime tmp,4 : time+=""+tmp+"時"
if get&32 : gettime tmp,5 : time+=""+tmp+"分"
if get&64 : gettime tmp,6 : if get&128 : tmp.1=tmp : else : time+=""+tmp+"秒"
if get&128 : gettime tmp,7 : if get&64 : time+=""+tmp.1+"."+tmp+"秒" : else : time+="0."+tmp+"秒"
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
repeat
redraw 0
color 255,255,255 : boxf : color
now nowtime,112 ; 新取得命令(時間・分・秒を取得する)
pos 0,0 : mes nowtime
redraw
wait 100
loop
11.余分文字を取り除くモジュール
変数の中に邪魔な文字が不特定の場所にあり、それらをすべて取り除きたい場合に利用しましょう。
文字列ではなく文字のASCIIコードを指定してください。
変数内の余計な文字を取り除いたものがシステム変数refstrに返ってきます。
(例)ハイフン(-)を取り除く
;************ 概要説明 ************
;
; remove p1,p2
;
; p1=0〜255 : 余分文字のキャラクタのASCIIコード
; p2=変数 : 余分文字を抜きたい変数
;
;**********************************
#module "removes"
#deffunc remove int,val
mref excess,0
mref variable,25
mref result,65
strlen len,variable
repeat len
peek tmp,variable,cnt
if evasion>0 : evasion--
if tmp>128&(tmp<160)|(tmp>223) : evasion=2 ; 2バイト文字の場合下位バイトは除去を無視する
if tmp==excess&(evasion==0) : continue
poke result,num,tmp
num+
loop
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
buf="abc-def-ghij-klm-n-opq-rs-tu-vw-xyz" ; 元となる変数
remove '-',buf ; ASCIIコードを指定するかシングルクォートで囲んだ文字を指定する
mes refstr
stop
12.DLLを使わずにCSVをメモリノートに変換
hspda.dllにCSV(,で区切られたデータ)をメモリノート(1行が1つのデータ)に変換する命令がありますが
コレだけのためにDLLを使うのが嫌という方は下記のモジュールを使用してみてください。
hspda.dllではp2に文字列か文字列変数のどちらでもいけましたが、
この命令は文字列変数しかご利用いただけません。文字列だとエラーが出てしまいます。
文字列で使用したいという方は、ご自分でサンプルを変更してください。
(例)CSVをメモリノートに変換
;************ 概要説明 ************
;
; csvtonote p1,p2
;
; p1=結果が代入される文字列型の変数名
; p2=CSV形式の文字列変数名
;
;**********************************
#module "csv"
#deffunc csvtonote val,val
mref result,24
mref origin,25
repeat
getstr tmp,origin,ichi,','
if cnt>0 : result+="\n"
result+=tmp
instr chk,origin,",",ichi
if chk==-1 : break
strlen len,tmp
ichi+=len+1
loop
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
buf=",a,b,c,d,,e"
csvtonote buf2,buf
mes buf2
stop
13.DLLを使わずにCSVを配列に変換
12をやったついでにhspda.dllの他のものもやってしまおうということでやってみました。
hspda.dllにCSVを配列変数に入れる命令が存在しますがDLLを使うのが嫌という方のために。
DLLは、オーバーフロー(配列の限界を越えた)したとき越えた部分は無視されますが、
下記のモジュールはエラーになってプログラムを中断してしまいます。
あらかじめオーバーフローしないように大きめに確保しておいてください。
(例)CSVを配列に代入
;************ 概要説明 ************
;
; csvtostr p1,p2
;
; p1=結果が代入される文字列型の配列変数名
; p2=CSV形式の文字列変数名
;
;**********************************
#module "csv"
#deffunc csvtostr val,val
mref result,56
mref origin,25
repeat
getstr tmp,origin,ichi,','
result.cnt=tmp
instr chk,origin,",",ichi
if chk==-1 : break
strlen len,tmp
ichi+=len+1
loop
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
count=10 ; 配列変数の要素最大数
sdim buf2,2,count
buf=",a,b,c,d,,e,f,g"
csvtostr buf2,buf
repeat count
mes buf2.cnt
loop
stop
14.メモリノートをCSVに変換
12の逆バージョンもついでにやってしまおうというものです。
なぜかDLLにはこの命令が存在しませんでした。必要のない命令なのかもしれませんね…。
(例)メモリノートからCSV形式
;************ 概要説明 ************
;
; notetocsv p1,p2
;
; p1=結果が代入される文字列型の配列変数名
; p2=メモリノートの文字列変数名
;
;**********************************
#module "csv"
#deffunc notetocsv val,val
mref result,24
mref origin,25
notesel origin
notemax max
repeat max
noteget tmp,cnt
if cnt!=0 : result+=","
result+=tmp
loop
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
buf="a\nb\nc\n\nd\ne\nf"
notetocsv buf2,buf
mes buf2
stop
15.16進数→10進数変換
HSPには10進数から16進数には簡単に変換できますが、逆は載ってませんので自前で作成しました。
(例)16→10
;************ 概要説明 ************
;
; hexchg p1
;
; p1="strings" : 16進数
;
;**********************************
#module "CardinalNumberChange"
#deffunc hexchg val
mref chgval,24
mref stt,64
strlen keta,chgval
num=chgval
chgval=0
repeat keta,1
peek tmp,num,keta-cnt
if tmp<'0'|(tmp>'f') : break ; 変換元変数が正式な10進数以外のものが入っている場合終了
if tmp>='a' : tmp-=87 : else : tmp-=48
dignity=1
repeat cnt-1
dignity=dignity*16
loop
chgval+=dignity*tmp
loop
str chgval
stt=chgval
int stt
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
buf=98765
mes "10進数 "+buf+"\n\n ↓\n"
str buf,16
mes "16進数 "+buf+"\n\n ↓\n"
hexchg buf
mes "10進数 "+buf
stop
16.基数変換
15で16→10進数変換をしました。基数変換で使用するのは大体16,10,2進数のいずれかでしょう。
ここでは2進数に変換したいと思います。(他のものへ変えたい場合は2〜32進数に対応したモジュールをご利用ください)
(例)10→2
buf=123 ; 変換元数値
two=""
repeat
tmp=buf\2
two=""+tmp+""+two
buf=buf/2
if buf=0 : break
loop
mes two
stop
17.英字小文字化・大文字化・大小反転モジュール
07で英字を大小文字に変換するためにはpeek命令で取り出した値に+-32すれば変換できると説明しました。
何回も変換しなければならないようなことがある場合、非常に面倒です。
一つの命令だけでできるようにモジュール化してしまいましょう。
(例)英字小文字化・大文字化・大小反転
;************************* 命令説明 *********************
;
; tagchg p1,p2
;
; p1=変数 : 変換する文字列型変数
; p2=0〜(0) : 0は大文字化,1は小文字化,それ以外は大小反転
;
;********************************************************
#module "alphabet"
#deffunc tagchg val,int
mref tag,24
mref size,1
strlen len,tag
repeat len
peek tmp,tag,cnt
if size=0 : if tmp>96&(tmp<123) : tmp-=32
if size=1 : if tmp>64&(tmp<91) : tmp+=32
if size>1 : if tmp>96&(tmp<123) : tmp-=32 : else : if tmp>64&(tmp<91) : tmp+=32
poke tag,cnt,tmp
loop
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
sdim msg,9,3
msg="大文字化","小文字化","大小反転"
buf="aBcdeFGHijKlmnOpQRstuvwxYZ"
mes ""+buf+"\n---------------------------"
repeat 3
tmp=buf
tagchg tmp,cnt ; 変数内の英字を0で大文字化,1で小文字化,その他で反転
mes ""+msg.cnt+" "+tmp
loop
stop
18.32768以上にも対応した乱数発生モジュール
32768以上の乱数がほしくなった場合はどうしますか?乱数を二つ以上組み合わせればできないことはありませんね。
しかし乱数の上限を不定にしたいとなった時どうしますか?
そういったときに登場するのがモジュールでしょう。
このrand命令と通常のrndの違う点が少しあります。
・乱数の上限が2147483647(HSPの標準で扱える最高値)
・randomizeで初期化しなくとも使える(逆に言うと毎回同じ擬似乱数の発生ができない)
・p2で指定する値が上限であるが0〜p2の値までがランダムに発生(「rand param,1」とすると0か1が発生)
rnd同様0は入れないでください。エラーチェックしていませんので落ちてしまいます。
(例)文字を数える
;****************** 命令説明 *****************
;
; rand p1,p2
;
; p1=数値型変数 : 読み込むための変数
; p2=1〜2147483647 : 乱数の最大値を指定する
;
;*********************************************
#module "random"
#deffunc rand val,int
mref variable,16
mref max,1
dim r,10
dim tmp,10
dim num,4
randomize
r.0=max/1000000000
r.1=max/100000000\10
r.2=max/10000000\10
r.3=max/1000000\10
r.4=max/100000\10
r.5=max/10000\10
r.6=max/1000\10
r.7=max/100\10
r.8=max/10\10
r.9=max\10
repeat 10
if r.cnt!=0 : num.1=cnt : break ; 最大桁位置取得
loop
num.2=0 ; 最大桁用オーバーフロー防止フラグ
repeat 10
num=9-cnt
if num<num.1 : break ; 最大桁を超えたら終了
num.3=num+1
if num=num.1 {
if num.2=0 : r.num+
rnd tmp.cnt,r.num
continue
}
rnd tmp.cnt,10
if tmp.cnt>r.num : num.2=1
loop
variable=tmp.9*1000000000+(tmp.8*100000000)+(tmp.7*10000000)+(tmp.6*1000000)
variable+=(tmp.5*100000)+(tmp.4*10000)+(tmp.3*1000)+(tmp.2*100)+(tmp.1*10)+tmp
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
repeat 10,1
tmp=cnt
repeat 25
rand buf,54321
mes buf
wait 1
loop
pos tmp*65,0
loop
stop
19.文字列の中央寄せ
ここではありませんが本家掲示板にて質問があったものです。
文字列を中央に表示するにはどうしたらよいかというものです。
bmscr構造体を参照することで現在のフォントYサイズを取得できますので、
コレを利用してXサイズを割り出し中央に寄せてみようというものです。
この命令使用後のカレントポジションは中央よりのままですが、モジュール集のものはきちんと戻していますので…。
(例)中央寄せ
;************ 概要説明 *************
;
; center p1
;
; p1 = "strings"
;
;**********************************
#module center
#deffunc center str
mref string,32
mref bmscr,67
size=bmscr.32/2 ; フォントYサイズの2分の1がXサイズ?
strlen len,string
ichi=winx-(size*len)/2
pos ichi,csry : mes string
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
font "MS ゴシック",80,1
center "12345"
color 255
center "あいうえお"
stop
20.文字列の右寄せ
19と同じような方法で文字列を右寄せにするにはどうしたらよいでしょうか。
ほとんど同じやり方でできますね…。中央寄せと同じ所に書いてもよかったのですが…。
19で書き忘れていたのですが注意する点は「等幅フォントを使用しなければ指定位置に来ない」と言う点です。
(例)中央寄せ
;************ 概要説明 *************
;
; right p1
;
; p1 = "strings"
;
;**********************************
#module "right"
#deffunc right str
mref string,32
mref bmscr,67
size=bmscr.32/2 ; フォントYサイズの2分の1がXサイズ?
strlen len,string
ichi=winx-(size*len)
pos ichi,csry : mes string
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
font "MS ゴシック",90,1
right "ABCDEFG"
color 255
font "MS 明朝",30
right "9876543210"
stop
21.3桁区切りのコンマを入れてみる
何かの値段を表示する時「\10,000」のように3桁区切りでコンマを表示する時がありますね。
HSPで使われる数値もこの3桁区切りのコンマを入れたものに変えてみましょう。
(例)10→2
buf=1234567890
str buf
repeat
strlen len,buf
if len<3 : extraction=len : else : extraction=3
strmid tmp,buf,-1,extraction
if cnt : beam=""+tmp+","+beam : else : beam=tmp
if extraction!=3 : break
strmid buf,buf,0,len-3
loop
mes beam
stop
桁区切り(コンマ)を入れると数値型を文字列型に変換するため他の数値との計算ができなくなってしまいます。
取り除くだけですから、別に11のコンマだけを取り除く方法でも構いませんが・・・
簡単ですけどコンマを抜き数値にするやり方も書いておきます。
beam="123,456,789"
repeat
strlen len,beam
if len<3 : a=len : else : a=3
strmid tmp,beam,-1,a
if cnt : evaluation=""+tmp+""+evaluation : else : evaluation=tmp
if a!=3 : int evaluation : break
strmid beam,beam,0,len-4
loop
mes evaluation
stop
22.ウィンドウの端まで来たら自動で折り返す文字列表示モジュール
ココであった質問ではないですけど他所であった質問の答えとして作成しました。
mes命令ではウィンドウの右端まで来ても改行コードが来るまでそのまま続いて表示されてしまいます。
常に監視し、はみ出しそうになったら自動で左端まで来るようにしています。
この命令には「改行コード」を入れないでください。文字化けしてしまいます。
(例)文字列自動折り返し命令
;************ 概要説明 *************
;
; retmes "strings"
;
; "strings" : 表示する255文字までの文字列
;
;**********************************
#module "retmes"
#deffunc retmes str
mref string,32
mref bmscr,67
fsize=bmscr.32/2 ; 大体のXサイズ取得
strlen len,string
if len*fsize+csrx<winx : mes string : return
mx=csrx
my=csry
repeat len
peek tmp,string,cnt
if tmp>128&(tmp<160)|(tmp>223) : tmp=2 : fsize=fsize*2 : else : tmp=1
if mx+fsize>winx : mx=0 : my+=bmscr.32
strmid msg,string,cnt,tmp
pos mx,my : mes msg
mx+=fsize
if tmp=2 : fsize=fsize/2 : tmp=cnt+2 : continue tmp
loop
return
#global
pos 150,20
retmes "あabcいうxyzえお1234567890かきくけこabcdefghijklmnopqrstuvwxyzABC"
stop
23.タブ「\t」をHSPでも使ってみるモジュール
本家掲示板の過去ログを漁っていたらloadlib.dllを使ってタブを入れるものを発見しました。
私は22のTIPSを利用しててDLLを使わずにできないものかと思案し、実験してみました。
多分コレでいけてるかと思いますけど何かおかしいところがあればおっしゃってください。
一応タブのスペースは半角8文字分です。それと注意を1点。等幅フォントを使用するようにしてください。
22は書き換えてません(書き換え予定なし)がコチラは「\t」が使えると言うことで「\n」も使える様にしています。
またモジュール集に入れているretmesも改行OKとなっています。TIPSは重大なバグ以外書き換えませんので(^^;
(例)文字列自動折り返し命令
;************ 概要説明 *************
;
; tab "strings"
;
; "strings" : 表示する255文字までの文字列
;
;**********************************
#module "tab"
#deffunc tab str
mref string,32
mref bmscr,67
size=bmscr.32/2
size.1=size
strlen len,string
mx=csrx : mx.1=csrx
my=csry
temp+=""
repeat len
peek tmp,string,cnt
if tmp>128&(tmp<160)|(tmp>223) : tmp.1=2 : size=size*2 : else : tmp.1=1
if mx+size>winx : mx=0 : my+=bmscr.32
if tmp=9 : tmp.2=7-(tmp.3\8) : mx+=tmp.2*size : tmp.3+=tmp.2 : strmid msg,temp,0,tmp.2
if tmp=13 : tmp.1=2 : tmp.3=0 : size=size*2 : msg="\n"
if tmp!=9&(tmp!=13) : strmid msg,string,cnt,tmp.1
pos mx,my : mes msg
if tmp=13 : mx=mx.1 : my+=bmscr.32 : else : mx+=size
if tmp.1=2 :size=size.1 : tmp=cnt+2 : continue tmp
tmp.3+ ; 現在左から何文字目かを表わす
loop
return
#global
sdim buf,256
font "MS ゴシック",14
buf ="12345678123456781234567812345678\n--------------------------------\n"
buf+="abcde\tfg\nhij\tklmn\nopqrstu\tvwxyz\nAB\tCDEFG\nHIJKLMNOP\tQRSTU\tVWXYZ"
pos 150,200
tab buf
stop
24.半角の数値を全角にするモジュール
英語の小文字大文字化と大して変わらないのですが質問があったものですので載せておきます。
変換前は1バイトなのでpeekですが、変換後は2バイト文字ですのでwpokeを使います。
peekで取り出すと0は48,1は49,2は50…となっています。変換後は何に変えればよいのでしょう?
試しにwpeekで取り出してみると0は20354,1は20610,2は20866…と20354から256飛びに並んでいます。
ですので変換は「48-変換前*256+20354」としてやれば思い通りのものになるはずですよね。
コレを使えば英字の2バイト化等もできますね。
(例)文字列自動折り返し命令
;************ 概要説明 *************
;
; halftofull p1,p2
;
; p1 : 変換後の数値(2バイト)を入れる変数
; p2 : 変換前の数値(1バイト)の入った変数
;
;**********************************
#module "halftofull"
#deffunc halftofull val,val
mref p1,24
mref p2,17
tmp=p2
str tmp
strlen len,tmp
p1=""
repeat len
peek half,tmp,cnt
half=half-48*256+20354
wpoke p1,cnt*2,half
loop
return
#global
randomize
rnd r,100000
halftofull result,r
mes ""+r+"\n\n ↓\n\n"+result
stop
25.ポインタの変化でデータ高速並び替え
ある程度整列されているデータをある部分だけ別の部分のものと入れ替えるのはどのようにしますか?
説明が不明ですね…例えば1,2,3,4,5,6,7,8,9,0というデータを1,2,3,8,9,0,4,5,6,7といった並び替えの場合です。
こういった並び替えがよく使われるわけではありませんが、一応紹介しておこうと思います(^^;
対象データをひとつずつずらしていくのはコレくらいの数ならまだしも1000くらいになると効率がよくありません。
…ということでデータの位置をそのままで次に来るデータのポインタを変えてしまおうというものです。
本来の使い方とは少し…いや結構違っていますが、ここでいうポインタとは指し示すもの「データのアドレス」です。
まぁこの辺は元々のものと同じですけど…。
別の同じ数だけの配列を用意しそれを次のデータのある位置を指し示すものとします。
(例)50音順をあ→か→な→は→さ→た→ま→や→ら→わ行の順番に入れ替える
arrangement=50 ; 必要な配列数
sdim char,2,arrangement
dim pointer,arrangement
char.0 ="あ","い","う","え","お"
char.5 ="か","き","く","け","こ"
char.10="さ","し","す","せ","そ"
char.15="た","ち","つ","て","と"
char.20="な","に","ぬ","ね","の"
char.25="は","ひ","ふ","へ","ほ"
char.30="ま","み","む","め","も"
char.35="や","","ゆ","","よ"
char.40="ら","り","る","れ","ろ"
char.45="わ","","を","","ん"
repeat arrangement
if cnt+1<arrangement:pointer.cnt=cnt+1:else:pointer.cnt=-1 ; 次のデータのあるアドレス(要素番号)を入れる
loop
pointer.9=20 ; 「こ」の次は「な」へ
pointer.19=30 ; 「と」の次は「ま」へ
pointer.29=10 ; 「ほ」の次は「さ」へ
repeat
pos cnt\5*40,cnt/5*20 : mes char.tmp ; 並び替えたデータ表示
tmp=pointer.tmp
if tmp=-1 : break
loop
stop
26.32bit値以上の加減算モジュール
HSPでは4バイト(32bit)整数しか扱えませんので、扱える範囲は-2147483648〜2147483647となります。
ほとんどないでしょうけど2,147,483,647を超える数値の計算をするにはどうすればよいでしょう?
私は文字列を使い演算しています。ココでは足し算と引き算を文字列のみ記載してあります。
ただすべての加減算が出来るわけではなく正の整数の加減算のみとなっています。
マイナス値の入った文字列型の数値は扱えません。ご自分で改良してみてください。
(例)文字列自動折り返し命令
;************ 概要説明 *************
;
; add p1,p2 sub p1,p2
;
; p1 : 数値の入った文字列型変数1
; p2 : 数値の入った文字列型変数2
; refstr : 計算結果が返ります
;
;**********************************
#module "calc"
#deffunc add val,val
mref val1,24
mref val2,25
mref result,65
strlen len.1,val1
strlen len.2,val2
if len.1>len.2 : len=len.1 : else : len=len.2
value=""
repeat len,1
strmid tmp1,val1,len.1-cnt,1
strmid tmp2,val2,len.2-cnt,1
int tmp1
int tmp2
tmp=tmp1+tmp2+tmp3
str tmp,2
strmid tmp3,tmp,0,1
int tmp3
strmid tmp,tmp,1,1
value=tmp+""+value
loop
result=value
return
#deffunc sub val,val
mref val1,24
mref val2,25
mref result,65
strlen len.1,val1
strlen len.2,val2
if len.1>len.2:len=len.1:reversal=0:else:len=len.2:reversal=1:tmp=len.1:len.1=len.2:len.2=tmp
if reversal=1 : tmpstr1=val2 : tmpstr2=val1 : else : tmpstr1=val1 : tmpstr2=val2
value=""
repeat len,1
if len.1-cnt>=0 : strmid tmp1,tmpstr1,len.1-cnt,1 : else : tmp1=0
if len.2-cnt>=0 : strmid tmp2,tmpstr2,len.2-cnt,1 : else : tmp2=0
int tmp1
int tmp2
if tmp1-tmp2>=0&(tmp3=1) : tmp1-
if tmp1-tmp2<0 : tmp=10-tmp1-tmp2-tmp3 : tmp3=1 : else : tmp=tmp1-tmp2 : tmp3=0
str tmp
value=tmp+""+value
loop
if reversal=1 : value="-"+value
result=value
return
#global
add1="9876543210"
add2="12345678900"
sub1="54321"
sub2="12345678900"
add add1,add2 ; 加算サンプル
mes ""+add1+" + "+add2+" = "+refstr
sub sub1,sub2 ; 減算サンプル
mes ""+sub1+" - "+sub2+" = "+refstr
stop
27.後入れ先出し(LIFO)モジュール
スタック(stack)やキュー(queue)といった言葉を聴いたことはないでしょうか?
スタックとは下図のように後に入れたものを先に出す(先に入れたものを後に出す)データ構造の事を指します。

今覚えさせていることをちょっと待って新しいものを先に先に使いたいといった場合に利用できるかと思います(^^;
ちなみにLIFOはLastInFirstOutの略です。「先入れ後出し」よりFILOとも言うみたいですね。
(例)LIFO機構
;************ 概要説明 *************
;
; spush p1,p2
;
; p1=数値型配列変数 : データを格納しておく配列変数
; p2=数値型変数 : 代入する数値データ
;
;
; pop p1,p2
;
; p1=数値型配列変数 : データが格納されている配列変数
; p2=数値型変数 : 取り出したデータを代入する数値型変数
;
;**********************************
#module "stack"
#deffunc spush val,val
mref p1,48
mref p2,17
mref pval,1024
repeat pval.2-1,1
tmp1=pval.2-cnt-1
tmp2=pval.2-cnt
p1.tmp2=p1.tmp1
loop
p1.0=p2
return
#deffunc pop val,val
mref p1,48
mref p2,17
mref pval,1024
p2=p1
repeat pval.2
tmp1=cnt+1
if pval.2-1=cnt : p1.cnt=0 : else : p1.cnt=p1.tmp1
loop
return
#global
dim variable,10 ; データを格納する変数
tmp=50,100,150,200,250,300,400,500,1000,2000 ; 代入するデータ
mes "入れていく"
repeat 10
spush variable,tmp.cnt
mes tmp.cnt
loop
pos 200,0 : mes"取り出す"
repeat 10
pop variable,variable2
mes variable2
loop
stop
28.先入れ先出し(FIFO)モジュール
27でスタックを解説しましたので先に入れたものを先に出すキューのデータ構造(FIFO)も書いておきます。

詰め込むだけ詰め込めておいて、初めからデータを取り出していくことが必要な時にご利用ください。
取り出す「pop」命令は27のものとまったく同じです。
(例)FIFO
;************ 概要説明 *************
;
; qpush p1,p2
;
; p1=数値型配列変数 : データを格納しておく配列変数
; p2=数値型変数 : 代入する数値データ
;
;
; pop p1,p2
;
; p1=数値型配列変数 : データが格納されている配列変数
; p2=数値型変数 : 取り出したデータを代入する数値型変数
;
;**********************************
#module "stack"
#deffunc qpush val,val
mref p1,48
mref p2,17
mref pval,1024
repeat pval.2
if p1.cnt!=0 : continue
p1.cnt=p2
break
loop
return
#deffunc pop val,val
mref p1,48
mref p2,17
mref pval,1024
p2=p1
repeat pval.2
tmp1=cnt+1
if pval.2-1=cnt : p1.cnt=0 : else : p1.cnt=p1.tmp1
loop
return
#global
dim variable,10 ; データを格納する変数
tmp=50,100,150,200,250,300,400,500,1000,2000 ; 代入するデータ
mes "入れていく"
repeat 10
qpush variable,tmp.cnt
mes tmp.cnt
loop
pos 200,0 : mes"取り出す"
repeat 10
pop variable,variable2
mes variable2
loop
stop
29.標準命令だけでllmod.asのcharlower,charupperと同じことをする
07でやった英大小文字化と08の1,2バイト判別の応用として、
llmod.asにあった大小文字変換をするWinApiのCharLowerA,CharUpperAを標準命令でやってみました。
当然全角の英文字が混じっていてもいけるようにはなっています。
(例)WinAPIのCharLowerA(CharUpperA)を使わずに変数内の英字の大小文字を変換する
;************ 概要説明 *************
;
; lowerchar p1
;
; p1="strings" : 16進数
;
; upperchar p1
;
; p1="strings" : 16進数
;
;**********************************
#module "codechange"
#deffunc lowerchar val
mref p1,24
strlen len,p1
ichi=0
repeat len:wait 1
peek tmp,p1,ichi
if tmp>128&(tmp<160)|(tmp>223) {
wpeek tmp,p1,ichi
if tmp>=24706&(tmp<=31106) : tmp+=8448
wpoke p1,ichi,tmp
ichi+=2
continue ichi
}
if tmp>=65&(tmp<=91) : tmp+=32
poke p1,ichi,tmp
ichi+
loop
return
#deffunc upperchar val
mref p1,24
strlen len,p1
ichi=0
repeat len:wait 1
peek tmp,p1,ichi
if tmp>128&(tmp<160)|(tmp>223) {
wpeek tmp,p1,ichi
if tmp>=33154&(tmp<=39554) : tmp-=8448
wpoke p1,ichi,tmp
ichi+=2
continue ichi
}
if tmp>=97&(tmp<=122) : tmp-=32
poke p1,ichi,tmp
ichi+
loop
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
buf="aBcdEfghijkLmnopqrstuVWxyz"
upperchar buf
mes buf
buf="ABCDEFGhIJKLMnOpQrSTUVWxYz"
lowerchar buf
mes buf
stop
30.S-JISからEUCに変換するモジュール
Unicodeの相互変換をloadlib.dllを使わずに標準だけでするモジュールを考えていたのですが、
HSPver2.6がもうじき出て標準命令で使えてしまい(llmod.asは必要だが)意味がなくなるので中止しました(^^;
とりあえずEUCの相互変換はできないようですのでコレを取り入れようかと…。
知らない人用に説明するとEUCコードはUnixで標準使用されているコードで
ネット上のデータを取り込んだら改行コードが「↑」こんなコードだったと言う経験があった人は少なくないはず…。
これはWindowsの改行がCR+LF(キャリッジリターン+ラインフィード)であるのに対しUnixはLFだけで、
WindowsではLFだけのコードでは「↑」このような文字が表示されるわけです。
ですのでこんな文字の入ったデータはWindows用に直してやる必要があります。
ソレをするのが…あ、コレはソレの逆のWindows→Unixですね。(^^;
確認することのできるソフトをお持ちでない方は31で作成してください。
使い方はllmod.asのto_uni(from_uni)と同じようにしています(やり方のパクリともいう)。
第3パラメータに変換する文字列の長さを入れます。-1で全て変換、0で全変換に必要なバイト数がstatに返ります。
気をつけることがありますが説明が長くなりすぎましたので31に書いています。
(例)EUCに変換
;************ 概要説明 *************
;
; to_euc v1,v2,n3
;
; v1 : 変換したEUC文字列を入れる変数
; v2 : EUCに変換するS-JIS文字列が入った変数
; n3 : EUCに変換するS-JIS文字列の長さ
;
;**********************************
#module "codechange"
#deffunc to_euc val,val,int
mref p1,24
mref p2,25
mref p3,2
mref stt,64
if p3=0 { ; 長さを取得
ichi=0 : stt=0
repeat
peek code,p2,ichi
if code=0 : break ; EOF
if code>128 : stt+ : if code<177|(code>223) : ichi+=2 : stt+ : continue ichi ; 半角カナも2バイト
ichi+ : stt+
if code=13 : ichi+ : continue ichi ; CR+LF→LF
loop
}
if p3 {
if p3=-1 : strlen p3,p2
ichi=0 : stt=0
repeat p3
peek code,p2,ichi
if code=13 : poke p1,stt,10 : ichi+=2 : stt+ : continue ichi ; CR+LF→LF
if code>128 { ; 2バイト・半角カナ文字
if code>176&(code<224) { ; 半角カナは2バイトに
poke p1,stt,142 : poke p1,stt+1,code : stt+
} else {
peek code.1,p2,ichi+1 ; 2バイト文字の下位バイト取得
if code.1<159 {
if code<160 : poke p1,stt,code*2-97 : else : poke p1,stt,code*2-225
if code.1>127 : poke p1,stt+1,code.1+96 : else : poke p1,stt+1,code.1+97
} else {
if code<160 : poke p1,stt,code*2-96 : else : poke p1,stt,code*2-224
poke p1,stt+1,code.1+2
}
ichI+ : stt+
}} else { ; 1バイト文字
poke p1,stt,code
}
ichI+ : stt+
loop
}
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
sdim buf,32000,2
sdim file,256
dialog "txt",16,"S-JIS(ANSI)形式のファイル"
if stat=0 : end
file=refstr
bload file,buf
to_euc buf.1,buf,-1
dialog "txt",17,"保存するEUC形式のファイル名"
if stat=0 : end
file=refstr
strmid chk,file,-1,4 ; ファイル名の終端4文字が「.txt」かチェック
if chk!=".txt" : file+=".txt"
strlen len,buf.1
buf=buf.1 ; なぜか変数を移し変えなければS-JIS形式で保存される(謎
bsave file,buf,len
dialog"変換完了"
31.EUCからS-JISに変換するモジュール
Unicodeの相互変換モジュールを作成しようとしましたが中止しました(30参照)。
ココはUnixで使用されているEUCコードをWindowsので使用されているS-JIS(ANSI)コードに変えるモジュールです。
使い方はllmod.asのfrom_uni(to_uni)と同じようにしています。
第3パラメータに変換する文字列の長さを入れます。-1で全て変換、0で全変換に必要なバイト数がstatに返ります。
気をつけるというかわかりませんが…変換できない文字がいくつかあるようです
他のソフトでも試してみましたが同じ結果となりましたのでスクリプトが悪いわけではない…と思います(^^;
何個か挙げておきます「\]^_`abcdefg@ABUV」。
(例)S-JISに変換
;************ 概要説明 *************
;
; from_euc v1,v2,n3
;
; v1 : 変換したS-JIS文字列を入れる変数
; v2 : S-JISに変換するEUC文字列が入った変数
; n3 : S-JISに変換するEUC文字列の長さ
;
;**********************************
#module "codechange"
#deffunc from_euc val,val,int
mref p1,24
mref p2,25
mref p3,2
mref stt,64
if p3<1 { ; 長さを取得
ichi=0 : stt=0
repeat
peek code,p2,ichi
if code=0 : break ; EOF
if code>127 : ichi+=2 : if code=142 : stt+ : continue ichi : else : stt+=2 : continue ichi
if code<128 : ichi+ : stt+ : if code=10 : stt+
loop
}
if p3 {
if p3=-1 : p3=stt
ichi=0 : stt=0
repeat p3
peek code,p2,ichi
if code=10 : code.1=13 : poke p1,stt,code.1 : stt+ ; LF→CR+LF
if code>127 { ; 2バイト・半角カナ文字
peek code.1,p2,ichi+1 ; 2バイト・半角カナ文字の下位バイト取得
if code=142 : poke p1,stt,code.1 : ichi+=2 : stt+ : continue ; 半角カナ文字
if code\2=0 : code.1-=2
if code\2=1 : code.1-=97 : if code.1>125 : code.1+
if code<223 : code=code+1/2+48 : else : code=code+1/2+112
poke p1,stt,code
poke p1,stt+1,code.1
ichi+ : stt+
} else { ; 1バイト文字
poke p1,stt,code
}
ichi+ : stt+
loop
}
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
sdim buf,32000,2
sdim file,256
dialog "txt",16,"EUC形式のファイル"
if stat=0 : end
file=refstr
bload file,buf
from_euc buf.1,buf,-1
mesbox buf.1,640,480,5
stop
32.小数点以下があっても加算できるモジュール
以前本家掲示板であった質問に答えたものの修正版です。
いろいろと修正しましたがまだおかしい箇所がある場合報告いただければ幸いです。
ホントはもっと短く出来るのでしょうけど私の考えではこれ以上短く出来ませんでした(^^;
32bit演算は変わりませんので小数部用に桁を多く取れば当然整数部用の桁がその分減ります。
だいたい9桁(途中計算も含む)に収まるようにすればオーバーフローは大丈夫かと。
(例)加算
;************ 概要説明 *************
;
; fadd "s1","s2",n3
;
; s1 : 文字列型の数値1
; s2 : 文字列型の数値2
; n3 : 小数部に使用する桁数
;
; s1とs2の加算結果をシステム変数refstrに返します
;
;**********************************
#module "float"
#deffunc fadd str,str,int
mref p1,32
mref p2,33
mref p3,2
mref result,65
peek mflg.0,p1 : if mflg.0='-' : mflg.0=1 : else : mflg.0=0
peek mflg.1,p2 : if mflg.1='-' : mflg.1=1 : else : mflg.1=0
getstr tmp,p1,,'.' : int tmp : intn=tmp
fltn=0 : strlen len,p1
if len>strsize : getstr tmp,p1,strsize : strlen len.0,tmp : int tmp : fltn=tmp
getstr tmp,p2,,'.' : int tmp : intn.1=tmp
fltn.1=0 : strlen len.1,p2
if len.1>strsize : getstr tmp,p2,strsize : strlen len.1,tmp : int tmp : fltn.1=tmp
keta=1
repeat p3
keta=keta*10
loop
intn=intn*keta : intn.1=intn.1*keta
repeat 2
keta=1
if p3-len.cnt>=0 {
repeat p3-len.cnt
keta=keta*10
loop
if mflg.cnt : intn.cnt-=fltn.cnt*keta : else : intn.cnt+=fltn.cnt*keta
} else {
repeat len.cnt-p3
keta=keta*10
loop
if mflg.cnt : intn.cnt-=fltn.cnt/keta : else : intn.cnt+=fltn/keta
}
loop
tmp=intn+intn.1
str tmp
strlen len.2,tmp
if len.2>p3 : strmid intn,tmp,0,len.2-p3 : strmid fltn,tmp,-1,p3 : else : intn="0" : fltn=tmp
fltn="0000000000"+fltn : strmid fltn,fltn,-1,p3
strlen len.2,fltn : tmp=0
repeat len.2
peek tmp,fltn,len.2-cnt-1
if tmp!='0' : strmid fltn,fltn,0,len.2-cnt : break
loop
tmp=fltn : int tmp
if tmp=0 : result=intn : else : result=""+intn+"."+fltn
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
a="5" : b="7.324852"
fadd a,b,8
mes ""+a+" + "+b+" = "+refstr
a="52" : b="9"
fadd a,b,7
mes ""+a+" + "+b+" = "+refstr
a="4321610.03" : b="6000007"
fadd a,b,2
mes ""+a+" + "+b+" = "+refstr
stop
33.小数点以下があっても減算できるモジュール
32の引き算バージョンです。
ほぼ同じ処理ですが微妙に違いますので載せておきます。コレもおかしい点があれば報告くださいませ。
桁数は32と同じく9桁くらいまでにしましょう。32で書き忘れてましたがマイナス値の計算も出来るはずですので。
(例)減算
;************ 概要説明 *************
;
; fsub "s1","s2",n3
;
; s1 : 文字列型の数値1
; s2 : 文字列型の数値2
; n3 : 小数部に使用する桁数
;
; s1からs2の減算結果をシステム変数refstrに返します
;
;**********************************
#module "float"
#deffunc fsub str,str,int
mref p1,32
mref p2,33
mref p3,2
mref result,65
peek mflg.0,p1 : if mflg.0='-' : mflg.0=1 : else : mflg.0=0
peek mflg.1,p2 : if mflg.1='-' : mflg.1=1 : else : mflg.1=0
getstr tmp,p1,,'.' : int tmp : intn=tmp
fltn=0 : strlen len,p1
if len>strsize : getstr tmp,p1,strsize : strlen len.0,tmp : int tmp : fltn=tmp
getstr tmp,p2,,'.' : int tmp : intn.1=tmp
fltn.1=0 : strlen len.1,p2
if len.1>strsize : getstr tmp,p2,strsize : strlen len.1,tmp : int tmp : fltn.1=tmp
keta=1
repeat p3
keta=keta*10
loop
intn=intn*keta : intn.1=intn.1*keta
repeat 2
keta=1
if p3-len.cnt>=0 {
repeat p3-len.cnt
keta=keta*10
loop
if mflg.cnt : intn.cnt-=fltn.cnt*keta : else : intn.cnt+=fltn.cnt*keta
} else {
repeat len.cnt-p3
keta=keta*10
loop
if mflg.cnt : intn.cnt-=fltn.cnt/keta : else : intn.cnt+=fltn.cnt/keta
}
loop
tmp=intn-intn.1
str tmp
strlen len,tmp
if len>p3 : strmid intn,tmp,0,len-p3 : strmid fltn,tmp,-1,p3 : else : intn="0" : fltn=tmp
fltn="0000000000"+fltn : strmid fltn,fltn,-1,p3
strlen len,fltn : tmp=0
repeat len
peek tmp,fltn,len-cnt-1
if tmp!='0' : strmid fltn,fltn,0,len-cnt : break
loop
tmp=fltn : int tmp
if tmp=0 : result=intn : else : result=""+intn+"."+fltn
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
a="1.23" : b="0.000054321"
fsub a,b,9
mes ""+a+" - "+b+" = "+refstr
a="55" : b="6.004982"
fsub a,b,7
mes ""+a+" - "+b+" = "+refstr
a="149930" : b="821"
fsub a,b,3
mes ""+a+" - "+b+" = "+refstr
stop
34.小数点以下があっても乗算できるモジュール
一番オーバーフローしやすい演算と思われますので気をつけてください。
アルゴリズムの改良によりオーバーフローしにくくしました。処理行数も6行縮みました^^
また0〜1まで極小数値同士の演算も改良して0を除く塊が9桁以内の結果なら例え50桁でもいけるようにしました。
(例)乗算
;************ 概要説明 *************
;
; fmul "s1","s2",n3
;
; s1 : 文字列型の数値1
; s2 : 文字列型の数値2
; n3 : 小数部に使用する桁数
;
; s1とs2の乗算結果をシステム変数refstrに返します
;
;**********************************
#module "float"
#deffunc fmul str,str,int
mref p1,32
mref p2,33
mref p3,2
mref result,65
mflg=0
repeat 2
if cnt : result=p2 : else : result=p1
peek mflg.1,result
if mflg.1='-' : mflg+
getstr tmp,result,,'.'
int tmp
if tmp<0 : intn.cnt=tmp*-1 : else : intn.cnt=tmp
strlen len.2,result
if len.2>strsize : strmid tmp,result,strsize,p3 : else : tmp=""
strlen len.2,tmp
repeat len.2
peek keta,tmp,len.2-cnt-1
if keta!='0' : strmid tmp,tmp,0,len.2-cnt : break
loop
keta=tmp
int keta
if keta=0 : tmp=""
strlen len.cnt,tmp
if cnt : len+len.1
tmp=""+intn.cnt+""+tmp
int tmp
intn.cnt=tmp
loop
tmp=intn*intn.1
str tmp
strlen len.2,tmp
if len.2-len>0 : strmid intn,tmp,0,len.2-len : else : repeat len : tmp="0"+tmp : loop : if mflg\2 : intn="-0" : else : intn="0"
strmid fltn,tmp,-1,len
strmid fltn,fltn,0,p3
tmp=fltn : int tmp
if tmp=0 : result=intn : else : result=""+intn+"."+fltn
int intn
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
a="0.0000045204" : b="-0.00000000000133"
fmul a,b,25
mes ""+a+" × "+b+" = "+refstr
a="-7.02" : b="0.004982"
fmul a,b,9
mes ""+a+" × "+b+" = "+refstr
a="110730.3" : b="12.05"
fmul a,b,3
mes ""+a+" × "+b+" = "+refstr
stop
35.小数点以下があっても除算できるモジュール
小数点以下があってもOKな割り算モジュールは整数同士の演算から小数が出る唯一の演算とと言う点から
他の加減乗算モジュールよりかは需要があるのではないでしょうか。
今回は初めの演算する数値の桁数、途中の計算での合計桁数が多すぎなければ
答えとなる数値の桁数が15桁であろうが30桁でも例え1000桁でもいける…はずです(自信なし
(例)除算
;************ 概要説明 *************
;
; fdiv "s1","s2",n3
;
; s1 : 文字列型の数値1
; s2 : 文字列型の数値2
; n3 : 小数部に使用する桁数
;
; s1とs2の除算結果をシステム変数refstrに返します
;
;**********************************
#module "float"
#deffunc fdiv str,str,int
mref p1,32
mref p2,33
mref p3,2
mref result,65
mflg=0
repeat 2
if cnt : result=p2 : else : result=p1
peek mflg.1,result
if mflg.1='-' : mflg+
getstr tmp,result,,'.'
int tmp
if tmp<0 : intn.cnt=tmp*-1 : else : intn.cnt=tmp
strlen len.2,result
if len.2>strsize : strmid tmp,result,strsize,p3 : else : tmp=""
strlen len.2,tmp
repeat len.2
peek keta,tmp,len.2-cnt-1
if keta!='0' : strmid tmp,tmp,0,len.2-cnt : break
loop
keta=tmp
int keta
if keta=0 : tmp=""
strlen len.cnt,tmp
if cnt : len-len.1
tmp=""+intn.cnt+""+tmp
int tmp
intn.cnt=tmp
loop
if intn.1=0 : result="error" : return
if len<0 : repeat len*-1 : intn=intn*10 : loop : len=0
keta=intn/intn.1
tmp=""+keta
if keta<0 : intn=intn*-1
strlen len.1,tmp
strmid result,tmp,0,len.1-len
if mflg\2 : result="-"+result
if len|(intn\intn.1) : result+="."
getstr tmp,tmp,len.1-len,''
result+=tmp
repeat p3
intn=intn\intn.1*10
if intn=0 : break
keta=intn/intn.1
result+=""+keta
loop
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
a="-9" : b="4"
fdiv a,b,3
mes ""+a+" ÷ "+b+" = "+refstr
a="3141.59" : b="2.65358"
fdiv a,b,16
mes ""+a+" ÷ "+b+" = "+refstr
a="18.0000600" : b="-0.130"
fdiv a,b,8
mes ""+a+" ÷ "+b+" = "+refstr
stop
36.文章をゆっくり端から表示するモジュール
試してないので真相は知らないのですが、hspdx.dllを使用してDirectXモードになっている時に
text命令は使えないというのを昔どこかでみたような記憶があります。
また、半角カナの入り混じった文章を表示させるときに文字化けが発生してしまうバグが存在します。
こういったときにご利用ください。
少々面倒ですが、コレを応用させれば後ろから1文字ずつ表示させることも出来ますよ。
(例)全角・半角の入り混じった文章を表示させる
;************ 概要説明 *************
;
; msg "s1",n2
;
; s1 : 文字列・文字列型の変数
; n2 : 速度(注.text命令の速度とは異なります)
;
;**********************************
#module "string"
#deffunc msg str,int
mref txt,32
mref speed,2
mref bmscr,67
fsize=bmscr.32/2
strlen len,txt
posx=csrx : posy=csry
sdim moji,4
repeat len
peek tmp,txt,cnt
poke moji,0,tmp
if tmp>128&(tmp<160)|(tmp>223) {
peek tmp,txt,cnt+1
poke moji,1,tmp
num=2
} else {
poke moji,1,0
num=1
}
pos posx,posy : mes moji
posx+=fsize*num
if speed>0 : wait speed
continue cnt+num
loop
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
pos 30,200
sdim buf,128
buf="アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン"
msg buf,5
stop
37.グラデーション文字2(モジュール版)
随分前に画像・音楽編の02にグラデーション文字を表示するTIPSを作成しました。
白い背景の時には使えたのですが、別の色で塗りつぶされていたり、画像が貼り付けられていた場合はダメでした。
また、一時ウィンドウ(バッファ)も2つ(計3画面)用意しなければ出来ないというものでした。
今回は36の1文字ずつ表示させるものの別の使い方として、
背景が何であろうと使えるようにしたものです。それも1画面ONLYとモジュールで。
応用が利くようになったのですが、色の変化が最低でも1文字単位なのであまりきれいに変わってくれません。
(例)グラデーション文章を表示させる
;************ 概要説明 *************
;
; colful "s1",n2,n3
;
; s1 : 文字列・文字列型の変数
; n2 : 開始色(「赤輝度<<16」+「緑輝度<<8」+「青輝度」の形式で指定します)
; n3 : 終了色(「赤輝度<<16」+「緑輝度<<8」+「青輝度」の形式で指定します)
;
;**********************************
#module "string"
#deffunc colful str,int,int
mref txt,32
mref start,1
mref finish,2
mref bmscr,67
sdim moji,4
fsize=bmscr.32/2
strlen len,txt
len.1=len-1
posx=csrx : posy=csry
red.0=start>>16&$ff : green.0=start>>8&$ff : blue.0=start&$ff ; 開始色
red.1=finish>>16&$ff : green.1=finish>>8&$ff : blue.1=finish&$ff ; 終了色
red.2=red.1-red.0/len.1 : green.2=green.1-green.0/len.1 : blue.2=blue.1-blue.0/len.1 ; 1文字ごとの増分値
color red,green,blue
repeat len
peek tmp,txt,cnt
poke moji,0,tmp
if tmp>128&(tmp<160)|(tmp>223) {
peek tmp,txt,cnt+1
poke moji,1,tmp
num=2
} else {
poke moji,1,0
num=1
}
pos posx,posy : mes moji
posx+=fsize*num
color red.2*cnt+red,green.2*cnt+green,blue.2*cnt+blue
if speed>0 : wait speed
continue cnt+num
loop
return
#global ; ***** ここまでがモジュール ここから下がサンプル *****
sdim buf,56
sdim name,20
picload "hsp2ttl.jpg"
buf="きれいなグラデーションがかかっているのかな?"
name="byアルティメット"
font "",25,1
col.0=255<<16 : col.1=255<<8
pos 50,50 : colful buf,col.0,col.1
col.0=0 : col.1=255<<16+(255<<8)+255
pos 200,120 : colful name,col.0,col.1
stop