12
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

HSP3で湯婆婆を実装してみる

Last updated at Posted at 2020-11-10

はじめに

原作者様: Javaで湯婆婆を実装してみる - Qiita

各言語版の実装が流行していますが、もう列挙できないほど広まってしまったのでこちらをどうぞ。
【毎日自動更新】湯婆婆 LGTMランキング! - Qiita

もう自分の使ったことのある言語は出尽くしてしまった…かと思ったのですが、HSP (Hot Soup Processor) は誰もやっていないっぽい!
ということで、HSP3で書いてみました。このネタをやりたいがためにHSP3.51をインストールしました。

15年くらい触っていなかったこともあり(当時はHSP2.55とか2.6とか…)、言語仕様が変わっていたり単純に忘れていたりしたので、意外に苦労しました。

コード

QiitaはHSPのシンタックスハイライトに対応していないらしい。。。

yubaba.hsp
#uselib "kernel32.dll"
#cfunc lstrlenW "lstrlenW" var ; Windows API

	randomize                  ; 乱数シードの初期化
	screen 0, 1000, 400        ; ウィンドウサイズの指定
	font "", 24                ; フォントの指定
	objmode 2                  ; コントロールのフォントも変更する
	mes "契約書だよ。そこに名前を書きな。"
	name = ""
	input name, 500, 30, 30    ; テキストボックス作成
	objsize 100, 30
	button "送信", *clicked    ; ボタン作成
	stop
*clicked
	sdim nameUnicode, 64       ; 文字列バッファを初期化
	cnvstow nameUnicode, name  ; マルチバイト文字列操作のためUnicodeに変換
	mes "フン。" + name + "というのかい。贅沢な名だねぇ。"
	newNameIndex = rnd(lstrlenW(nameUnicode))
	sdim newNameUnicode        ; Unicodeベースで1文字取り出す
	memcpy newNameUnicode, nameUnicode, 2, 0, newNameIndex * 2
	newName = cnvwtos(newNameUnicode) ; 通常の文字列に変換
	mes "今からお前の名前は" + newName + "だ。いいかい、" + newName + "だよ。分かったら返事をするんだ、" + newName + "!!"

実行例

テキストボックスに名前を入れ、「送信」ボタンを押すと、湯婆婆が答えてくれます。

image.png

コードの注意点(特にマルチバイト関連)

令和にもなればHSPでもUnicode (UTF-16) なんて当たり前に使えるようになっていると思っていましたが、割と面倒でした。
マルチバイト文字を考慮して文字列の切り出しを行うために、目的の文字列をまずUnicodeに変換します。

	cnvstow nameUnicode, name  ; 文字数操作のためUnicodeに変換

続いて、入力された名前の文字数をカウントして、取ってくる文字のインデックスを選択します。文字数カウントの部分でWindows APIを使っています。

	newNameIndex = rnd(lstrlenW(nameUnicode))

関連: lstrlenW function (winbase.h) - Win32 apps | Microsoft Docs

lstrlenW を使うために、スクリプトの先頭で以下のように宣言しています。

#uselib "kernel32.dll"
#cfunc lstrlenW "lstrlenW" var

関連: HSP3 プログラミング・マニュアル 「4.9. API呼び出し」

そして選んだインデックスで1文字を取ります。Unicodeは1文字あたり2バイトなので、文字数と転送元のインデックスを2倍します。

	memcpy newNameUnicode, nameUnicode, 2, 0, newNameIndex * 2

ここで strmid を使いたくなるのですが、Unicode文字列では終端以外にNULL文字 (C言語でいうところの \0) が現れる場合があるため、正しく動作しません。

最後に、取ってきた文字を通常の文字列に戻します。

	newName = cnvwtos(newNameUnicode) ; 通常の文字列に変換

お約束

名前を入れないで送信すると落ちます。原作リスペクト
image.png

12
8
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?