+
+ /* Travel here via a 1-fuel unit jump (a hyper hole) */
+ if addr[Fuel]+1 < dims[Fuel] {
+ hole_index := (dims[Fuel] - 1) - (addr[Fuel] + 1)
+ if hole_index < len(flight_plan()) && addr[Location] == data.p2i[flight_plan()[hole_index]] {
+ other[Fuel] = addr[Fuel] + 1
+ for other[Location] = 0; other[Location] < dims[Location]; other[Location]++ {
+ Consider(data, dims, table, other, 0, &best_value, best_source)
+ }
+ other[Location] = addr[Location]
+ other[Fuel] = addr[Fuel]
+ }
+ }
+
+ /* Travel here via Eden Warp Unit */
+ if addr[Edens]+1 < dims[Edens] && addr[UnusedCargo] > 0 {
+ _, available := data.Planets[data.i2p[addr[Location]]].RelativePrices["Eden Warp Units"]
+ if !available {
+ other[Edens] = addr[Edens] + 1
+ if other[Hold] != 0 {
+ other[UnusedCargo] = addr[UnusedCargo] - 1
+ }
+ for other[Location] = 0; other[Location] < dims[Location]; other[Location]++ {
+ Consider(data, dims, table, other, 0, &best_value, best_source)
+ }
+ other[Location] = addr[Location]
+ other[UnusedCargo] = addr[UnusedCargo]
+ other[Edens] = addr[Edens]
+ }
+ }
+ other[Traded] = addr[Traded]
+ }
+
+ /* Trade */
+ if addr[Traded] == 1 {
+ other[Traded] = 0
+
+ /* Consider not trading */
+ Consider(data, dims, table, other, 0, &best_value, best_source)
+
+ if !data.Planets[data.i2p[addr[Location]]].Private {
+
+ /* Sell */
+ if addr[Hold] == 0 && addr[UnusedCargo] == 0 {
+ for other[Hold] = 0; other[Hold] < dims[Hold]; other[Hold]++ {
+ commodity := data.i2c[other[Hold]]
+ if !data.Commodities[commodity].CanSell {
+ continue
+ }
+ relative_price, available := data.Planets[planet].RelativePrices[commodity]
+ if !available {
+ // TODO: Dump cargo
+ continue
+ }
+ base_price := data.Commodities[commodity].BasePrice
+ absolute_price := float64(base_price) * float64(relative_price) / 100.0
+ sell_price := int(absolute_price * 0.9)
+
+ for other[UnusedCargo] = 0; other[UnusedCargo] < dims[UnusedCargo]; other[UnusedCargo]++ {
+ quantity := *hold - (other[UnusedCargo] + other[Cloaks] + other[Edens])
+ sale_value := quantity * sell_price
+ Consider(data, dims, table, other, sale_value, &best_value, best_source)
+ }
+ }
+ other[UnusedCargo] = addr[UnusedCargo]
+ other[Hold] = addr[Hold]
+ }
+
+ /* Buy */
+ other[Traded] = addr[Traded] /* Buy after selling */
+ if addr[Hold] != 0 {
+ commodity := data.i2c[addr[Hold]]
+ if data.Commodities[commodity].CanSell {
+ relative_price, available := data.Planets[planet].RelativePrices[commodity]
+ if available {
+ base_price := data.Commodities[commodity].BasePrice
+ absolute_price := int(float64(base_price) * float64(relative_price) / 100.0)
+ quantity := *hold - (addr[UnusedCargo] + addr[Cloaks] + addr[Edens])
+ total_price := quantity * absolute_price
+ other[Hold] = 0
+ other[UnusedCargo] = 0
+ Consider(data, dims, table, other, -total_price, &best_value, best_source)
+ other[UnusedCargo] = addr[UnusedCargo]
+ other[Hold] = addr[Hold]
+ }
+ }
+ }
+ }
+ other[Traded] = addr[Traded]
+ }
+
+ /* 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 */
+ for i := uint(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 != VALUE_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&0xfff == 0 {
+ print(fmt.Sprintf("\r%3.1f%%", 100*float64(cell_filled_count)/float64(StateTableSize(dims))))
+ }
+
+ return table[my_index].value
+}
+
+func FinalState(dims []int) []int {
+ 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
+ // Fuel and Location are determined by FindBestState
+ return addr
+}
+
+func FindBestState(data planet_data, dims []int, table []State, addr []int) int32 {
+ max_index := int32(-1)
+ max_value := 0.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]++ {
+ planet := data.i2p[addr[Location]]
+ if len(end()) == 0 || end()[planet] {
+ index := EncodeIndex(dims, addr)
+ today_value := CellValue(data, dims, table, addr)
+ tomorrow_value := *tomorrow_weight * float64(*hold+data.Planets[planet].TomorrowValue)
+ value := float64(today_value) + tomorrow_value
+ if value > max_value {
+ max_value = value
+ max_index = index
+ }
+ }
+ }
+ }
+ return max_index
+}
+
+func Commas(n int32) (s string) {
+ if n < 0 {
+ panic(n)
+ }
+ 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 FighterAndShieldCost(data planet_data, dims []int, table []State, best int32) {
+ if *drones == 0 && *batteries == 0 {
+ return
+ }
+ fmt.Println()
+ if *drones > 0 {
+ final_state := FinalState(dims)
+ final_state[BuyFighters] = 0
+ alt_best := FindBestState(data, dims, table, final_state)
+ cost := table[alt_best].value - table[best].value
+ fmt.Println("\rDrones were", float64(cost)/float64(*drones), "each")
+ }
+ if *batteries > 0 {
+ final_state := FinalState(dims)
+ final_state[BuyShields] = 0
+ alt_best := FindBestState(data, dims, table, final_state)
+ cost := table[alt_best].value - table[best].value
+ fmt.Println("\rBatteries were", float64(cost)/float64(*batteries), "each")
+ }
+}
+
+func EndEdensCost(data planet_data, dims []int, table []State, best int32) {
+ if *end_edens == 0 {
+ return
+ }
+ fmt.Println()
+ final_state := FinalState(dims)
+ for extra_edens := 1; extra_edens <= *end_edens; extra_edens++ {
+ final_state[Edens] = *end_edens - extra_edens
+ alt_best := FindBestState(data, dims, table, final_state)
+ extra_funds := table[alt_best].value - table[best].value
+ fmt.Println("\rUse", extra_edens, "extra edens, make an extra",
+ Commas(extra_funds), "(",
+ Commas(extra_funds/int32(extra_edens)), "per eden)")
+ }
+}
+
+func VisitCost(data planet_data, dims []int, table []State, best int32) {
+ if dims[Visit] == 1 {
+ return
+ }
+ fmt.Println()
+ final_state := FinalState(dims)
+ for i := uint(0); i < uint(len(visit())); i++ {
+ all_bits := dims[Visit] - 1
+ final_state[Visit] = all_bits & ^(1 << i)
+ alt_best := FindBestState(data, dims, table, final_state)
+ cost := table[alt_best].value - table[best].value
+ fmt.Printf("\r%11v Cost to visit %v\n", Commas(cost), visit()[i])