さて、今からしばらく実行結果が変わらない地味なソースコードの手直し手していきます。正直今回のプログラムに限って言えばそれほど重要な事ではありません。というのも、プログラム自体が簡単で小さく、また速さも要求されないからです。ではなぜこんなことをするのか?目的は二つあります。
一つは、ソースコード自体を「短く解り易く」するためです。大きなプログラムや複雑なプログラムを作っている時、途中でどこがどんな役割をしているのかが解らなくなってしまったらお終いです。また、あとからプログラムを修正したい、改造したいと思った時、大抵ソースコードの意味なんて忘れてしまっているものです。その時、ソースコードがごちゃごちゃしていると解読が困難で、最悪1から作り直し、なんてことになりかねません。
もう一つは、プログラムを「小さく速く」するためです。プログラムのサイズが大きいよりは小さい方が好まれますし、その方が実行する時も軽くなります。また、インターネット上で公開する時にも、サーバーの容量を考えると小さい方が良いです。計算やデータの管理をメインとするアプリ、シューティングゲームなどのある程度速さの求められるゲームなどでは、速さが重要になってきます。そうでなくでも、遅いより速い方がストレスなく使うことが出来ます。
さて、まずはループの部分をもっと見やすくすっきりさせます。今まではラベルとgotoでループを作り、反復した回数を変数で数えていましたが、実はそれを一気に肩代わりしてくれる便利な命令があります。repeat
とloop
です。
まずは例によって完成品を。
;画像の準備
buffer 1
picload "number.png"
gsel 0 ;操作先ウインドウを戻しておく
gmode 2,16,32 ;ずっと同じ設定なのでここでセット
;ウインドウの準備
title "clock"
width 16*12,32
;変数の準備
dim time,11
;★この際なので
repeat
;時刻の取得
hor=gettime(4)
min=gettime(5)
sec=gettime(6)
if hor<12 { time(0)=12 }else{ time(0)=14 };AかPか
if hor>12 { hor-=12 };12より大きかったら調整
time(1)=13,11,(hor/10),(hor\10),10,(min/10),(min\10),10,(sec/10),(sec\10)
;時刻更新の準備
redraw 0
color 185,122,87
boxf
;★時刻を画像表示
repeat 11
pos 16*cnt,0 : gcopy 1,16*time(cnt),0
loop
redraw 1
;繰り返し
await 1000
loop
repeat~loop
その間に挟まれた部分が繰り返し実行されます。repeat
の第1引数に繰り返す回数を数値で指定します。省略すると無限ループになります。そんな感じで、前回までは*main
とgoto *main
で挟んで無限ループにしていた部分も、同じものを使ってみました。
また、何回目のループなのかが「システム変数」cnt
に代入されています。システム変数というのは、HSPが何らかの重要な情報を代入している変数で、中身を使う事は出来ますが、プログラムから代入する事はできません。今回のように二重のループになっている時は、その部分を挟んでいるrepeat~loop
の回数が入っています。なので、外側のループの回数も一番内側で使いたい場合は、変数に一度代入する必要があります。また、cntは0から値が始まります。1周目が0、2周目が1、という具合です。
以下は、九九の表を表示するサンプルです。
repeat 9
c=cnt
repeat 9
pos cnt*24,c*24
mes (c+1)*(cnt+1)
loop
loop
一応、これで少しはスッキリしました。今回は、もっと簡単にしてみましょう。そのために使うのが「文字コード」です。
コンピュータは電子回路ですから、本来数値しか扱うことが出来ません。ではどうやって文字列を扱っているかと言いますと、文字に1つ1つ数値を対応させて管理しています。つまり、コンピュータからしてみると、文字列も数値の羅列も同じものに見える、という事です。この文章も、コンピュータには数値の連続にしか見えていません。
この文字に対応した数値の事を「文字コード」と呼びます。文字コードにはいろいろと種類があるのですが、それに関してはコラムを参照してください。半角文字には0x00から0xffまでの数値、全角文字には0x0000から0xffffまでの数値が割り当てられているのが普通です。ちなみに、0x00~0xffの数値は8ビット(2進数で8桁)で表現できるます。そこで、この半角1文字を表す8ビットをまとめて「1バイト」と言います。1キロバイトは1024バイト、1メガバイトは1024キロバイト、1ギガバイトは1024メガバイト、1テラバイトは1024ギガバイトです。
この表はHSPで作成したものです(charcode.hsp)。上と左の赤い数値を足すと、その文字の文字コードになります。例えばAは0x41=65です。
ここで注目すべきは、一応の規則性があるという事です。abc…zyxは順番に並んでいますし、012…789もちゃんと並んでいます。つまり、数字の文字コードから0の文字コードを引けば、数字を数値に直すことが出来るのです。そして嬉しい事に、:もすぐ隣に並んでいます。
そんなわけで、これを利用してソースコードを解り易く整理してみましょう。文字列から文字コードを知るためにはpeek
関数を利用します。
;画像の準備
buffer 1
picload "number.png"
gsel 0 ;操作先ウインドウを戻しておく
gmode 2,16,32 ;ずっと同じ設定なのでここでセット
;ウインドウの準備
title "clock"
width 16*12,32
;この際なので
repeat
;★時刻の取得
hor=gettime(4)
if hor<12 { time="<" }else{ time(0)=">" };★<はA、>はP
if hor>12 { hor-=12 };12より大きかったら調整
time+=strf("=;%02d:%02d:%02d",hor,gettime(5),gettime(6))
;timeが"<=;11:30:23"のような文字列になる
;時刻更新の準備
redraw 0
color 185,122,87
boxf
;★時刻を画像表示
repeat 11
pos 16*cnt,0 : gcopy 1,16*(peek(time,cnt)-'0'),0
loop
redraw 1
await 1000
loop
補足を一つだけ。'
で挟んだ半角文字は、その文字の文字コードを表します。1は数値の1、"1"は文字の1、'1'は1の文字コードです。
配列変数を使わず、また\(¥)などの計算も無いのでずいぶんスッキリしています。前回のページで完成したものと比べると、32行から20行への短縮です。計算量も減っているはずです。
仕組みはこうです。まず、表示する時刻を表す文字列を組みます。そして、その文字列からpeekで一文字ずつ文字を取り出し、その文字コードから'0'を引きます(peek(time,cnt)-'0'
)。これに16をかけて、画像のコピー元とします。これで0から9までの数字はOKです。問題は:AmPです。画像は「0123456789: AmP」の並びです。文字コードの並びは「0123456789:;<=>」となっています。そこで、文字列を組む時に、「"Pm 11:24:12"」とする代わりに「">=;11:24:12"」とします。すると、'0'を引くという単純な計算で、自動的に時刻がきちんと表示されます。
repeat
~loop
が便利これで一応、デジタル時計としては完成です。が、このままだとただの時計です。なんだか寂しいので、タイマー機能をつけちゃいましょう。そうすればカップラーメン作ったりするときくらいには役に立つでしょう。
今回は何も気にせず文字コードというものを使いましたが、実は文字コードにもさまざまな種類があります。どの数値がどの文字に対応しているか、というのが種類によって違うのです。
ASCIIコード
Shift-JIS
EUC-JP
Unicode