# Civ4/integration question and practice for the golfers

**URL:** <https://www.ruby-forum.com/t/civ4-integration-question-and-practice-for-the-golfers/74742>\
**Category:** Ruby\
**Created:** [November 7, 2006, 10:54am UTC](https://www.ruby-forum.com/t/civ4-integration-question-and-practice-for-the-golfers/74742 "2006-11-07T10:54:52Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![spooq](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/58956e/32.png) [@spooq](https://www.ruby-forum.com/u/spooq)\
**Post date:** [November 7, 2006, 10:54am UTC](https://www.ruby-forum.com/t/civ4-integration-question-and-practice-for-the-golfers/74742/1 "2006-11-07T10:54:52Z")

</div>

For reasons not clear even to myself, I’m trying to predict the growth  
and  
production of a city in CivIV (c.f. CivFanatics  
[http://www.civfanatics.com](http://www.civfanatics.com)  
).

Each city has an integer population and a number of tiles (actually 20  
but  
reduced here to 10 to speed-up testing). Each population point (P) can  
work  
one tile in a given turn. Tiles have three attributes excitingly named  
F, G and H. I am attempting to enumerate all interesting combinations  
of worked tiles for any given city size. Output is in gnuplot format.

Here’s the code (fore!).

puts “Starting #{Time.now}”

numArray = (1…10).to\_a

# Generate tiles

tiles = numArray.inject([]) { |acc, node| acc + [[rand(4),rand(4),  
rand(4)]]  
}

# Generate unique combinations for given size

File::open(“output.txt”, “w”) { |file|  
file \<\< “#P F G H\n”  
numArray.inject([[]]) { |acc, node|  
acc.inject([]) { |acc, injectedNodes| acc + [injectedNodes,  
injectedNodes + [node]] }  
}.collect { |c|  
c.inject([0,0,0,0]) { |acc, node| [acc[0].succ, acc[1] +  
tiles[node-1][0], acc[2] + tiles[node-1][1], acc[3] + tiles[node-1][2]]  
}  
}.uniq.sort.inject(1) { |acc, node|  
file \<\< “\n” if node[0] == acc  
file \<\< " " \<\< node.join(" ") \<\< “\n”  
node[0] == acc ? acc.succ : acc  
}  
}

puts “Finished #{Time.now}”

My problem is ensuring that only efficient combinations are output. If  
we  
look at a doctored example…

#P A B C  
0 0 0 0

1 0 0 0  
1 2 0 0 ← This is not interesting,  
1 2 0 3 ← when this is possible.  
1 0 1 0 ← However this still is, even though A+B+C is less  
than  
the line above.

Can anyone suggest a nice golfed algorithm to get rid of the useless  
combinations? Remember that any of the three resources might be deemed  
most  
important, e.g. 1 1 0 0 is still interesting when 1 0 9 9 exists.

When this bit gets nailed down, the next step is integrating  
permutations of  
combinations over time and solving for maximum G and/or H, given that  
acquiring enough F will increase P. It’s probably best to assume no  
micro-management, i.e. when a city grows, the combination chosen for the  
new  
size remains in place until the next growth.

Thanks for getting this far, all comments welcome.

---

<div class="post-metadata">

**Author:** ![spooq](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/58956e/32.png) [@spooq](https://www.ruby-forum.com/u/spooq)\
**Post date:** [November 7, 2006, 10:59am UTC](https://www.ruby-forum.com/t/civ4-integration-question-and-practice-for-the-golfers/74742/2 "2006-11-07T10:59:24Z")

</div>

Not sure if anyone’s reading this, but here’s where I’m at now.  
Permutations are generated and selected for each resource.

# Warning! Running time is sensitive to changes in this number.

NumberOfTilesPerCity = 6

puts “Starting #{Time.now}”

# Generate tiles

NumArray = (1…NumberOfTilesPerCity).to\_a  
tiles = NumArray.inject([]) { |acc, node| acc + [[rand(4),rand(4),  
rand(4)]] }

# Calc food required to achieve a pop size

def inc(size)  
10 \* 2 \*\* size - 20 # Or similar  
end

# Given a total amount of food, calc current size

def currentSize(food)  
s = 1  
s += 1 while food \> inc(s)  
s  
end

# Generate combinations

Combinations = NumArray.inject([[]]) { |acc, node| # Combinations (ints)  
acc.inject([]) { |acc, injectedNodes| acc + [injectedNodes,  
injectedNodes + [node]] }  
}.map { |c|  
c.inject([0,2,1,2]) { |acc, node| # Combinations (tiles)  
(0…2).inject([acc[0].succ]) { |i,n| i + [acc[n.succ] +  
tiles[node-1][n]] }  
}  
}.uniq.sort.inject([]) { |acc, node| # Tranches  
acc + [acc.size \<= node[0] ? [node] : acc.pop + [node]]  
}.each { |set|  
set.delete\_if { |test| # Prune  
set.inject(false) { |acc, comp|  
acc or (!test.equal?(comp) and ((1…3).inject(true) { |i,n| test[n]  
\<= comp[n] and i } and acc = true))  
}  
}  
}

# Generate permutations

class Array  
def permute(i = 0, \*a)  
return [a] if i == size  
self[i].map { |x| permute(i+1, \*(a + [x])) }.inject([]) { |m,x| m + x  
}  
end  
end  
Permutations = Combinations.permute

# Containers to store results

EmptyResult = [0,0,0,0]  
bestResult = []  
strings = “Pop,Food,Gold,Hammers”.split(’,’)  
4.times { |x| bestResult \<\< (EmptyResult.dup \<\< strings[x]) }

# Integrate across t

PermutationResults = Permutations.map { |p|  
result = [1,0,0,0]  
80.times { |t|  
result = [currentSize(result[1])] + (1…3).to\_a.inject([]) { |i,n|  
i + [result[n] + p[result[0]][n]]  
}  
result[0] = NumArray.size if result[0] \> NumArray.size # Cap size  
}  
result  
}.inject(bestResult) { |acc, node|  
ret = acc  
(acc.size).times { |x| ret[x] = node + [ret[x][ret.size]] if node[x]

> ret[x][x] }  
> ret  
> }

# Write results to disk

File::open(“output.txt”, “w”) { |file|  
file \<\< “# Combinations\n”  
Combinations.each { |set|  
set.each { |comb|  
file \<\< " " \<\< comb.join(" ") \<\< “\n”  
}  
file \<\< “\n”  
}

```
file << "# Permutations\n"
Permutations.each { |pset|
	pset.each { |p|
		file << " " << p.join(" ") << "\n"
	}
	file << "\n"
}
file << "# Results\n"
PermutationResults.each { |res|
	file << " " << res.join(" ") << "\n"
}

```

}

puts “Finished #{Time.now}”
