+
+ /* Buy a Device of Cloaking */
+ if addr[Cloaks] == 1 && addr[UnusedCargo] < dims[UnusedCargo]-1 {
+ relative_price, available := data.Planets[data.i2p[addr[Location]]].RelativePrices["Device Of Cloakings"]
+ if available {
+ absolute_price := int(float64(data.Commodities["Device Of Cloakings"].BasePrice) * float64(relative_price) / 100.0)
+ other[Cloaks] = 0
+ if other[Hold] != 0 {
+ other[UnusedCargo] = addr[UnusedCargo] + 1
+ }
+ Consider(data, dims, table, other, -absolute_price, &best_value, best_source)
+ other[UnusedCargo] = addr[UnusedCargo]
+ other[Cloaks] = addr[Cloaks]
+ }
+ }
+
+ /* Buy Fighter Drones */
+ if addr[BuyFighters] == 1 {
+ relative_price, available := data.Planets[data.i2p[addr[Location]]].RelativePrices["Fighter Drones"]
+ if available {
+ absolute_price := int(float64(data.Commodities["Fighter Drones"].BasePrice) * float64(relative_price) / 100.0)
+ other[BuyFighters] = 0
+ Consider(data, dims, table, other, -absolute_price**drones, &best_value, best_source)
+ other[BuyFighters] = addr[BuyFighters]
+ }
+ }
+
+ /* Buy Shield Batteries */
+ if addr[BuyShields] == 1 {
+ relative_price, available := data.Planets[data.i2p[addr[Location]]].RelativePrices["Shield Batterys"]
+ if available {
+ absolute_price := int(float64(data.Commodities["Shield Batterys"].BasePrice) * float64(relative_price) / 100.0)
+ other[BuyShields] = 0
+ Consider(data, dims, table, other, -absolute_price**batteries, &best_value, best_source)
+ other[BuyShields] = addr[BuyShields]
+ }
+ }
+
+ /* Visit this planet */
+ var i uint
+ for i = 0; i < uint(len(visit())); i++ {
+ if addr[Visit]&(1<<i) != 0 && visit()[i] == data.i2p[addr[Location]] {
+ other[Visit] = addr[Visit] & ^(1 << i)
+ Consider(data, dims, table, other, 0, &best_value, best_source)
+ }
+ }
+ other[Visit] = addr[Visit]
+
+ /* Buy Eden warp units */
+ eden_limit := data.Commodities["Eden Warp Units"].Limit
+ if addr[Edens] > 0 && addr[Edens] <= eden_limit {
+ relative_price, available := data.Planets[data.i2p[addr[Location]]].RelativePrices["Eden Warp Units"]
+ if available {
+ absolute_price := int(float64(data.Commodities["Eden Warp Units"].BasePrice) * float64(relative_price) / 100.0)
+ for quantity := addr[Edens]; quantity > 0; quantity-- {
+ other[Edens] = addr[Edens] - quantity
+ if addr[Hold] != 0 {
+ other[UnusedCargo] = addr[UnusedCargo] + quantity
+ }
+ if other[UnusedCargo] < dims[UnusedCargo] {
+ Consider(data, dims, table, other, -absolute_price*quantity, &best_value, best_source)
+ }
+ }
+ other[Edens] = addr[Edens]
+ other[UnusedCargo] = addr[UnusedCargo]
+ }
+ }
+
+ // Check that we didn't lose track of any temporary modifications to other.
+ for i := 0; i < NumDimensions; i++ {
+ if addr[i] != other[i] {
+ panic(i)
+ }
+ }
+
+ // Sanity check: This cell was in state BEING_EVALUATED
+ // the whole time that it was being evaluated.
+ if table[my_index].value != CELL_BEING_EVALUATED {
+ panic(my_index)
+ }
+
+ // Record our findings
+ table[my_index].value = best_value
+ table[my_index].from = EncodeIndex(dims, best_source)
+
+ // UI: Progress bar
+ cell_filled_count++
+ if cell_filled_count&0xff == 0 {
+ print(fmt.Sprintf("\r%3.1f%%", 100*float64(cell_filled_count)/float64(StateTableSize(dims))))
+ }
+
+ return table[my_index].value
+}
+
+func FindBestState(data planet_data, dims []int, table []State) int32 {
+ addr := make([]int, NumDimensions)
+ addr[Edens] = *end_edens
+ addr[Cloaks] = dims[Cloaks] - 1
+ addr[BuyFighters] = dims[BuyFighters] - 1
+ addr[BuyShields] = dims[BuyShields] - 1
+ addr[Visit] = dims[Visit] - 1
+ addr[Traded] = 1
+ addr[Hold] = 0
+ addr[UnusedCargo] = 0
+ max_index := int32(-1)
+ max_value := int32(0)
+ max_fuel := 1
+ if *fuel == 0 {
+ max_fuel = 0
+ }
+ for addr[Fuel] = 0; addr[Fuel] <= max_fuel; addr[Fuel]++ {
+ for addr[Location] = 0; addr[Location] < dims[Location]; addr[Location]++ {
+ if len(end()) == 0 || end()[data.i2p[addr[Location]]] {
+ index := EncodeIndex(dims, addr)
+ value := CellValue(data, dims, table, addr)
+ if value > max_value {
+ max_value = value
+ max_index = index
+ }
+ }
+ }
+ }
+ return max_index
+}
+
+func Commas(n int32) (s string) {
+ r := n % 1000
+ n /= 1000
+ for n > 0 {
+ s = fmt.Sprintf(",%03d", r) + s
+ r = n % 1000
+ n /= 1000
+ }
+ s = fmt.Sprint(r) + s
+ return
+}
+
+func DescribePath(data planet_data, dims []int, table []State, start int32) (description []string) {
+ for index := start; index > 0 && table[index].from > 0; index = table[index].from {
+ var line string
+ addr := DecodeIndex(dims, index)
+ prev := DecodeIndex(dims, table[index].from)
+ if addr[Fuel] != prev[Fuel] {
+ from := data.i2p[prev[Location]]
+ to := data.i2p[addr[Location]]
+ line += fmt.Sprintf("Jump from %v to %v (%v hyper jump units)", from, to, prev[Fuel]-addr[Fuel])
+ }
+ if addr[Edens] == prev[Edens]-1 {
+ from := data.i2p[prev[Location]]
+ to := data.i2p[addr[Location]]
+ line += fmt.Sprintf("Eden warp from %v to %v", from, to)
+ }
+ if addr[Hold] != prev[Hold] {
+ if addr[Hold] == 0 {
+ quantity := *hold - (prev[UnusedCargo] + prev[Edens] + prev[Cloaks])
+ line += fmt.Sprintf("Sell %v %v", quantity, data.i2c[prev[Hold]])
+ } else if prev[Hold] == 0 {
+ quantity := *hold - (addr[UnusedCargo] + addr[Edens] + addr[Cloaks])
+ line += fmt.Sprintf("Buy %v %v", quantity, data.i2c[addr[Hold]])
+ } else {
+ panic("Switched cargo?")
+ }
+
+ }
+ if addr[Cloaks] == 1 && prev[Cloaks] == 0 {
+ // TODO: Dump cloaks, convert from cargo?
+ line += "Buy a Cloak"
+ }
+ if addr[Edens] > prev[Edens] {
+ line += fmt.Sprint("Buy ", addr[Edens]-prev[Edens], " Eden Warp Units")
+ }
+ if addr[BuyShields] == 1 && prev[BuyShields] == 0 {
+ line += fmt.Sprint("Buy ", *batteries, " Shield Batterys")
+ }
+ if addr[BuyFighters] == 1 && prev[BuyFighters] == 0 {
+ line += fmt.Sprint("Buy ", *drones, " Fighter Drones")
+ }
+ if addr[Visit] != prev[Visit] {
+ // TODO: verify that the bit chat changed is addr[Location]
+ line += fmt.Sprint("Visit ", data.i2p[addr[Location]])
+ }
+ if line == "" && addr[Hold] == prev[Hold] && addr[Traded] != prev[Traded] {
+ // The Traded dimension is for housekeeping. It doesn't directly
+ // correspond to in-game actions, so don't report transitions.
+ continue
+ }
+ if line == "" {
+ line = fmt.Sprint(prev, " -> ", addr)
+ }
+ description = append(description, fmt.Sprintf("%13v ", Commas(table[index].value))+line)
+ }
+ return