UWSCのStarsをUWSCにとかせる

UWSC公式掲示板に懐かしいゲームが再びあったので、今度はAIもどきにしてみた。



Stars - 懐かしいゲーム

Linersさん作のスクリプトです。

print acw(GETID(GET_LOGPRINT_WIN),,,240, 400) + "   ★☆★ STARS ★☆★<#cr>"
x = random(100) +1
for i = 1 to 7
  g = input("あなたの予想は?")
  if g = x then break else print format(g, 3) + ":" + format("☆", 7 - logn(2, abs(x - g))) + "<#cr> あと" + (7-i) + "回" 
next
if i = 8 then msgbox("残念!! 答えは " + x + " でした。") else msgbox("★☆お見事☆★ " + i + "回 で正解です。")

AIもどき

Starsのスクリプトが「Stars.uws」として

OPTION EXPLICIT

CONST TRY_NUM = 100
CONST NUM_MAX = 100
CONST NUM_MIN = 1
CONST SCRIPT_NAME = "Stars.uws"

EXEC(GET_UWSC_DIR + "\uwsc.exe " + GET_CUR_DIR + "\" + SCRIPT_NAME)
DIM widLog = GETID("UWSC - " + SCRIPT_NAME, "TUScript.UnicodeClass")

DIM res = FALSE, i, wid, num = NUM_MIN, log, a[3], pre = 0, j, widRes, b = 0
HASHTBL rs
FOR i = 1 TO 7
	wid = GETID("UWSC - " + SCRIPT_NAME, "TFInpBox.UnicodeClass")
	SetNum(wid, num)
	log = SPLIT(GETSTR(widLog, 1), "<#CR>")
	widRes = GETID("UWSC - " + SCRIPT_NAME, "TFmsgDlg.UnicodeClass")
	IFB widRes > -1 THEN
		res = (pre = 0 OR pre = LENGTH(log))
		BREAK
	ENDIF
	pre = LENGTH(log)
	IF pre > 3 THEN log = log[pre - 3] ELSE log = ""
	rs[num] = LENGTH(log) - LENGTH(REPLACE(log, "☆", "")) + 1
	num = GetNextNum(num, a, rs, i)
NEXT
IF res THEN MSGBOX("Clear! " + i + " : " + num) ELSE MSGBOX("Fail...")


FUNCTION SetNum(wid, num)
	RESULT = FALSE
	DIM c = 1
	WHILE GETSTR(wid) <> num AND c < TRY_NUM
		SLEEP(0.1)
		SENDSTR(wid, num, 1, TRUE)
		c = c + 1
	WEND
	WHILE !CLKITEM(wid, "OK") AND c < TRY_NUM
		SLEEP(0.1)
		c = c + 1
	WEND
	SLEEP(0.1)
	RESULT = TRUE
FEND

FUNCTION GetNextNum(num, var a[], var rs[], i)
	DIM j, b
	IFB i = 1 THEN
		num = NUM_MAX
		a[2] = 0
	ELSE
		IFB i = 2 THEN
			a[3] = 1
			IFB rs[a[2], HASH_VAL] > rs[num] THEN
				a[2] = 1; a[3] = 0
			ENDIF
			b = 1
			j = 1
		ELSE
			FOR j = 0 TO 2
				a[j] = a[j + 1]
			NEXT
			a[3] = i - 1
			b = 0
			j = 1
			IFB rs[a[2], HASH_VAL] > rs[num] THEN
				a[3] = a[2]; a[2] = a[1]
				IFB rs[a[1], HASH_VAL] > rs[num] THEN
					j = -1
					a[1] = i - 1
				ELSEIF rs[a[1], HASH_VAL] = rs[num] THEN
					b = 1
					IFB rs[a[3], HASH_KEY] > rs[a[1], HASH_KEY] THEN
						IFB rs[a[1], HASH_KEY] > num THEN
							j = -1
							a[1] = i - 1
						ELSE
							a[2] = i - 1
						ENDIF
					ELSE
						IFB rs[a[1], HASH_KEY] > num THEN
							a[2] = i - 1
						ELSE
							j = -1
							a[1] = i - 1
						ENDIF
					ENDIF
				ELSE
					a[2] = i - 1
				ENDIF
			ELSEIF rs[a[2], HASH_VAL] = rs[num] THEN
				b = 1
				IFB rs[a[2], HASH_KEY] > rs[a[1], HASH_KEY] THEN
					IFB rs[a[1], HASH_KEY] > num THEN
						a[3] = a[2]; a[2] = i - 1
					ENDIF
				ELSE
					IFB rs[a[1], HASH_KEY] < num THEN
						a[3] = a[2]; a[2] = i - 1
					ENDIF
				ENDIF
			ENDIF
		ENDIF
		num = INT(rs[a[3], HASH_KEY] - (rs[a[3], HASH_KEY] - rs[a[2], HASH_KEY]) / (rs[a[3], HASH_VAL] + rs[a[2], HASH_VAL] + b) * (rs[a[2], HASH_VAL] + b) * j + 0.5)
		IF num < NUM_MIN THEN num = NUM_MIN + (NUM_MIN - num)
		IF num > NUM_MAX THEN num = NUM_MAX - (num - NUM_MAX)
		WHILE rs[num, HASH_EXISTS]
			num = num + j
		WEND
	ENDIF
	RESULT = num
FEND

FUNCTION GetNextNumCheat(num, var a[], var rs[], i)
	RESULT = num + INT(POWER(2, 7 - rs[num])) + 1
FEND

こっちのスクリプトを起動すると、同じディレクトリーにあるStars.uwsを起動して、勝手にときだします。
GetNextNumが番号を推測する関数ですが、元のスクリプトのロジックは入っていません。
学習もしないため、正答率は75%程度です。
☆の数の最大数がわかるなら、もう少しマシにできるかな。
もちろん、元のスクリプトのロジックを組み込んだGetNextNumCheatにすると、正答率は100%です。

今回の目的

「完成された人工知能はもはや人工知能ではない。それは、、、システム」
それは誰の言葉だったか忘れましたが、そこを目指したものです。
ようは、エキスパートシステム(モデルは私ですが)。
ちゃんと学習型人工知能を作成すれば、すぐに100%になると思いますが、
それを書くのは面倒だったもので。