UWSCで安直なバトルゲーム
遺伝的アルゴリズム、ってあるじゃない?
あれ、やってみたいなー、と思いまして。
お題を何にしようか考えて、、、バトルゲームはどうだろう、と。
適当にパラメーターと行動パターンがあるもの、ということで、作成してみた。
ルール
攻撃力・防御力・回避力・体力がそれぞれ1以上で、合計値が1000になるように割り振る。
コマンド制で、「攻撃」「防御」「回避攻撃」を選ぶ。
攻撃同士は、相討ち。両方ダメージ。
攻撃と防御は、攻撃を受けるも、防御力重視のダメージで済む。
攻撃と回避攻撃は、回避攻撃側の攻撃のみ通る。
防御同士、回避攻撃同士は、何もなし。
防御と回避攻撃は、回避攻撃側が防御力によるカウンター攻撃を受ける。
攻撃・防御・回避攻撃は、みすくみの関係ですね。
回避力の高い方が先制。同じはランダム。
回避力が高いと確率で攻撃がスカる。
相手の体力を0にしたら勝ち。
スクリプト
battle.uws
OPTION EXPLICIT IFB GET_UWSC_NAME = "battle.uws" THEN DIM i, gen[1] FOR i = 0 TO 1 SELECT SLCTBOX(SLCT_NUM, 0, "P" + i + "を選択してください", "弱い", "強い", "遺伝子入力", "Manual") CASE 0 SELECT SLCTBOX(SLCT_NUM, 0, "P" + i + "を選択してください", "剛腕", "固い", "早い", "タフ") CASE 0 gen[i] = "PgrLoTuywUeBt6uYPu1GR6fuwLU7mumFbaFmGDNQ5jUC5QbE7VpcMt451E4iblGtcrYExByqCy8j" CASE 1 gen[i] = "7l33KS4QINEBl7uG0Gx3YSpCz9Mw6zpdEWGthmNvBLa6yhvqLlMCaGPAs0BEBsYOzNVKXxm1aeLT" CASE 2 gen[i] = "vcZp2eQkZb6zxVYz7VUZ00lFNadlx2rTMmMkk4GEPDH2JvSmr9owOyrOS4DOaixcdJBPY9TrhNo8" CASE 3 gen[i] = "Plp0Cx7ywUeBt6uYPhP5uT6UvFatClVr5b200DggjCQZ9dIs79Hu2jDBnjTablGtcrYExByqCy8j" DEFAULT gen[i] = Battle.CreateGen() SELEND CASE 1 SELECT SLCTBOX(SLCT_NUM, 0, "P" + i + "を選択してください", "剛腕", "固い", "早い", "タフ") CASE 0 gen[i] = "6DKHh3AuMuWoC1fN3ZUU03uzDsrYgW63ZyTJhd4pAX071dducqBmWPqyIw6syGT4bTSQqU3Ba4h0" CASE 1 gen[i] = "Fz4bW2oYRRslRTJ7uNZNUuTyFW4ZaSJi88RHrNVowpVkdAgJuhtRHehI7h2DWUEKdOR4YHXuPkK1" CASE 2 gen[i] = "KrBzjRf85CMkstSHF3ygMGHdpvH0htxuaBsWhW6q6KlFQkeoi9BhWw5ugqUiMHXBlHPngjqaPatW" CASE 3 gen[i] = "2cMvqnLufGTu0CJZjfl3b86A7GqsSj0DgUIz1sOwvI3qRzi5yvoTB5dRKkKrzkJU7N55OiOVJEd4" DEFAULT gen[i] = "CBLxg2IBdrMkstSHF3ygMGHdpvqsSj0DgUIz1sOw6KlFQkeoi9BhFkxzvIvOdXU2fttJi1E5bwVx" SELEND CASE 2 gen[i] = INPUT("アルファベット大文字・小文字、数字を76文字まで入力してください", Battle.CreateGen()) CASE 3 gen[i] = "PLAYER" DEFAULT gen[i] = Battle.CreateGen() SELEND NEXT Battle.Do(gen) ENDIF MODULE Battle PUBLIC LogLevel = 5 PUBLIC HASHTBL _adicn = HASH_CASECARE PROCEDURE Log(msg, level=4) IF level < LogLevel THEN PRINT msg FEND PROCEDURE Battle DIM i FOR i = 0 TO 9 _adicn["" + i] = i NEXT FOR i = 0 TO 25 _adicn[CHR(ASC("a") + i)] = i + 10 NEXT FOR i = 0 TO 25 _adicn[CHR(ASC("A") + i)] = i + 36 NEXT FEND FUNCTION Do(gen[], n=1) // 遺伝子を展開 DIM atk[1], def[1], eva[1], hp[1], hpo[1], ran[1][2], pat[1], i, j, t[3], r[1] FOR i = 0 TO 1 IFB gen[i] = "PLAYER" THEN hpo[i] = 0 WHILE hpo[i] = 0 atk[i] = INT(VAL(INPUT("攻撃力を入力してください。<#CR><#CR>攻撃力+防御力+回避力+体力=1000になるようにしてください", 250))) def[i] = INT(VAL(INPUT("防御力を入力してください。", (1000-atk[i])/3))) eva[i] = INT(VAL(INPUT("回避力を入力してください。", (1000-atk[i]-def[i])/2))) hpo[i] = CalcHp(atk[i], def[i], eva[i]) IF MSGBOX("攻撃力:" + atk[i] + "<#CR>防御力:" + def[i] + "<#CR>回避力:" + eva[i] + "<#CR>体力 :" + hpo[i] + "<#CR>でよろしいですか?", BTN_YES OR BTN_NO) = BTN_NO THEN hpo[i] = 0 WEND ELSE IF LENGTH(gen[i] < 76) THEN gen[i] = gen[i] + FORMAT("0", 76 - LENGTH(gen[i])) AnalyzeGen(gen[i], atk[i], def[i], eva[i], hpo[i], ran[i][0], ran[i][1], ran[i][2], pat[i]) ENDIF Log("P" + i + " : atk(" + atk[i] + ") def(" + def[i] + ") eva(" + eva[i] + ") hp(" + hpo[i] + ") " + gen[i], 3) NEXT DIM s[1], c = 0, w = 0 WHILE w < n AND (c - w < n) // 最初の二手の実行 FOR j = 0 TO 1 hp[j] = hpo[j] r[j] = 0 IFB gen[j] = "PLAYER" THEN s[j] = GetCmd(hp[j], hpo[j]) ELSE s[j] = COPY(pat[j], 1, 1) ENDIF NEXT t[0] = ProcStep(atk, def, eva, hp, ran[0][r[0]], ran[1][r[1]], s[0], s[1], 1) IFB hp[0] > 0 AND hp[1] > 0 THEN FOR j = 0 TO 1 IFB gen[j] = "PLAYER" THEN s[j] = GetCmd(hp[j], hpo[j]) ELSE s[j] = COPY(pat[j], 2, 1) ENDIF NEXT t[1] = ProcStep(atk, def, eva, hp, ran[0][r[0]], ran[1][r[1]], s[0], s[1], 2) ENDIF // 残りの実行 i = 3 WHILE hp[0] > 0 AND hp[1] > 0 IFB GETKEYSTATE(VK_F1) THEN SELECT SLCTBOX(SLCT_NUM, 0, "強制介入", "ログレベル変更", "P0勝利", "P1勝利") CASE 0 LogLevel = VAL(INPUT("レベルは?", LogLevel)) CASE 1 hp[1] = 0 BREAK CASE 2 hp[0] = 0 BREAK SELEND ENDIF t[2] = t[0] * 9 + t[1] t[3] = ((t[0] MOD 3) * 3 + INT(t[0] / 3)) * 9 + ((t[1] MOD 3) * 3 + INT(t[1] / 3)) Log(" 2手前:" + t[0] + " 1手前:" + t[1], 5) t[0] = t[1] FOR j = 0 TO 1 IFB hp[j] < hpo[j] / 3 THEN r[j] = 2 ELSEIF hp[j] < hpo[j] * 2 / 3 THEN r[j] = 1 ENDIF IFB gen[j] = "PLAYER" THEN s[j] = GetCmd(hp[j], hpo[j]) ELSE s[j] = COPY(pat[j], 3 + t[2+j] + r[j] * 81, 1) Log(" 組み合わせ:" + t[2+j] + " hp:" + hp[j] + "/" + hpo[j] + "=" + r[j] + " 手:" + s[j], 5) ENDIF NEXT t[1] = ProcStep(atk, def, eva, hp, ran[0][r[0]], ran[1][r[1]], s[0], s[1], i) i = i + 1 WEND c = c + 1 IFB hp[0] > 0 THEN w = w + 1 Log("P0の1本! " + w) ELSE Log("P1の1本! " + (c - w)) ENDIF WEND IFB w < n THEN Log("P1の勝利!", 3) RESULT = 1 ELSE Log("P0の勝利!", 3) RESULT = 0 ENDIF FEND FUNCTION GetCmd(hp, hpo) RESULT = "" + SLCTBOX(SLCT_NUM, 0, "コマンド HP(" + hp + "/" + hpo + ")", "攻撃", "防御", "回避攻撃") FEND // 処理 FUNCTION ProcStep(atk[], def[], eva[], var hp[], ran0, ran1, c0, c1, turn) // 乱数による手の差し替え判定 DIM i, c, t[] = 0, 0 c = c0 + c1 IF ran0 > RANDOM(1000) THEN c0 = "" + RANDOM(3) IF ran1 > RANDOM(1000) THEN c1 = "" + RANDOM(3) IF c <> c0 + c1 THEN Log(" P0 P1 " + c + " -> " + c0 + c1, 5) Log("ターン " + turn) SELECT c0 + c1 CASE "00" t[0] = INT(atk[1] * (1 - def[0] / 1000)) IF t[0] < 1 THEN t[0] = 1 t[1] = INT(atk[0] * (1 - def[1] / 1000)) IF t[1] < 1 THEN t[1] = 1 Log(" 相討ち!") RESULT = 0 CASE "01" t[1] = INT((atk[0] - def[1]) / 3) IF t[1] < 1 THEN t[1] = 1 Log(" P0がガードの上から攻撃") RESULT = 1 CASE "02" t[0] = INT(atk[1] * (1 - def[0] / 1000)) IF t[0] < 1 THEN t[0] = 1 Log(" P1が回避攻撃") RESULT = 2 CASE "10" t[0] = INT((atk[0] - def[1]) / 3) IF t[0] < 1 THEN t[1] = 1 Log(" P1がガードの上から攻撃") RESULT = 3 CASE "11" Log(" 睨み合い") RESULT = 4 CASE "12" t[1] = INT((def[0] - def[1]) / 3) IF t[1] < 1 THEN t[1] = 1 Log(" P0がカウンター") RESULT = 5 CASE "20" t[1] = INT(atk[0] * (1 - def[1] / 1000)) IF t[1] < 1 THEN t[1] = 1 Log(" P0が回避攻撃") RESULT = 6 CASE "21" t[0] = INT((def[1] - def[0]) / 3) IF t[0] < 1 THEN t[0] = 1 Log(" P1がカウンター") RESULT = 7 CASE "22" Log(" 双方回避") RESULT = 8 SELEND DIM f[] = 0, 0 IFB eva[0] = eva[1] THEN f[0] = RANDOM(2) ELSE f[0] = (eva[0] < eva[1]) * 1 ENDIF f[1] = 1 - f[0] FOR i = 0 TO 1 IFB t[f[1]] > 0 AND hp[f[0]] > 0 THEN // 当たり判定 IFB eva[f[1]] - eva[f[0]] < RANDOM(1000) THEN Log(" P" + f[1] + "は " + t[f[1]] + "のダメージ") hp[f[1]] = hp[f[1]] - t[f[1]] ELSE Log(" P" + f[0] + "はミスした") ENDIF ENDIF f[0] = f[1] f[1] = 1 - f[1] NEXT FEND // 遺伝子展開 PROCEDURE AnalyzeGen(gen, var atk, var def, var eva, var hp, var ran0, var ran1, var ran2, var pat) // 最初の6桁*2を3パラ*2に。3進数243桁は、前のパラから2桁・3桁と、62進数8桁*8 DIM n = Conv(COPY(gen, 1, 6)), i atk = n MOD 1000 n = (n - atk) / 1000 def = n MOD 1000 n = (n - def) / 1000 eva = n MOD 1000 n = (n - eva) / 1000 pat = "" FOR i = 1 TO 2 pat = pat + (n MOD 3) n = INT(n / 3) NEXT Log("First: " + COPY(gen, 1, 6) + " " + Conv(COPY(gen, 1, 6)) + " atk:" + atk + " def:" + def + " eva:" + eva + " pat:" + pat, 5) n = Conv(COPY(gen, 7, 6)) ran0 = n MOD 1000 n = (n - ran0) / 1000 ran1 = n MOD 1000 n = (n - ran1) / 1000 ran2 = n MOD 1000 n = (n - ran2) / 1000 FOR i = 1 TO 3 pat = pat + (n MOD 3) n = INT(n / 3) NEXT Log("Second: " + COPY(gen, 7, 6) + " " + Conv(COPY(gen, 7, 6)) + " ran0:" + ran0 + " ran1:" + ran1 + " ran2:" + ran2 + " pat:" + pat, 5) FOR n = 0 TO 7 pat = pat + Conv(COPY(gen, 13 + n * 8, 8), 3) NEXT hp = CalcHp(atk, def, eva) Log("pat:" + pat, 5) FEND FUNCTION CalcHp(var atk, var def, var eva) IF atk < 1 THEN atk = 1 IF def < 1 THEN def = 1 IF eva < 1 THEN eva = 1 IFB atk + def + eva > 999 THEN IFB atk > def THEN IFB atk > eva THEN IFB eva + def > 998 THEN eva = 1 def = 998 - atk ELSE atk = 999 - eva - def ENDIF ELSE IFB atk + def > 998 THEN eva = 1 def = 998 - atk ELSE eva = 999 - atk - def ENDIF ENDIF ELSE IFB def > eva THEN IFB eva + atk > 998 THEN eva = 1 def = 998 - atk ELSE def = 999 - eva - atk ENDIF ELSE IFB def + atk > 998 THEN eva = 1 def = 998 - atk ELSE eva = 999 - def - atk ENDIF ENDIF ENDIF ENDIF RESULT = 1000 - atk - def - eva FEND FUNCTION Conv(numstr, adicn=0) RESULT = 0 DIM i, b = LENGTH(_adicn) FOR i = 1 TO LENGTH(numstr) RESULT = RESULT * b + _adicn[COPY(numstr, i, 1)] NEXT IFB adicn > 0 THEN i = RESULT RESULT = "" DIM c FOR c = 1 TO INT(LOGN(adicn, POWER(b, LENGTH(numstr)))) RESULT = RESULT + (i MOD adicn) i = INT(i / adicn) NEXT IF LENGTH(RESULT) = 0 THEN RESULT = "0" ENDIF FEND // 遺伝子生成 FUNCTION CreateGen() DIM i, b = LENGTH(_adicn) RESULT = "" FOR i = 1 TO 76 RESULT = RESULT + _adicn[RANDOM(b), HASH_KEY] NEXT FEND ENDMODULE
弱いグループは適当にやって勝てますが、強いグループは、、、強い、、、かな?
遺伝子には、上記のことが含まれているのです。