SHOW:
|
|
- or go back to the newest paste.
1 | // miridiusAi | |
2 | package miridiusAi | |
3 | ||
4 | import ( | |
5 | common "github.com/zond/stockholm-ai/common" | |
6 | state "github.com/zond/stockholm-ai/state" | |
7 | ) | |
8 | ||
9 | /* | |
10 | BalancedAi1 basically just aims to multiply as much as possible | |
11 | 1. For each node i in s: | |
12 | a. i.Attraction = how much growth I would gain by sending 1 soldier there | |
13 | 2. For each node j in s where I have units: | |
14 | a. For each node k, attraction to k = k.Attraction / (distance from j to k) | |
15 | b. attraction of each edge connected to j is the sum of the attractions of nodes whos path start with that edge | |
16 | c. attraction of not moving = j.Attraction | |
17 | d. leave 1 unit to hold the node, and divide remaining units amongst all edges proportionally based on attraction ratios | |
18 | ||
19 | Known issues: | |
20 | 1. Soldiers currently on edges are not considered in calculations, which causes the AI to send out units more often than really necessary. | |
21 | */ | |
22 | type BalancedAi1 struct{} | |
23 | ||
24 | /* | |
25 | Orders will analyze all nodes in s and return orders for each one | |
26 | */ | |
27 | func (self BalancedAi1) Orders(logger common.Logger, me state.PlayerId, s *state.State) (result state.Orders) { | |
28 | ||
29 | var attraction, totalAttraction float64 | |
30 | var edge state.NodeId | |
31 | // Calculate base attraction for all nodes | |
32 | - | attractions := make(map[state.NodeId]float64, len(s.Nodes)+1) |
32 | + | attractions := make(map[state.NodeId]float64, len(s.Nodes)) |
33 | for _, node := range s.Nodes { | |
34 | if node.Units[me] < 1 { | |
35 | attraction = 1 | |
36 | } else { | |
37 | attraction = 0 | |
38 | } | |
39 | attraction = attraction + (0.2 * float64(node.Units[me]) / float64(node.Size)) | |
40 | ||
41 | attractions[node.Id] = attraction | |
42 | } | |
43 | ||
44 | // For each node in s | |
45 | for _, node := range s.Nodes { | |
46 | // If I have units there (after leaving 1 behind to defend) | |
47 | if units := node.Units[me] - 1; units > 0 { | |
48 | // Check my attraction to all other nodes and keep an attraction sum for each starting edge. | |
49 | edgeAttractions := make(map[state.NodeId]float64, len(node.Edges)+1) | |
50 | totalAttraction = 0 | |
51 | for _, destNode := range s.Nodes { | |
52 | path := s.Path(node.Id, destNode.Id, nil) | |
53 | if len(path) > 0 { | |
54 | edge = path[0] | |
55 | attraction = attractions[destNode.Id] / float64(len(path)) | |
56 | } else { | |
57 | edge = node.Id | |
58 | attraction = attractions[destNode.Id] | |
59 | } | |
60 | edgeAttractions[edge] = edgeAttractions[edge] + attraction | |
61 | totalAttraction = totalAttraction + attraction | |
62 | } | |
63 | // go through all edges and send units accordingly | |
64 | for edgeId, att := range edgeAttractions { | |
65 | // in case of rounding errors or some other hiccup, make sure current edge's attraction <= total | |
66 | if att > totalAttraction { | |
67 | totalAttraction = att | |
68 | } | |
69 | sendUnits := int(float64(units) * att / totalAttraction) | |
70 | units = units - sendUnits | |
71 | totalAttraction = totalAttraction - att | |
72 | result = append(result, state.Order{ | |
73 | Src: node.Id, | |
74 | Dst: edgeId, | |
75 | Units: sendUnits, | |
76 | }) | |
77 | } | |
78 | } | |
79 | } | |
80 | return | |
81 | } |