Spiel untersucht und optimiert: KI-Suche, Hintergrund-Threads, Dialog-Helfer
- KI-Vorausschau in zwei Stufen mit Zielvorauswahl (höchstens 4 Ziele je Karte und Angreifer, die 8 besten Erstschritte vertieft): 5 Gegner 2063 ms -> 101 ms, 1 Gegner 160 ms -> 36 ms, alle Kandidaten im Budget; 52:48 gegen die alte Suche - KI rechnet im WorkerThreadPool auf einer Spielkopie, schon während der Wartezeit; längste Bildzeit im Kampf mit 5 Gegnern 108 ms -> 38 ms - Musik wird im Hintergrund erzeugt (Start 185 ms schneller) - Style.overlay und Style.confirm ersetzen vier kopierte Dialoge - Übersetzungen für Abbrechen und Zurücksetzen, Archetypen neu gemessen - tests/perf_probe.gd (Laufzeiten) und tests/frame_probe.tscn (Bildzeiten) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QPgKvy5W9WRNFHjkm5QsHx
This commit is contained in:
49
tests/frame_probe.gd
Normal file
49
tests/frame_probe.gd
Normal file
@@ -0,0 +1,49 @@
|
||||
extends Node
|
||||
## Fensterprobe: Kosten von refresh() und längste Bildzeit während KI-Zügen (5 Gegner).
|
||||
|
||||
var main: Node
|
||||
var max_dt := 0.0
|
||||
var frames_n := 0
|
||||
var measuring := false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
Game.test_seed = 4242
|
||||
main = load("res://scenes/main.tscn").instantiate()
|
||||
main.save_path = "user://_probe.json"
|
||||
add_child(main)
|
||||
await get_tree().process_frame
|
||||
await get_tree().process_frame
|
||||
var scr: BattleScreen = BattleScreen.new(5)
|
||||
main.show_screen(scr)
|
||||
await get_tree().process_frame
|
||||
await get_tree().process_frame
|
||||
var h: Game.Player = scr.game.human
|
||||
while h.hand.size() < 8 and not h.deck.is_empty():
|
||||
scr.game.draw(h)
|
||||
var t0 := Time.get_ticks_usec()
|
||||
for i in 30:
|
||||
scr.refresh()
|
||||
print("refresh() mit 5 Gegnern und 8 Handkarten: %.2f ms" % ((Time.get_ticks_usec() - t0) / 1000.0 / 30))
|
||||
scr.mulligan.visible = false
|
||||
h.mulligan_done = true
|
||||
scr.ai_delay = 0.2
|
||||
measuring = true
|
||||
var start := Time.get_ticks_msec()
|
||||
var actions := 0
|
||||
var last_turn := scr.game.turn
|
||||
while Time.get_ticks_msec() - start < 12000 and scr.game.winner == "":
|
||||
if scr.game.current().is_human and scr.game.current() == h:
|
||||
scr.game.end_turn()
|
||||
scr.after_action()
|
||||
await get_tree().process_frame
|
||||
measuring = false
|
||||
print("längste Bildzeit in 12 s KI-Spiel: %.0f ms (%d Bilder, Zug %d)" % [max_dt * 1000.0, frames_n, scr.game.turn])
|
||||
DirAccess.remove_absolute(ProjectSettings.globalize_path("user://_probe.json"))
|
||||
get_tree().quit()
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if measuring:
|
||||
frames_n += 1
|
||||
max_dt = maxf(max_dt, delta)
|
||||
1
tests/frame_probe.gd.uid
Normal file
1
tests/frame_probe.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://botawgwpha3ai
|
||||
6
tests/frame_probe.tscn
Normal file
6
tests/frame_probe.tscn
Normal file
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://tests/frame_probe.gd" id="1"]
|
||||
|
||||
[node name="FrameProbe" type="Node"]
|
||||
script = ExtResource("1")
|
||||
50
tests/perf_probe.gd
Normal file
50
tests/perf_probe.gd
Normal file
@@ -0,0 +1,50 @@
|
||||
extends SceneTree
|
||||
## Laufzeitmessung: Start, KI-Entscheidungen, Deckerzeugung, Vorschau, Musik.
|
||||
|
||||
|
||||
func ms(f: Callable, n: int = 1) -> float:
|
||||
var t0 := Time.get_ticks_usec()
|
||||
for i in n:
|
||||
f.call()
|
||||
return (Time.get_ticks_usec() - t0) / 1000.0 / n
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
var t := ms(func(): Cards.all())
|
||||
print("Kartenpool laden: %.1f ms" % t)
|
||||
var r := RandomNumberGenerator.new()
|
||||
r.seed = 3
|
||||
var starter := Profile.starter().deck_cards()
|
||||
print("Gegnerdeck (Zielstärke): %.1f ms" % ms(func(): DeckGen.build_opponent_deck_rated(r, ["Feuer", "Erde"], 1.5), 10))
|
||||
print("Vorschau 1..5 Gegner: %.1f ms" % ms(func():
|
||||
for n in range(1, 6):
|
||||
for i in n:
|
||||
Game.random_opponent(r, i + 1, Game.START_LIFE, 1.3, "")))
|
||||
for n in [1, 3, 5]:
|
||||
var g := Game.new_battle(starter, n, r, {"target_rating": 1.5})
|
||||
# ein volles Brett für alle, damit die Entscheidung teuer wird
|
||||
var uid := 5000
|
||||
for p in g.players:
|
||||
p.mulligan_done = true
|
||||
for k in 4:
|
||||
var c := Game.Creature.new(Cards.by_id("f_wolf"), p, uid)
|
||||
uid += 1
|
||||
c.ready = true
|
||||
c.attacks_left = 1
|
||||
p.board.append(c)
|
||||
var h: Game.Player = g.players[0]
|
||||
h.energy = 10
|
||||
h.max_energy = 10
|
||||
for k in 6:
|
||||
h.hand.append(Cards.by_id("f_funke"))
|
||||
AI.time_budget_ms = 100000
|
||||
var t_full := ms(func(): AI.choose_action(g, h))
|
||||
AI.time_budget_ms = 150
|
||||
var t_budget := ms(func(): AI.choose_action(g, h))
|
||||
var cands := AI.candidate_actions(g, h).size()
|
||||
print("KI-Entscheidung, %d Gegner, %d Kandidaten: ohne Budget %.0f ms, mit Budget %.0f ms" % [n, cands, t_full, t_budget])
|
||||
print("Spielkopie: %.3f ms" % ms(func(): Game.new_battle(starter, 5, r).clone(), 20))
|
||||
print("Musik erzeugen (läuft im Hintergrund-Thread): %.0f ms" % ms(func(): Sfx.new()._music()))
|
||||
print("Deckstärke berechnen: %.3f ms" % ms(func(): Game.deck_rating(starter), 100))
|
||||
print("Snapshot 6 Spieler: %.2f ms" % ms(func(): Game.new_battle(starter, 5, r).snapshot(0), 10))
|
||||
quit()
|
||||
1
tests/perf_probe.gd.uid
Normal file
1
tests/perf_probe.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://xrm3o6vloxh0
|
||||
Reference in New Issue
Block a user