From: Ola Leifler Date: 2007-03-05T23:40:16+09:00 Subject: Re: [QUIZ] GOPS (#116) --Apple-Mail-2--622601840 Content-Type: multipart/mixed; boundary=Apple-Mail-1--622602060 --Apple-Mail-1--622602060 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; delsp=yes; format=flowed Hi! Here's my first attempt at a Ruby Quiz. It may be slight overkill, but I thought that Direct Ruby Programming (http:// drp.rubyforge.org/), a kind of evolutionary programming technique, could be useful when implementing a learning agent. It can train against others, using the supplied GOPS::Game engine. /Ola Leifler Example of a learning session: irb(main):240:0> drpbot=DRPBot.new # irb(main):241:0> drpbot.learn D, [2007-03-05T15:38:18.194945 #21885] DEBUG -- : Best draw card function after training: Proc.new do card= @cards.detect {|card| card > (if not (@played_cards).empty? then (@played_cards).min else (if not ((1..13).to_a-@competition_cards).empty? then ((1..13).to_a-@competition_cards).first else 12 end) end)} || @cards.min @played_cards << card @cards-=[card] card end.call --Apple-Mail-1--622602060 Content-Transfer-Encoding: 7bit Content-Type: text/x-ruby-script; x-unix-mode=0700; x-mac-creator=454D4178; name=drp_bot.rb Content-Disposition: attachment; filename=drp_bot.rb #!/usr/bin/env ruby require 'drp' require 'logger' require File.join(File.join(File.expand_path(File.dirname(__FILE__)), *%w[.. lib]), 'gops.rb') class Array def random_element self[rand*size] end def sum inject(0) {|sum,x|x+sum} end end class BotGenerator extend DRP::RuleEngine begin_rules # Highest def draw_card "@cards.max" end # Lowest def draw_card "@cards.min" end # A number from 1 to n def num(n) (rand*(n+1)).to_i.to_s end def array_collator %w[min max first last sum].random_element end def bin_op %w[&& ||].random_element end def op %w[== < > <= >=].random_element end def stack ["(1..13).to_a-",""].random_element+ (%w[@played_cards @competition_cards @opponent_cards].random_element) end def num_or_card s=stack "(if not (#{s}).empty? \n\t then \n\t\t(#{s}).#{array_collator}\n\t else \n\t\t#{num_or_card}\n end)" end # No matter how many cards are played, we can still compare between # a card and all possible values def num_or_card num(13) end def num_or_card "score" end def comparisons "#{comparison} #{bin_op} (#{comparisons})" end def comparisons comparison end def comparison %w[true false].random_element end # generate a condition and draw statement, with nice indentation for # debugging def select_card_exp(indent) %{#{" "*indent unless indent==2}if #{comparisons} #{" "*indent}then #{" "*(indent+1)}#{draw_card} #{" "*indent}else #{select_card_exp(indent+1)} #{" "*indent}end} end def select_card_exp(indent) (" "*indent)+draw_card end def select_card_block %{Proc.new do card=#{select_card_exp(2)} @played_cards << card @cards-=[card] card end.call} end weight 3 def comparison "#{num_or_card} #{op} #{num_or_card}" end # Function of the played cards def draw_card "@cards.detect {|card| card #{op} #{num_or_card}} || #{draw_card}" end end_rules end module GOPS class Player # Release resources so fork remains available def close_connection @bot.close end end end class DRPBot < GOPS::Player attr_reader :name, :cards def play_card(competition_card) @competition_cards << competition_card instance_eval(@draw_card_function) end def send_opponents_play(played_card) @opponent_cards << played_card end def win_card(card) @winnings << card end def score @winnings.sum end attr_accessor :draw_card_function def initialize @name = "DRP Bot" @logger = Logger.new(STDOUT) @generator=BotGenerator.new init_variables @draw_card_function=@generator.select_card_block # @logger.debug("Draw card function:\n\n#{@draw_card_function}") end def init_variables @cards=GOPS::CARDS.clone @competition_cards=[] @opponent_cards=[] @played_cards=[] @winnings=[] # @logger.debug("Current draw card function:\n#{@draw_card_function}") end def play @score=0 13.times do |i| # competition card comp_card=STDIN.gets.sub(/Competition card:\s+(\d+)/,"\1").to_i @competition_cards << comp_card my_bid=instance_eval(@draw_card_function) STDOUT.puts my_bid STDOUT.flush # opponent's bid opponent_bid=STDIN.gets.sub(/Opponent's bid:\s+(\d+)/,"\1").to_i @opponent_cards << opponent_bid @score += comp_card if my_bid > opponent_bid end @score end attr_accessor :genes_scores # Train for