# -*- 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(' ') }