From: spooq Date: 2006-11-04T04:39:34+09:00 Subject: Re: Civ4/integration question and practice for the golfers 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}" On 11/2/06, spooq wrote: > For reasons not clear even to myself, I'm trying to predict the growth and > production of a city in CivIV (c.f. CivFanatics > ). > > 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. > >