#!/usr/bin/ruby -w # # == Synopsis # # Play one move of a Trap the Cap game # # == Usage # ttc [ -b | --board-size SIZE ] [ -i | --input FILE ] [ -r | --robot ROBOT ] [ -h | --help ] # # == Author # Neil Smith require 'libttc' require 'cgi' require 'open3' require 'timeout' # Prevent dangerous operations $SAFE = 1 class InvalidRobotError < StandardError end class NoInputFileError < StandardError end class InvalidMoveInHistoryError < StandardError end class GameWonInHistoryError < StandardError end # A table of the known game-playing robots $ROBOT_NAME_TABLE = { 'Always clockwise simple' => '/var/www/scripts.njae.me.uk/trap-the-cap/robots/1', 'Clockwise cloud' => '/var/www/scripts.njae.me.uk/trap-the-cap/robots/2', 'GA generation 1006' => '/var/www/scripts.njae.me.uk/trap-the-cap/robots/3' } $ROBOT_CODE_TABLE = { '1' => '/var/www/scripts.njae.me.uk/trap-the-cap/robots/1', '2' => '/var/www/scripts.njae.me.uk/trap-the-cap/robots/2', '3' => '/var/www/scripts.njae.me.uk/trap-the-cap/robots/3' } # How long the robot has to respond $ROBOT_TIMEOUT = 10 def generate_output(cgi, returned_move, annotation) if returned_move.empty? return_part = "" else return_part = cgi.p { "Result is: " } + "\n" + cgi.h1 { returned_move } + "\n" end if annotation.empty? annotation_part = "" else annotation_part = cgi.p { annotation } end cgi.html { cgi.head { "\n" + cgi.title{"Move result"} } + "\n" + cgi.body { return_part + annotation_part } } end begin cgi = CGI.new("html4") chosen_robot = cgi['robot'] if $ROBOT_NAME_TABLE.has_key? chosen_robot chosen_robot_dir = $ROBOT_NAME_TABLE[chosen_robot] chosen_robot_dir.untaint else raise InvalidRobotError, "#{chosen_robot} is not a valid robot code" end begin game, moves, next_roll = Game.read_game(cgi['moves'].downcase.split("\n")) game.apply_moves! moves rescue InvalidMoveError => error raise(InvalidMoveInHistoryError, error.message) rescue GameWonNotice => error raise(GameWonInHistoryError, error.message) end current_directory = Dir.pwd current_directory.untaint Dir.chdir chosen_robot_dir returned_move = "" returned_error = "" robot_input = game.players.length.to_s + "\n" robot_input += (moves.collect {|m| m.to_s}).join("\n") + "\n" if not moves.empty? robot_input += next_roll.to_s # cgi.out { generate_output(cgi, "", "passing robot #{game.players.length.to_s + "#" + (moves.collect {|m| m.to_s}).join('!\n!') + "#" + next_roll.to_s}!") } # cgi.out { generate_output(cgi, "", "passing robot #{robot_input}!") } Timeout.timeout($ROBOT_TIMEOUT + 1) do Open3.popen3('./runme') do |robot_in, robot_out, robot_err| robot_in << robot_input robot_in.close_write returned_move = robot_out.gets returned_error = robot_err.gets end end Dir.chdir current_directory # cgi.out { generate_output(cgi, "", "Returned move #{returned_move}; robot error was #{returned_error}!") } raise(InvalidMoveError, "Robot returned error '#{returned_error}'") if returned_error != nil raise(InvalidMoveError, "Null move") if returned_move.nil? or returned_move.empty? next_move = returned_move.chomp.to_move(game) game.apply_move! next_move # cgi.out { generate_output(cgi, "", "Applied move #{returned_move}!") } cgi.out { generate_output(cgi, returned_move, "") } rescue InvalidMoveInHistoryError => error cgi.out { generate_output(cgi, "", "Invalid move in history: #{error}") } # puts "Invalid move in history: #{error}" rescue GameWonInHistoryError => error cgi.out { generate_output(cgi, "", "Game already won in historic moves: #{error}") } # puts "Game already won in historic moves: #{error}" rescue InvalidMoveError => error cgi.out { generate_output(cgi, "", "Robot returned invalid move: #{error}") } # puts "Robot returned invalid move: #{error}" rescue GameWonNotice => error cgi.out { generate_output(cgi, returned_move, "Game won: #{error}") } # puts "Robot returned #{returned_move}" # puts "Game won: #{error}" rescue InvalidRobotError => error cgi.out { generate_output(cgi, "", "Invalid robot selection: #{error}") } # puts "Invalid robot selection: #{error}" rescue Timeout::Error => error cgi.out { generate_output(cgi, "", "Robot timed out") } # puts "Robot timeout: #{error}" end