update
This commit is contained in:
@@ -22,31 +22,111 @@ func setup(rand: RandomNumberGenerator) -> void:
|
||||
greed = rand.randf_range(0.3, 0.8)
|
||||
|
||||
|
||||
func take_turn(p: PlayerState, pool: Pool, rand: RandomNumberGenerator, round_no: int) -> void:
|
||||
func take_turn(p: PlayerState, pool: Pool, rand: RandomNumberGenerator) -> void:
|
||||
_do_upgrades(p, pool)
|
||||
_do_buys(p, pool, rand, round_no)
|
||||
_do_placements(p, pool, round_no)
|
||||
_do_buys(p, pool)
|
||||
_do_placements(p)
|
||||
_do_upgrades(p, pool)
|
||||
var keep := int(lerpf(2.0, 18.0, greed))
|
||||
if p.gold > keep + Data.REROLL_COST and rand.randf() < 0.6:
|
||||
p.reroll(pool, rand)
|
||||
_do_buys(p, pool, rand, round_no)
|
||||
_do_placements(p, pool, round_no)
|
||||
_do_upgrades(p, pool)
|
||||
# Wer kurz vor einem Upgrade steht, würfelt gezielt nach Futter.
|
||||
var hunting := _closest_upgrade_gap(p) <= 3
|
||||
var rolls := 3 if hunting else 1
|
||||
for i in rolls:
|
||||
if p.gold > keep + Data.REROLL_COST and (hunting or rand.randf() < 0.6):
|
||||
p.reroll(pool, rand)
|
||||
_do_buys(p, pool)
|
||||
_do_placements(p)
|
||||
_do_upgrades(p, pool)
|
||||
# Level kaufen, wenn das Brett voll ist und Nachwuchs auf der Bank wartet.
|
||||
while p.gold > keep + Data.XP_BUY_COST and not p.can_place() \
|
||||
and _pick_bench_for_board(p) >= 0 and p.buy_xp():
|
||||
_do_placements(p)
|
||||
_free_bench(p, pool)
|
||||
|
||||
|
||||
## Stellt das Brett gegen den bekannten Gegner um: Tanks vor seine Schützen,
|
||||
## eigene Schützen weg von seinen Tanks. Ohne Gegner gilt die Standardaufstellung.
|
||||
func arrange(p: PlayerState, opp: PlayerState) -> void:
|
||||
if p.board.is_empty():
|
||||
return
|
||||
var units: Array = p.board_units()
|
||||
p.board.clear()
|
||||
var threat := [] # Spalten (gespiegelt), in denen gegnerische Schützen stehen
|
||||
var enemy_tanks := [] # Spalten (gespiegelt) gegnerischer Tanks
|
||||
if opp != null:
|
||||
for hex in opp.board:
|
||||
var col: int = Data.BOARD_COLS - 1 - hex.x
|
||||
if opp.board[hex].role == Data.Role.TANK:
|
||||
enemy_tanks.append(col)
|
||||
else:
|
||||
threat.append(col)
|
||||
var center := [3, 2, 4, 1, 5, 0, 6]
|
||||
var tank_cols := threat.duplicate()
|
||||
for c in center:
|
||||
if not tank_cols.has(c):
|
||||
tank_cols.append(c)
|
||||
# Schützen möglichst weit weg von gegnerischen Tanks.
|
||||
var far_cols := center.duplicate()
|
||||
far_cols.sort_custom(func(a, b):
|
||||
return _min_dist(a, enemy_tanks) > _min_dist(b, enemy_tanks))
|
||||
units.sort_custom(func(a, b): return a.role == Data.Role.TANK and b.role != Data.Role.TANK)
|
||||
for u in units:
|
||||
var rows: Array = [0, 1, 2, 3] if u.role == Data.Role.TANK else [3, 2, 1, 0]
|
||||
var cols: Array = tank_cols if u.role == Data.Role.TANK else far_cols
|
||||
var placed := false
|
||||
for r in rows:
|
||||
for c in cols:
|
||||
var h := Vector2i(c, r)
|
||||
if not p.board.has(h):
|
||||
p.board[h] = u
|
||||
placed = true
|
||||
break
|
||||
if placed:
|
||||
break
|
||||
|
||||
|
||||
func _min_dist(col: int, cols: Array) -> int:
|
||||
if cols.is_empty():
|
||||
return 0
|
||||
var best := 99
|
||||
for c in cols:
|
||||
best = mini(best, absi(col - c))
|
||||
return best
|
||||
|
||||
|
||||
## Kleinste Zahl fehlender Futter-Avatare über alle Board-Einheiten.
|
||||
func _closest_upgrade_gap(p: PlayerState) -> int:
|
||||
var best := 99
|
||||
for hex in p.board:
|
||||
var miss := p.upgrade_missing(hex)
|
||||
if p.board[hex].upgrade_cost().is_empty():
|
||||
continue
|
||||
var total := 0
|
||||
for e in miss:
|
||||
total += miss[e]
|
||||
best = mini(best, total)
|
||||
return best
|
||||
|
||||
|
||||
## Elemente, die irgendeine Board-Einheit für ihr nächstes Upgrade braucht.
|
||||
func _needed_elements(p: PlayerState) -> Dictionary:
|
||||
var need := {}
|
||||
for hex in p.board:
|
||||
for e in p.board[hex].upgrade_cost():
|
||||
need[e] = true
|
||||
return need
|
||||
|
||||
|
||||
func _wants(entry: ShopEntry, p: PlayerState) -> bool:
|
||||
if entry.element < 0:
|
||||
# Neutral wird beim Kauf spezialisiert, also immer brauchbar.
|
||||
return true
|
||||
if pref.has(entry.element):
|
||||
if _needed_elements(p).has(entry.element):
|
||||
return true
|
||||
# Elemente, die schon auf dem Board sind, sind immer Futter.
|
||||
return p.trait_counts().has(entry.element)
|
||||
return pref.has(entry.element)
|
||||
|
||||
|
||||
func _do_buys(p: PlayerState, pool: Pool, rand: RandomNumberGenerator, round_no: int) -> void:
|
||||
func _do_buys(p: PlayerState, pool: Pool) -> void:
|
||||
for i in p.shop.size():
|
||||
var e: ShopEntry = p.shop[i]
|
||||
if e.sold:
|
||||
@@ -60,8 +140,8 @@ func _do_buys(p: PlayerState, pool: Pool, rand: RandomNumberGenerator, round_no:
|
||||
p.buy(i, pool, _pick_element(p) if e.element < 0 else e.element)
|
||||
|
||||
|
||||
func _do_placements(p: PlayerState, pool: Pool, round_no: int) -> void:
|
||||
while p.can_place(round_no):
|
||||
func _do_placements(p: PlayerState) -> void:
|
||||
while p.can_place():
|
||||
var idx := _pick_bench_for_board(p)
|
||||
if idx < 0:
|
||||
return
|
||||
@@ -69,7 +149,7 @@ func _do_placements(p: PlayerState, pool: Pool, round_no: int) -> void:
|
||||
var hex := _pick_hex(p, a.role)
|
||||
if hex.x < 0:
|
||||
return
|
||||
if not p.place(idx, hex, round_no):
|
||||
if not p.place(idx, hex):
|
||||
return
|
||||
|
||||
|
||||
@@ -77,6 +157,7 @@ func _do_placements(p: PlayerState, pool: Pool, round_no: int) -> void:
|
||||
## Alles Weitere bleibt als Futter auf der Bank.
|
||||
func _pick_bench_for_board(p: PlayerState) -> int:
|
||||
var counts := p.trait_counts()
|
||||
var need := _needed_elements(p)
|
||||
var best := -1
|
||||
var best_score := -1
|
||||
for i in p.bench.size():
|
||||
@@ -84,7 +165,9 @@ func _pick_bench_for_board(p: PlayerState) -> int:
|
||||
if a == null:
|
||||
continue
|
||||
var score := 0
|
||||
if pref.has(a.elements[0]):
|
||||
if need.has(a.elements[0]) and counts.get(a.elements[0], 0) > 0:
|
||||
score = 0 # Futter für ein laufendes Upgrade bleibt auf der Bank
|
||||
elif pref.has(a.elements[0]):
|
||||
score = 3 if counts.get(a.elements[0], 0) == 0 else 1
|
||||
else:
|
||||
score = 2 if counts.get(a.elements[0], 0) == 0 else 0
|
||||
@@ -144,12 +227,16 @@ func _do_upgrades(p: PlayerState, pool: Pool) -> void:
|
||||
func _free_bench(p: PlayerState, pool: Pool) -> void:
|
||||
if p.free_bench_slot() >= 0:
|
||||
return
|
||||
var counts := p.trait_counts()
|
||||
var need := _needed_elements(p)
|
||||
# Erst verkaufen, was weder Futter noch Lieblingselement ist.
|
||||
for i in p.bench.size():
|
||||
var a = p.bench[i]
|
||||
if a == null:
|
||||
continue
|
||||
if counts.get(a.elements[0], 0) == 0 and not pref.has(a.elements[0]):
|
||||
if a != null and not need.has(a.elements[0]) and not pref.has(a.elements[0]):
|
||||
p.sell_bench(i, pool)
|
||||
return
|
||||
for i in p.bench.size():
|
||||
var a = p.bench[i]
|
||||
if a != null and not need.has(a.elements[0]):
|
||||
p.sell_bench(i, pool)
|
||||
return
|
||||
p.sell_bench(0, pool)
|
||||
|
||||
Reference in New Issue
Block a user