ソースコードすっきり!

ソースコードの最適化

さて、今からしばらく実行結果が変わらない地味なソースコードの手直し手していきます。正直今回のプログラムに限って言えばそれほど重要な事ではありません。というのも、プログラム自体が簡単で小さく、また速さも要求されないからです。ではなぜこんなことをするのか?目的は二つあります。

一つは、ソースコード自体を「短く解り易く」するためです。大きなプログラムや複雑なプログラムを作っている時、途中でどこがどんな役割をしているのかが解らなくなってしまったらお終いです。また、あとからプログラムを修正したい、改造したいと思った時、大抵ソースコードの意味なんて忘れてしまっているものです。その時、ソースコードがごちゃごちゃしていると解読が困難で、最悪1から作り直し、なんてことになりかねません。

もう一つは、プログラムを「小さく速く」するためです。プログラムのサイズが大きいよりは小さい方が好まれますし、その方が実行する時も軽くなります。また、インターネット上で公開する時にも、サーバーの容量を考えると小さい方が良いです。計算やデータの管理をメインとするアプリ、シューティングゲームなどのある程度速さの求められるゲームなどでは、速さが重要になってきます。そうでなくでも、遅いより速い方がストレスなく使うことが出来ます。

repeat~loop

さて、まずはループの部分をもっと見やすくすっきりさせます。今まではラベルとgotoでループを作り、反復した回数を変数で数えていましたが、実はそれを一気に肩代わりしてくれる便利な命令があります。repeatloopです。

まずは例によって完成品を。

	;画像の準備
	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引数に繰り返す回数を数値で指定します。省略すると無限ループになります。そんな感じで、前回までは*maingoto *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'を引くという単純な計算で、自動的に時刻がきちんと表示されます。

規則性を利用します。

これで一応、デジタル時計としては完成です。が、このままだとただの時計です。なんだか寂しいので、タイマー機能をつけちゃいましょう。そうすればカップラーメン作ったりするときくらいには役に立つでしょう。

コラム:文字コード色々

今回は何も気にせず文字コードというものを使いましたが、実は文字コードにもさまざまな種類があります。どの数値がどの文字に対応しているか、というのが種類によって違うのです。

ASCIIコード

Shift-JIS

EUC-JP

Unicode

目次へ戻る