-func FillStateTable2(data planet_data, dims []int, table []State,
-fuel_remaining, edens_remaining int, planet string, barrier chan<- bool) {
- /* The dimension nesting order up to this point is important.
- * Beyond this point, it's not important.
- *
- * It is very important when iterating through the Hold dimension
- * to visit the null commodity (empty hold) first. Visiting the
- * null commodity represents selling. Visiting it first gets the
- * action order correct: arrive, sell, buy, leave. Visiting the
- * null commodity after another commodity would evaluate the action
- * sequence: arrive, buy, sell, leave. This is a useless action
- * sequence. Because we visit the null commodity first, we do not
- * consider these action sequences.
- */
- eden_capacity := data.Commodities["Eden Warp Units"].Limit
- addr := make([]int, len(dims))
- addr[Edens] = edens_remaining
- addr[Fuel] = fuel_remaining
- addr[Location] = data.p2i[planet]
+/* These four fill procedures fill in the cell at address addr by
+ * looking at all the possible ways to reach this cell and selecting
+ * the best one.
+ *
+ * The other obvious implementation choice is to do this the other way
+ * around -- for each cell, conditionally overwrite all the other cells
+ * that are reachable *from* the considered cell. We choose gathering
+ * reads over scattering writes to avoid having to take a bunch of locks.
+ */
+
+func UpdateCell(table []State, here, there, value_difference int) {
+ possible_value := table[there].value + value_difference
+ if table[there].value > 0 && possible_value > table[here].value {
+ table[here].value = possible_value
+ table[here].from = there
+ }
+}
+
+func FillCellByArriving(data planet_data, dims []int, table []State, addr []int) {
+ my_index := EncodeIndex(dims, addr)
+ other := make([]int, NumDimensions)
+ copy(other, addr)
+
+ /* Travel here via a 2-fuel unit jump */
+ if addr[Fuel]+2 < dims[Fuel] {
+ other[Fuel] = addr[Fuel] + 2
+ for other[Location] = 0; other[Location] < dims[Location]; other[Location]++ {
+ UpdateCell(table, my_index, EncodeIndex(dims, other), 0)
+ }
+ other[Location] = addr[Location]
+ other[Fuel] = addr[Fuel]
+ }
+
+ /* Travel here via a hidey hole */
+ if addr[Fuel]+1 < dims[Fuel] {
+ hole_index := (dims[Fuel] - 1) - (addr[Fuel] + 1)
+ if hole_index < len(flight_plan()) {
+ other[Fuel] = addr[Fuel] + 1
+ other[Location] = data.p2i[flight_plan()[hole_index]]
+ UpdateCell(table, my_index, EncodeIndex(dims, other), 0)
+ other[Location] = addr[Location]
+ other[Fuel] = addr[Fuel]
+ }
+ }
+
+ /* Travel here via Eden Warp Unit */
+ for other[Edens] = addr[Edens] + 1; other[Edens] < dims[Edens]; other[Edens]++ {
+ for other[Location] = 0; other[Location] < dims[Location]; other[Location]++ {
+ UpdateCell(table, my_index, EncodeIndex(dims, other), 0)
+ }
+ }
+ other[Location] = addr[Location]
+ other[Edens] = addr[Edens]
+}
+
+func FillCellBySelling(data planet_data, dims []int, table []State, addr []int) {
+ if addr[Hold] > 0 {
+ // Can't sell and still have cargo
+ return
+ }
+ if addr[UnusedCargo] > 0 {
+ // Can't sell everything and still have 'unused' holds
+ return
+ }
+ my_index := EncodeIndex(dims, addr)
+ other := make([]int, NumDimensions)
+ copy(other, addr)
+ planet := data.i2p[addr[Location]]
+ for other[Hold] = 0; other[Hold] < dims[Hold]; other[Hold]++ {
+ commodity := data.i2c[other[Hold]]
+ if !data.Commodities[commodity].CanSell {
+ // TODO: Dump cargo
+ continue
+ }
+ relative_price, available := data.Planets[planet].RelativePrices[commodity]
+ if !available {
+ continue
+ }
+ base_price := data.Commodities[commodity].BasePrice
+ absolute_price := relative_price * base_price
+ sell_price := int(float64(absolute_price) * 0.9)
+
+ for other[UnusedCargo] = 0; other[UnusedCargo] < dims[UnusedCargo]; other[UnusedCargo]++ {
+
+ quantity := *hold - other[UnusedCargo] // TODO: Partial sales
+ sale_value := quantity * sell_price
+ UpdateCell(table, my_index, EncodeIndex(dims, other), sale_value)
+ }
+ }
+ other[UnusedCargo] = addr[UnusedCargo]
+}
+
+func FillCellByBuying(data planet_data, dims []int, table []State, addr []int) {
+ if addr[Hold] == 0 {
+ // Can't buy and then have nothing
+ return
+ }
+ my_index := EncodeIndex(dims, addr)
+ other := make([]int, NumDimensions)
+ copy(other, addr)
+ planet := data.i2p[addr[Location]]
+ commodity := data.i2c[addr[Hold]]
+ if !data.Commodities[commodity].CanSell {
+ return
+ }
+ relative_price, available := data.Planets[planet].RelativePrices[commodity]
+ if !available {
+ return
+ }
+ base_price := data.Commodities[commodity].BasePrice
+ absolute_price := relative_price * base_price
+ quantity := *hold - addr[UnusedCargo]
+ total_price := quantity * absolute_price
+ other[Hold] = 0
+ UpdateCell(table, my_index, EncodeIndex(dims, other), -total_price)
+}
+
+func FillCellByMisc(data planet_data, dims []int, table []State, addr []int) {
+ /* Buy Eden warp units */
+ /* Buy a Device of Cloaking */
+ /* Silly: Dump a Device of Cloaking */
+ /* Buy Fighter Drones */
+ /* Buy Shield Batteries */
+ /* Visit this planet */
+}
+
+func FillStateTable2Iteration(data planet_data, dims []int, table []State,
+addr []int, f func(planet_data, []int, []State, []int)) {
+ /* TODO: Justify the safety of the combination of this dimension
+ * iteration and the various phases f. */