update
This commit is contained in:
@@ -101,14 +101,7 @@ static func candidate_actions(game: Game, p: Game.Player, prune: bool = false) -
|
||||
for cr in p.board:
|
||||
if cr.hidden and game.can_reveal(p, cr)[0]:
|
||||
out.append({"type": "reveal", "creature": cr})
|
||||
var pairs := []
|
||||
for i in p.board.size():
|
||||
for j in range(i + 1, p.board.size()):
|
||||
if game.can_fuse(p, p.board[i], p.board[j])[0]:
|
||||
pairs.append([p.board[i], p.board[j]])
|
||||
if prune and pairs.size() > MAX_TARGETS:
|
||||
pairs = _top(pairs, func(pr): return _value(pr[0]) + _value(pr[1]), MAX_TARGETS)
|
||||
for pr in pairs:
|
||||
for pr in fusion_pairs(game, p, prune):
|
||||
out.append({"type": "fuse", "creature": pr[0], "other": pr[1]})
|
||||
for cr in p.board:
|
||||
if not cr.can_attack():
|
||||
@@ -126,6 +119,39 @@ static func candidate_actions(game: Game, p: Game.Player, prune: bool = false) -
|
||||
return out
|
||||
|
||||
|
||||
## Verschmelzungen, die sich lohnen könnten: Paare eigener Wesen (mit prune die schwächsten, die
|
||||
## Plätze frei machen), jedes angeschlagene Wesen mit der billigsten Handkarte, die zwei
|
||||
## billigsten Handkarten. Das Ergebnis kommt auf die Hand, die Vorausschau legt es im Folgeschritt.
|
||||
static func fusion_pairs(game: Game, p: Game.Player, prune: bool) -> Array:
|
||||
var pairs := []
|
||||
for i in p.board.size():
|
||||
for j in range(i + 1, p.board.size()):
|
||||
pairs.append([p.board[i], p.board[j]])
|
||||
if prune and pairs.size() > MAX_TARGETS:
|
||||
pairs = _top(pairs, func(pr): return -(_value(pr[0]) + _value(pr[1])), MAX_TARGETS)
|
||||
var cheap := _cheapest(p)
|
||||
if not cheap.is_empty():
|
||||
for cr in p.board:
|
||||
if cr.health < cr.max_health:
|
||||
pairs.append([cr, cheap[0]])
|
||||
if cheap.size() >= 2:
|
||||
pairs.append([cheap[0], cheap[1]])
|
||||
return pairs.filter(func(pr): return game.can_fuse(p, pr[0], pr[1])[0])
|
||||
|
||||
|
||||
## Handkarten nach Kosten aufsteigend.
|
||||
static func _cheapest(p: Game.Player) -> Array:
|
||||
var cheap: Array = p.hand.duplicate()
|
||||
cheap.sort_custom(func(a, b): return a.cost < b.cost)
|
||||
return cheap
|
||||
|
||||
|
||||
## Teil einer Verschmelzung in einem anderen Spiel: Handkarten sind in Kopien dieselben Objekte,
|
||||
## Wesen werden über ihre uid gefunden.
|
||||
static func _part(g: Game, x):
|
||||
return x if x is Cards.Card else g.find_creature(x.uid)
|
||||
|
||||
|
||||
## Führt eine Aktion des Originals auf der Kopie aus.
|
||||
static func apply_on_clone(g2: Game, game: Game, action: Dictionary) -> void:
|
||||
var p2: Game.Player = g2.players[game.current_idx]
|
||||
@@ -135,7 +161,7 @@ static func apply_on_clone(g2: Game, game: Game, action: Dictionary) -> void:
|
||||
"reveal":
|
||||
g2.reveal(p2, g2.find_creature(action.creature.uid))
|
||||
"fuse":
|
||||
g2.fuse(p2, g2.find_creature(action.creature.uid), g2.find_creature(action.other.uid))
|
||||
g2.fuse(p2, _part(g2, action.creature), _part(g2, action.other))
|
||||
_:
|
||||
g2.attack(g2.find_creature(action.creature.uid), map_target(g2, game, action.target))
|
||||
|
||||
@@ -150,9 +176,9 @@ static func map_target(g2: Game, game: Game, t):
|
||||
static func map_action(game: Game, copy: Game, action: Dictionary) -> Dictionary:
|
||||
var out := action.duplicate()
|
||||
if action.has("creature"):
|
||||
out["creature"] = game.find_creature(action.creature.uid)
|
||||
out["creature"] = _part(game, action.creature)
|
||||
if action.has("other"):
|
||||
out["other"] = game.find_creature(action.other.uid)
|
||||
out["other"] = _part(game, action.other)
|
||||
if action.get("target") != null:
|
||||
out["target"] = map_target(game, copy, action.target)
|
||||
return out
|
||||
@@ -211,7 +237,7 @@ static func choose_action(game: Game, p: Game.Player) -> Dictionary:
|
||||
static func _kills(attacker, defender) -> bool:
|
||||
if defender is Game.Player:
|
||||
return attacker.power() >= defender.life
|
||||
return attacker.power() + Cards.matchup(attacker.card.elements, defender.card.elements) >= defender.health
|
||||
return attacker.power() + Game.matchup_bonus(attacker, defender) >= defender.health
|
||||
|
||||
|
||||
static func _value(c) -> int:
|
||||
@@ -234,8 +260,14 @@ static func _best(list: Array, key: Callable):
|
||||
static func choose_action_greedy(game: Game, p: Game.Player) -> Dictionary:
|
||||
if game.winner != "" or game.enemies_of(p).is_empty():
|
||||
return {"type": "end"}
|
||||
# Gierig: erst das teuerste Spielbare legen (bei vollem Feld die zwei schwächsten Wesen
|
||||
# verschmelzen), dann aufdecken und angreifen, dann Doppelschlag kaufen, dann ziehen.
|
||||
# Gierig: ein Wesen mit höchstens halbem Leben heilen (mit der billigsten Handkarte
|
||||
# verschmelzen, wenn das Ergebnis bezahlbar bleibt), dann das teuerste Spielbare legen (bei
|
||||
# vollem Feld die zwei schwächsten Wesen verschmelzen), dann aufdecken und angreifen, dann ziehen.
|
||||
var cheap := _cheapest(p)
|
||||
if not cheap.is_empty():
|
||||
for cr in p.board:
|
||||
if cr.health * 2 <= cr.max_health and game.can_fuse(p, cr, cheap[0])[0] and Game.fusion_result(p, cr, cheap[0]).cost <= p.energy:
|
||||
return {"type": "fuse", "creature": cr, "other": cheap[0]}
|
||||
var playable := p.hand.filter(func(c): return game.can_play(p, c)[0])
|
||||
if not playable.is_empty():
|
||||
Game.shuffle(playable, game.rng)
|
||||
@@ -244,7 +276,7 @@ static func choose_action_greedy(game: Game, p: Game.Player) -> Dictionary:
|
||||
if c.cost > card.cost:
|
||||
card = c
|
||||
return {"type": "play", "card": card, "face_down": false}
|
||||
if p.board.size() >= Game.MAX_BOARD and p.hand.any(func(c): return c.cost <= p.energy - 1):
|
||||
if p.board.size() >= Game.MAX_BOARD and p.hand.any(func(c): return c.cost <= p.energy):
|
||||
var weakest: Array = p.board.duplicate()
|
||||
weakest.sort_custom(func(a, b): return _value(a) < _value(b))
|
||||
if game.can_fuse(p, weakest[0], weakest[1])[0]:
|
||||
|
||||
Reference in New Issue
Block a user