View difference between Paste ID: Tpj2TTbj and vngv7Tym
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
}