Refactor civilization flow mechanics: enhance commit and colonization logic, add tests for flow application and resource allocation, and optimize performance metrics.
This commit is contained in:
@@ -306,53 +306,84 @@ func _limit(plans: Dictionary, budget: Dictionary, rules: Dictionary) -> void:
|
||||
plans[source].counts[destination] = allowed
|
||||
_merge(plans[source], source, rejected, plans[source].profiles[destination])
|
||||
|
||||
## Apply one conserved source-by-owner table, then credit each destination once.
|
||||
func _commit(target: Dictionary, physical: Dictionary, plans: Dictionary, rules: Dictionary, year: Variant) -> void:
|
||||
var credits: Dictionary = {}
|
||||
var contributions: Dictionary = {}
|
||||
var births: Dictionary = {}
|
||||
var ownership: Dictionary = {}
|
||||
var space_stages: Dictionary = {"Ct": true}
|
||||
for id in rules: space_stages[id] = id == "Ct" or str(rules[id].home) != ""
|
||||
for source in plans:
|
||||
ownership[source] = {}
|
||||
var free: Variant = target.amount.get(source, 0)
|
||||
if E.gt(free, 0): ownership[source][""] = free
|
||||
for owner in target.binds:
|
||||
for source in target.binds[owner]:
|
||||
if not ownership.has(source): continue
|
||||
var held: Variant = target.binds[owner][source]
|
||||
if E.gt(held, 0): ownership[source][owner] = held
|
||||
for source in plans:
|
||||
var plan: Dictionary = plans[source]
|
||||
var slots: Dictionary = {"": target.amount.get(source, 0)}
|
||||
for owner in target.binds:
|
||||
var held: Variant = target.binds[owner].get(source, 0)
|
||||
if E.gt(held, 0): slots[owner] = held
|
||||
var remaining: Dictionary = {}
|
||||
for destination in plan.counts:
|
||||
var amount: Variant = plan.counts[destination]
|
||||
if E.le(amount, 0): continue
|
||||
remaining[destination] = amount
|
||||
if not contributions.has(destination): contributions[destination] = []
|
||||
contributions[destination].append({"amount": amount, "profile": plan.profiles[destination]})
|
||||
if destination == source: continue
|
||||
var taken: Dictionary = Q.allocate_profiled(slots, amount)
|
||||
for owner in taken:
|
||||
if E.le(taken[owner], 0): continue
|
||||
slots[owner] = E.subtract(slots[owner], taken[owner])
|
||||
var host: String = owner
|
||||
if State.is_space_civilization(destination, rules) or destination == "Ct": host = ""
|
||||
elif owner == "" and State.is_space_civilization(source, rules): host = "@host"
|
||||
var slots: Dictionary = ownership[source]
|
||||
target.amount[source] = 0
|
||||
var owners: Array = slots.keys()
|
||||
if owners.size() == 1 and owners[0] == "":
|
||||
target.amount[source] = remaining.get(source, 0)
|
||||
for destination in remaining:
|
||||
if destination == source: continue
|
||||
var host: String = "@host" if space_stages.get(source, false) and not space_stages.get(destination, false) else ""
|
||||
if not credits.has(destination): credits[destination] = {}
|
||||
credits[destination][host] = E.add(credits[destination].get(host, 0), taken[owner])
|
||||
target.amount[source] = slots[""]
|
||||
for owner in slots:
|
||||
if owner != "": target.binds[owner][source] = slots[owner]
|
||||
credits[destination][host] = E.add(credits[destination].get(host, 0), remaining[destination])
|
||||
continue
|
||||
for i in owners.size():
|
||||
var owner: String = owners[i]
|
||||
# Last row receives the remaining exact quotas; the free-only path
|
||||
# therefore needs no proportional allocation or repeated subtraction.
|
||||
var allocation: Dictionary = remaining if i == owners.size() - 1 else Q.allocate_profiled(remaining, slots[owner])
|
||||
for destination in allocation:
|
||||
var amount: Variant = allocation[destination]
|
||||
if E.le(amount, 0): continue
|
||||
if i != owners.size() - 1:
|
||||
remaining[destination] = E.subtract(remaining[destination], amount)
|
||||
if destination == source:
|
||||
if owner == "": target.amount[source] = amount
|
||||
else: target.binds[owner][source] = amount
|
||||
continue
|
||||
var host: String = owner
|
||||
if space_stages.get(destination, false): host = ""
|
||||
elif owner == "" and space_stages.get(source, false): host = "@host"
|
||||
if not credits.has(destination): credits[destination] = {}
|
||||
credits[destination][host] = E.add(credits[destination].get(host, 0), amount)
|
||||
if owner != "" and E.le(allocation.get(source, 0), 0): target.binds[owner][source] = 0
|
||||
var hosts: Dictionary = {}
|
||||
for id in physical:
|
||||
if world.catalog.entities[id].event_group == "DwStar" and E.gt(physical[id], 0): hosts[id] = physical[id]
|
||||
var host_shares: Array = _host_shares(hosts) if not hosts.is_empty() else []
|
||||
for destination in credits:
|
||||
var created: Variant = world.ledger.credit(target, destination, Q.sum(credits[destination]))
|
||||
var bound: Variant = 0
|
||||
for owner in credits[destination]:
|
||||
var count: Variant = credits[destination][owner]
|
||||
if owner == "" or E.le(count, 0): continue
|
||||
if owner == "@host":
|
||||
if hosts.is_empty(): continue
|
||||
var ownership: Dictionary = Q.split_profile(target.civilization_remainders, "flow:hosts:" + destination, count, hosts.keys(), _host_shares(hosts))
|
||||
for host in ownership:
|
||||
if E.le(ownership[host], 0): continue
|
||||
var distributed: Dictionary = Q.split_profile(target.civilization_remainders, "flow:hosts:" + destination, count, hosts.keys(), host_shares)
|
||||
for host in distributed:
|
||||
if E.le(distributed[host], 0): continue
|
||||
if not target.binds.has(host): target.binds[host] = {}
|
||||
target.binds[host][destination] = E.add(target.binds[host].get(destination, 0), ownership[host])
|
||||
target.amount[destination] = E.subtract(target.amount[destination], count)
|
||||
target.binds[host][destination] = E.add(target.binds[host].get(destination, 0), distributed[host])
|
||||
else:
|
||||
target.binds[owner][destination] = E.add(target.binds[owner].get(destination, 0), count)
|
||||
target.amount[destination] = E.subtract(target.amount[destination], count)
|
||||
bound = E.add(bound, count)
|
||||
target.amount[destination] = E.subtract(target.amount[destination], bound)
|
||||
if not rules.has(destination): births[destination] = created
|
||||
var final: Dictionary = world.ledger.physical_amounts(target)
|
||||
for destination in contributions:
|
||||
@@ -387,7 +418,7 @@ func _colonize(target: Dictionary, colonies: Dictionary, year: Variant, rules: D
|
||||
var total: Variant = Q.sum(granted)
|
||||
if E.le(total, 0): return
|
||||
var taken_resources: Dictionary = Q.allocate_profiled(stocks, total)
|
||||
var remaining: Dictionary = granted.duplicate()
|
||||
var removed_by_owner: Dictionary = {}
|
||||
for resource in taken_resources:
|
||||
var removed: Variant = taken_resources[resource]
|
||||
if E.le(removed, 0): continue
|
||||
@@ -401,15 +432,30 @@ func _colonize(target: Dictionary, colonies: Dictionary, year: Variant, rules: D
|
||||
if E.le(amount, 0): continue
|
||||
if owner == "": target.amount[resource] = E.subtract(target.amount[resource], amount)
|
||||
else: target.binds[owner][resource] = E.subtract(target.binds[owner][resource], amount)
|
||||
var allocation: Dictionary = Q.allocate_profiled(remaining, amount)
|
||||
for destination in allocation:
|
||||
var count: Variant = allocation[destination]
|
||||
if E.le(count, 0): continue
|
||||
remaining[destination] = E.subtract(remaining[destination], count)
|
||||
var created: Variant = world.ledger.credit(target, destination, count)
|
||||
if owner != "" and not State.is_space_civilization(destination, rules):
|
||||
target.amount[destination] = E.subtract(target.amount[destination], created)
|
||||
target.binds[owner][destination] = E.add(target.binds[owner].get(destination, 0), created)
|
||||
removed_by_owner[owner] = E.add(removed_by_owner.get(owner, 0), amount)
|
||||
var remaining: Dictionary = granted.duplicate()
|
||||
var placements: Dictionary = {}
|
||||
var owners: Array = removed_by_owner.keys()
|
||||
for i in owners.size():
|
||||
var owner: String = owners[i]
|
||||
var allocation: Dictionary = remaining if i == owners.size() - 1 else Q.allocate_profiled(remaining, removed_by_owner[owner])
|
||||
for destination in allocation:
|
||||
var count: Variant = allocation[destination]
|
||||
if E.le(count, 0): continue
|
||||
if i != owners.size() - 1: remaining[destination] = E.subtract(remaining[destination], count)
|
||||
if owner == "" or State.is_space_civilization(destination, rules): continue
|
||||
if not placements.has(destination): placements[destination] = {}
|
||||
placements[destination][owner] = count
|
||||
for destination in granted:
|
||||
var count: Variant = granted[destination]
|
||||
if E.le(count, 0): continue
|
||||
world.ledger.credit(target, destination, count)
|
||||
var bound: Variant = 0
|
||||
for owner in placements.get(destination, {}):
|
||||
var held: Variant = placements[destination][owner]
|
||||
target.binds[owner][destination] = E.add(target.binds[owner].get(destination, 0), held)
|
||||
bound = E.add(bound, held)
|
||||
target.amount[destination] = E.subtract(target.amount[destination], bound)
|
||||
for id in granted:
|
||||
if E.le(granted[id], 0): continue
|
||||
var profile: Dictionary = colonies[id].profiles[id]
|
||||
|
||||
Reference in New Issue
Block a user