# -*- coding: utf-8 -*-
#
# GAで8-Queenを解く!
#
class Queens
POPULATION = 1000
attr_reader :solution
def randomgene
(0...8).collect {
rand(8)
}
end
def initialize
@genes = []
POPULATION.times {
@genes << randomgene
}
File.delete("average.log") if File.exist?("average.log")
File.delete("best.log") if File.exist?("best.log")
end
def evaluateone(gene)
collisions = 0
v = {}
(0...8).each { |i|
collisions += 1 if v[gene[i]]
v[gene[i]] =
}
v = {}
(0...8).each { |i|
collisions += 1 if v[i+gene[i]]
v[i+gene[i]] =
}
v = {}
(0...8).each { |i|
collisions += 1 if v[i-gene[i]]
v[i-gene[i]] =
}
if collisions == 0 then
@solution = gene
end
# 1.0 / (1.0 + collisions)
collisions
end
def evaluate
@val = []
@totalval = 0.0
totalcollisions = 0.0
best = 100.0
(0...POPULATION).each { |i|
collisions = evaluateone(@genes[i])
@val[i] = 1.0 / (1.0 + collisions)
@totalval += @val[i]
totalcollisions += collisions
best = collisions if collisions < best
}
File.open("average.log","a"){ |f|
f.puts totalcollisions.to_f / POPULATION
}
File.open("best.log","a"){ |f|
f.puts best.to_f
}
end
def selectone
r = rand(10000) / 10000.0
v = 0.0
(0...POPULATION).each { |i|
if r >= v && r < v + @val[i] / @totalval then
return @genes[i].dup
end
v += @val[i] / @totalval
}
end
def dump
(0..10).each { |i|
puts @genes[i].join(' ')
}
puts "totalval = #{@totalval}"
end
def calc
newgenes = []
while newgenes.length < POPULATION do
if rand(10000) < 6000 then # 交叉
a = selectone
b = selectone
p1 = rand(8)
p2 = rand(8)
if p2 < p1 then
tmp = p2
p2 = p1
p1 = tmp
end
(p1..p2).each { |i|
tmp = a[i]
a[i] = b[i]
b[i] = tmp
}
newgenes << a
newgenes << b
elsif rand(10000) < 600 then # 突然変異
a = selectone
a[rand(8)] = rand(8)
newgenes << a
else
newgenes << selectone
end
end
@genes = newgenes
end
end
queens = Queens.new
while true do
queens.evaluate
queens.dump
queens.calc
break if queens.solution
end
(0...8).each { |i|
s = (0...8).collect { '.' }
s[queens.solution[i]] = 'Q'
puts s.join(' ')
}