Initial commit
[trapthecap.git] / src / cgi-files / ttc-simple.rb
1 #!/usr/bin/ruby -w
2 #
3 # == Synopsis
4 #
5 # Play one move of a Trap the Cap game
6 #
7 # == Usage
8 # ttc [ -b | --board-size SIZE ] [ -i | --input FILE ] [ -r | --robot ROBOT ] [ -h | --help ]
9 #
10 # == Author
11 # Neil Smith
12
13 require 'libttc'
14 require 'cgi'
15 require 'open3'
16 require 'timeout'
17
18 # Prevent dangerous operations
19 $SAFE = 1
20
21 class InvalidRobotError < StandardError
22 end
23
24 class NoInputFileError < StandardError
25 end
26
27 class InvalidMoveInHistoryError < StandardError
28 end
29
30 class GameWonInHistoryError < StandardError
31 end
32
33
34 # A table of the known game-playing robots
35
36 $ROBOT_NAME_TABLE = {
37 'Always clockwise simple' => '/var/www/scripts.njae.me.uk/trap-the-cap/robots/1',
38 'Clockwise cloud' => '/var/www/scripts.njae.me.uk/trap-the-cap/robots/2',
39 'GA generation 1006' => '/var/www/scripts.njae.me.uk/trap-the-cap/robots/3'
40 }
41
42 $ROBOT_CODE_TABLE = {
43 '1' => '/var/www/scripts.njae.me.uk/trap-the-cap/robots/1',
44 '2' => '/var/www/scripts.njae.me.uk/trap-the-cap/robots/2',
45 '3' => '/var/www/scripts.njae.me.uk/trap-the-cap/robots/3'
46 }
47
48
49 # How long the robot has to respond
50 $ROBOT_TIMEOUT = 10
51
52
53 def generate_output(cgi, returned_move, annotation)
54 if returned_move.empty?
55 return_part = ""
56 else
57 return_part = cgi.p { "Result is: " } + "\n" + cgi.h1 { returned_move } + "\n"
58 end
59
60 if annotation.empty?
61 annotation_part = ""
62 else
63 annotation_part = cgi.p { annotation }
64 end
65
66 cgi.html {
67 cgi.head { "\n" + cgi.title{"Move result"} } + "\n" +
68 cgi.body { return_part + annotation_part }
69 }
70 end
71
72
73 begin
74
75 cgi = CGI.new("html4")
76
77 chosen_robot = cgi['robot']
78 if $ROBOT_NAME_TABLE.has_key? chosen_robot
79 chosen_robot_dir = $ROBOT_NAME_TABLE[chosen_robot]
80 chosen_robot_dir.untaint
81 else
82 raise InvalidRobotError, "#{chosen_robot} is not a valid robot code"
83 end
84
85 begin
86 game, moves, next_roll = Game.read_game(cgi['moves'].downcase.split("\n"))
87 game.apply_moves! moves
88 rescue InvalidMoveError => error
89 raise(InvalidMoveInHistoryError, error.message)
90 rescue GameWonNotice => error
91 raise(GameWonInHistoryError, error.message)
92 end
93
94 current_directory = Dir.pwd
95 current_directory.untaint
96 Dir.chdir chosen_robot_dir
97
98 returned_move = ""
99 returned_error = ""
100 robot_input = game.players.length.to_s + "\n"
101 robot_input += (moves.collect {|m| m.to_s}).join("\n") + "\n" if not moves.empty?
102 robot_input += next_roll.to_s
103
104 # cgi.out { generate_output(cgi, "", "passing robot #{game.players.length.to_s + "#" + (moves.collect {|m| m.to_s}).join('!\n!') + "#" + next_roll.to_s}!") }
105 # cgi.out { generate_output(cgi, "", "passing robot #{robot_input}!") }
106
107
108 Timeout.timeout($ROBOT_TIMEOUT + 1) do
109 Open3.popen3('./runme') do |robot_in, robot_out, robot_err|
110 robot_in << robot_input
111 robot_in.close_write
112 returned_move = robot_out.gets
113 returned_error = robot_err.gets
114 end
115 end
116
117 Dir.chdir current_directory
118
119 # cgi.out { generate_output(cgi, "", "Returned move #{returned_move}; robot error was #{returned_error}!") }
120
121 raise(InvalidMoveError, "Robot returned error '#{returned_error}'") if returned_error != nil
122 raise(InvalidMoveError, "Null move") if returned_move.nil? or returned_move.empty?
123 next_move = returned_move.chomp.to_move(game)
124 game.apply_move! next_move
125
126 # cgi.out { generate_output(cgi, "", "Applied move #{returned_move}!") }
127 cgi.out { generate_output(cgi, returned_move, "") }
128
129 rescue InvalidMoveInHistoryError => error
130 cgi.out { generate_output(cgi, "", "Invalid move in history: #{error}") }
131 # puts "Invalid move in history: #{error}"
132 rescue GameWonInHistoryError => error
133 cgi.out { generate_output(cgi, "", "Game already won in historic moves: #{error}") }
134 # puts "Game already won in historic moves: #{error}"
135
136 rescue InvalidMoveError => error
137 cgi.out { generate_output(cgi, "", "Robot returned invalid move: #{error}") }
138 # puts "Robot returned invalid move: #{error}"
139 rescue GameWonNotice => error
140 cgi.out { generate_output(cgi, returned_move, "Game won: #{error}") }
141 # puts "Robot returned #{returned_move}"
142 # puts "Game won: #{error}"
143
144 rescue InvalidRobotError => error
145 cgi.out { generate_output(cgi, "", "Invalid robot selection: #{error}") }
146 # puts "Invalid robot selection: #{error}"
147 rescue Timeout::Error => error
148 cgi.out { generate_output(cgi, "", "Robot timed out") }
149 # puts "Robot timeout: #{error}"
150
151 end