#!/usr/bin/ruby -w # # == Synopsis # # Play one move of a Cartagena game # # == Usage # CGI script # # == Author # Neil Smith require 'libcartagena' 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 = { 'First Possible' => '/var/www/scripts.njae.me.uk/cartagena/robots/1', 'Random' => '/var/www/scripts.njae.me.uk/cartagena/robots/2' } $ROBOT_CODE_TABLE = { '1' => '/var/www/scripts.njae.me.uk/cartagena/robots/1', '2' => '/var/www/scripts.njae.me.uk/cartagena/robots/2' } # How long the robot has to respond $ROBOT_TIMEOUT = 15 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 = Game.read_game(cgi['history'].downcase.split("\n")) 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 += game.board.positions.collect {|p| p.symbol.to_s}.join("\n") + "\n" robot_input += (moves.collect {|m| m.format(game.board, true)}).join("\n") + "\n" if not moves.empty? robot_input += (game.current_player + 1).to_s + "\n" robot_input += game.players_cards[game.current_player].collect {|c| c.to_s}.join("\n") + "\n" if not game.players_cards[game.current_player].empty? # 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, true) 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