swint 0.5 → 0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +22 -4
- data/README +31 -62
- data/Rakefile +17 -3
- data/bin/swint +15 -71
- data/lib/{swint_basics/array.rb → array.rb} +8 -0
- data/lib/swint/abstract_robot.rb +9 -0
- data/lib/swint/class_robot.rb +12 -0
- data/lib/swint/field.rb +4 -4
- data/lib/swint/game.rb +149 -120
- data/lib/swint/map.rb +67 -54
- data/lib/swint/xmlrpc_robot.rb +12 -0
- data/lib/swint_exec/ascii_to_map.rb +40 -0
- data/lib/swint_exec/race.rb +74 -0
- data/lib/swint_exec/tournament.rb +78 -0
- metadata +14 -12
- data/lib/swint/robot.rb +0 -125
- data/lib/swint_basics/hash.rb +0 -11
data/CHANGELOG
CHANGED
@@ -1,7 +1,25 @@
|
|
1
|
-
2008-
|
2
|
-
|
1
|
+
2008-02-02 v0.6 features
|
2
|
+
|
3
|
+
* README rewritten
|
4
|
+
* swint executable now requires a subcommand, on of
|
5
|
+
'race', 'asc2map'
|
6
|
+
* some refactorization
|
7
|
+
* -n flag removed
|
8
|
+
* 'push_object'-feature implemented
|
9
|
+
* 'shout'- and listen'-feature implemented, not tested though
|
10
|
+
* swint now is a rubyforge project, see
|
11
|
+
http://rubyforge.org/projects/swint
|
12
|
+
* swint now comes with a simple 'asc2map' converter
|
13
|
+
* -t also turns on the flags-feature for visual marks on the map
|
14
|
+
* -r http://localhost:1234/ may be abbreviated to -r 1234
|
15
|
+
|
16
|
+
2008-01-17 v0.5 features and fixes
|
17
|
+
|
18
|
+
* swint now is a ruby gem
|
3
19
|
* -e und -c to require and use a ruby robot class
|
4
|
-
|
20
|
+
for debugging and profiling purposes
|
21
|
+
* map rotation fix
|
22
|
+
* -w fix
|
5
23
|
|
6
24
|
2008-01-14 v0.4 features
|
7
25
|
|
@@ -16,7 +34,7 @@
|
|
16
34
|
|
17
35
|
2008-01-06 v0.2 lots of minor improvements
|
18
36
|
|
19
|
-
* less flickering
|
37
|
+
* less flickering (through ncurses binary tput)
|
20
38
|
* use -s to see every step
|
21
39
|
* use -w to wait for input each step
|
22
40
|
|
data/README
CHANGED
@@ -1,80 +1,49 @@
|
|
1
|
-
|
1
|
+
(c) 2008-02-02 Philipp Hofmann <phil@s126.de>
|
2
2
|
================================================================================
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
(c) 2008-01-07 Philipp Hofmann <phil@s126.de>
|
3
|
+
__ __
|
4
|
+
.-----.--.--.--.|__|.-----.| |_
|
5
|
+
|__ --| | | || || || _|
|
6
|
+
|_____|________||__||__|__||____|
|
7
|
+
|
9
8
|
================================================================================
|
10
9
|
|
11
|
-
|
12
|
-
programming game originally created by Stefan Schwarzburg
|
10
|
+
_swint_ is an entirely in Ruby written client for the Swarm Intelligence
|
11
|
+
programming game originally created by Stefan Schwarzburg.
|
12
|
+
|
13
13
|
|
14
14
|
Usage:
|
15
15
|
|
16
|
-
|
16
|
+
swint race [options]
|
17
|
+
swint asc2map <filename>
|
17
18
|
|
18
19
|
|
19
20
|
Options:
|
20
21
|
|
21
|
-
-r|--robot <uri>
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
-
|
32
|
-
|
33
|
-
visualize each step, not only each turn
|
34
|
-
|
35
|
-
|
36
|
-
-w|--wait
|
37
|
-
|
38
|
-
wait for input before each step
|
39
|
-
|
40
|
-
|
41
|
-
-v|--no-visual
|
42
|
-
|
43
|
-
turn off visuals
|
44
|
-
|
45
|
-
|
46
|
-
-t|--test
|
47
|
-
|
48
|
-
turn off the initial rotation of map (better for testing)
|
49
|
-
|
50
|
-
|
51
|
-
-n|--n-times <times>
|
52
|
-
|
53
|
-
play more than one game
|
54
|
-
|
55
|
-
|
56
|
-
-i|--statistics
|
57
|
-
|
58
|
-
display statistics
|
59
|
-
|
60
|
-
|
61
|
-
-e|--require <file>
|
62
|
-
|
63
|
-
require a ruby file
|
64
|
-
|
65
|
-
|
66
|
-
-c|--class
|
22
|
+
-r|--robot <uri> supply a URL to your robot's XMLRPC
|
23
|
+
interface here, may be used repeatedly
|
24
|
+
-m|--map <filename> supply a filename to the XML map of the game
|
25
|
+
-s|--step visualize each step, not only each turn
|
26
|
+
-w|--wait wait for input before each step
|
27
|
+
-v|--no-visual turn off visuals
|
28
|
+
-t|--test turn off the initial rotation of map
|
29
|
+
(better for testing)
|
30
|
+
-i|--statistics display timing statistics
|
31
|
+
-e|--require <file> require a ruby file
|
32
|
+
-c|--class add a ruby robot class as player
|
67
33
|
|
68
|
-
add a ruby robot class as player
|
69
34
|
|
35
|
+
Examples:
|
70
36
|
|
71
|
-
|
37
|
+
A quick race on example.map
|
38
|
+
$ swint race -r 8000 -r 8001 -i
|
72
39
|
|
73
|
-
|
40
|
+
Testing your bot
|
41
|
+
$ swint race -r 8000 -s -t -m another.map
|
74
42
|
|
75
|
-
|
43
|
+
Converting an ascii-map to xml-map
|
44
|
+
$ swint asc2map ascii.map > xml.map
|
76
45
|
|
77
|
-
For testing your bot:
|
78
46
|
|
79
|
-
|
47
|
+
See Also:
|
80
48
|
|
49
|
+
Project Hompage: http://branch14.org/swint
|
data/Rakefile
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
Gem::manage_gems
|
3
|
+
|
4
|
+
################################################################################
|
5
|
+
|
6
|
+
require 'spec/rake/spectask'
|
7
|
+
|
8
|
+
desc "Run all examples with RCov"
|
9
|
+
Spec::Rake::SpecTask.new('examples_with_rcov') do |t|
|
10
|
+
t.spec_files = FileList['examples/**/*.rb']
|
11
|
+
t.rcov = true
|
12
|
+
t.rcov_opts = ['--exclude', 'examples']
|
13
|
+
end
|
14
|
+
|
15
|
+
################################################################################
|
16
|
+
|
3
17
|
require 'rake/gempackagetask'
|
4
18
|
|
5
19
|
spec = Gem::Specification.new do |s|
|
@@ -7,7 +21,7 @@ spec = Gem::Specification.new do |s|
|
|
7
21
|
# REQUIRED
|
8
22
|
|
9
23
|
s.name = "swint"
|
10
|
-
s.version = "0.
|
24
|
+
s.version = "0.6"
|
11
25
|
s.summary = "a console client for the swarm intelligence programming game"
|
12
26
|
|
13
27
|
# REQUIRED AND SET BY DEFAULT
|
@@ -37,7 +51,8 @@ spec = Gem::Specification.new do |s|
|
|
37
51
|
# s.has_rdoc = false
|
38
52
|
# s.rdoc_options = []
|
39
53
|
# s.required_ruby_version = '> 0.0.0'
|
40
|
-
|
54
|
+
s.requirements << 'tput binary from ncurses'
|
55
|
+
s.requirements << "swarm intelligence maps, see #{s.homepage}"
|
41
56
|
# s.test_files = []
|
42
57
|
# s.dependencies = []
|
43
58
|
# s.add_dependency('log4r', '>= 1.0.5')
|
@@ -56,4 +71,3 @@ end
|
|
56
71
|
task :default => "pkg/#{spec.name}-#{spec.version}.gem" do
|
57
72
|
puts "generated latest version"
|
58
73
|
end
|
59
|
-
|
data/bin/swint
CHANGED
@@ -1,75 +1,19 @@
|
|
1
1
|
#! /usr/bin/env ruby
|
2
2
|
#-*- coding: utf-8 -*-
|
3
3
|
|
4
|
-
# (c) 2008-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
require '
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
require 'swint/_constants'
|
21
|
-
require 'swint/game'
|
22
|
-
require 'swint/map'
|
23
|
-
require 'swint/field'
|
24
|
-
require 'swint/result'
|
25
|
-
require 'swint/abstract_robot'
|
26
|
-
require 'swint/xmlrpc_robot'
|
27
|
-
require 'swint/class_robot'
|
28
|
-
|
29
|
-
##############################
|
30
|
-
|
31
|
-
config = OpenStruct.new
|
32
|
-
config.step = false
|
33
|
-
config.wait = false
|
34
|
-
config.visual = true
|
35
|
-
config.map = 'example.map'
|
36
|
-
config.robots = []
|
37
|
-
config.ntimes = 1
|
38
|
-
config.statistics = false
|
39
|
-
|
40
|
-
opts = OptionParser.new do |o|
|
41
|
-
o.on('-r', '--robot URI', 'URI of robot') { |r| config.robots << r }
|
42
|
-
o.on('-m', '--map URI', 'URI of map') { |m| config.map = m }
|
43
|
-
o.on('-s', '--step', 'Show each step') { config.step = true }
|
44
|
-
o.on('-w', '--wait', 'Wait for return after visual') { config.wait = true }
|
45
|
-
o.on('-v', '--no-visual', 'No visual at all') { config.visual = false }
|
46
|
-
o.on('-t', '--test', 'Do not rotate map') { config.test = true }
|
47
|
-
o.on('-n', '--n-times TIMES', 'Run n games') { |n| config.ntimes = n.to_i }
|
48
|
-
o.on('-i', '--statistics', 'Display statistics') { config.statistics = true }
|
49
|
-
o.on('-e', '--require FILENAME', 'Provide a file to require') { |e| require(e) }
|
50
|
-
o.on('-c', '--class CLASS', 'Provide a Ruby Robot Class') { |c| config.robots << Kernel.const_get(c) }
|
4
|
+
# (c) 2008-02-02 Philipp Hofmann <phil@s126.de>
|
5
|
+
|
6
|
+
args = ARGV
|
7
|
+
case args.shift.to_sym
|
8
|
+
when :race
|
9
|
+
require 'swint_exec/race'
|
10
|
+
SwintExec::Race::start(args)
|
11
|
+
when :tournament
|
12
|
+
require 'swint_exec/tournament'
|
13
|
+
SwintExec::Tournament::start(args)
|
14
|
+
when :asc2map
|
15
|
+
require 'swint_exec/ascii_to_map'
|
16
|
+
SwintExec::AsciiToMap::start(args)
|
17
|
+
else
|
18
|
+
puts 'unkown command (valid commands: race, tournament, asc2map)'
|
51
19
|
end
|
52
|
-
|
53
|
-
opts.parse!(ARGV)
|
54
|
-
|
55
|
-
Swint.rotate_map! unless config.test
|
56
|
-
|
57
|
-
unless File.exist?(config.map)
|
58
|
-
puts "mapfile #{config.map} not found"
|
59
|
-
exit
|
60
|
-
end
|
61
|
-
|
62
|
-
config.ntimes.times do
|
63
|
-
game = Swint::Game.new(config)
|
64
|
-
result = game.run
|
65
|
-
puts "winner after % 3s rounds robot %s" % [result.rounds, result.winner]
|
66
|
-
if config.statistics
|
67
|
-
puts "\ntiming statistics\n-----------------"
|
68
|
-
puts "game took %5.2f seconds" % result.time
|
69
|
-
result.data.each do |r, d|
|
70
|
-
time = 0
|
71
|
-
d[:times].each { |t| time += t }
|
72
|
-
puts "% 5.2f seconds %s (%s)" % [time, d[:robot].name, d[:robot].owner]
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
data/lib/swint/abstract_robot.rb
CHANGED
data/lib/swint/class_robot.rb
CHANGED
data/lib/swint/field.rb
CHANGED
@@ -9,16 +9,16 @@ module Swint
|
|
9
9
|
|
10
10
|
class Field
|
11
11
|
|
12
|
-
attr_accessor :robot
|
12
|
+
attr_accessor :robot, :weight
|
13
13
|
attr_reader :pos
|
14
14
|
|
15
|
-
def initialize(s, pos)
|
16
|
-
@pos, @state = pos, s
|
15
|
+
def initialize(s, pos, weight=nil)
|
16
|
+
@pos, @state, @weight = pos, s, weight
|
17
17
|
@robot = false
|
18
18
|
end
|
19
19
|
|
20
20
|
def state
|
21
|
-
@robot ? :robot : @state
|
21
|
+
@robot ? :robot : (@weight ? :object : @state)
|
22
22
|
end
|
23
23
|
|
24
24
|
end
|
data/lib/swint/game.rb
CHANGED
@@ -1,129 +1,158 @@
|
|
1
1
|
#! /usr/bin/env ruby
|
2
|
-
#-*- coding:
|
2
|
+
#-*- coding:utf-8 -*-
|
3
3
|
|
4
4
|
# (c) 2008-01-14 Philipp Hofmann <phil@s126.de>
|
5
5
|
|
6
6
|
module Swint
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
def run
|
24
|
-
system "clear" if @config.visual
|
25
|
-
@robots.shuffle!
|
26
|
-
counter = 0
|
27
|
-
@result.start = Time.now
|
28
|
-
until @game_end
|
29
|
-
counter += 1
|
30
|
-
no_robot_left = true
|
31
|
-
@robots.each do |k, r|
|
32
|
-
r.speed.times do |step|
|
33
|
-
if !@game_end
|
34
|
-
answer = :do_nothing
|
35
|
-
dt = measure { answer = r.next(@map) } if r.has_energy?
|
36
|
-
case answer
|
37
|
-
|
38
|
-
when :move_to
|
39
|
-
no_robot_left = false
|
40
|
-
if r.use_energy?
|
41
|
-
dir = nil
|
42
|
-
dt += measure { dir = r.move }
|
43
|
-
npos = r.pos.add(DIRV[dir])
|
44
|
-
nstate = @map.state_of_field(npos)
|
45
|
-
if nstate==:goal
|
46
|
-
@robots.each { |key, b| b.end_game( (b==r) ? 'winner' : 'looser' ) }
|
47
|
-
@result.winner = k
|
48
|
-
@game_end = true
|
49
|
-
end
|
50
|
-
if [:free, :energy, :start].include?(nstate)
|
51
|
-
f, p = @map.fields[npos], @map.fields[r.pos]
|
52
|
-
r.restore if f.state==:energy
|
53
|
-
p.robot = false
|
54
|
-
f.robot = true
|
55
|
-
r.pos = npos
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
when :push_object
|
60
|
-
no_robot_left = false
|
61
|
-
if r.use_energy?
|
62
|
-
dir = nil
|
63
|
-
dt += measure { dir = r.push }
|
64
|
-
opos = r.pos.add(DIRV[dir])
|
65
|
-
ppos = opos.add(DIRV[dir])
|
66
|
-
ostate = @map.state_of_field(opos)
|
67
|
-
pstate = @map.state_of_field(ppos)
|
68
|
-
|
69
|
-
if pstate==:free
|
70
|
-
if ostate==:object
|
71
|
-
# ...
|
72
|
-
end
|
73
|
-
if ostate==:robot
|
74
|
-
# ...
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
end
|
81
|
-
|
82
|
-
@result.step(k, dt || 0)
|
83
|
-
# end of step
|
84
|
-
visualize(counter, step) if @config.visual && @config.step
|
85
|
-
|
86
|
-
end
|
87
|
-
|
88
|
-
end
|
89
|
-
|
90
|
-
# end of robot
|
91
|
-
|
92
|
-
end
|
7
|
+
|
8
|
+
class Game
|
9
|
+
|
10
|
+
def initialize(config)
|
11
|
+
@config = config
|
12
|
+
@robots = Hash.new
|
13
|
+
@map = Swint::Map.new.load_from_xml(File.new(config.map).read)
|
14
|
+
config.robots.each do |r|
|
15
|
+
puts "connecting to robot: #{r}" if config.visual
|
16
|
+
@robots[@robots.size+1] = Swint::XmlrpcRobot.new(r, @map.start) if r.is_a?(String)
|
17
|
+
@robots[@robots.size+1] = Swint::ClassRobot.new(r, @map.start) if r.is_a?(Class)
|
18
|
+
end
|
19
|
+
@result = Result.new(@robots)
|
20
|
+
@game_end = false
|
21
|
+
end
|
93
22
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
23
|
+
def run
|
24
|
+
system "clear" if @config.visual
|
25
|
+
counter = 0
|
26
|
+
@result.start = Time.now
|
27
|
+
until @game_end
|
28
|
+
counter += 1
|
29
|
+
no_robot_left = true
|
30
|
+
@robots.to_a.shuffle.each do |robot|
|
31
|
+
k, r = robot
|
32
|
+
r.speed.times do |step|
|
33
|
+
if !@game_end
|
34
|
+
answer = :do_nothing
|
35
|
+
dt = measure { answer = r.next(@map) } if r.has_energy?
|
36
|
+
case answer
|
37
|
+
|
38
|
+
when :move_to
|
39
|
+
no_robot_left = false
|
40
|
+
if r.use_energy?
|
41
|
+
dir = nil
|
42
|
+
dt += measure { dir = r.move }
|
43
|
+
npos = r.pos.add(DIRV[dir])
|
44
|
+
nstate = @map.state_of_field(npos)
|
45
|
+
if nstate==:goal
|
46
|
+
@robots.each { |key, b| b.end_game( (b==r) ? 'winner' : 'looser' ) }
|
47
|
+
@result.winner = k
|
48
|
+
@game_end = true
|
49
|
+
end
|
50
|
+
if [:free, :energy, :start].include?(nstate)
|
51
|
+
f, p = @map.fields[npos], @map.fields[r.pos]
|
52
|
+
r.restore if f.state==:energy
|
53
|
+
p.robot = false
|
54
|
+
f.robot = true
|
55
|
+
r.pos = npos
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
when :push_object
|
60
|
+
no_robot_left = false
|
61
|
+
if r.use_energy?
|
62
|
+
dir = nil
|
63
|
+
dt += measure { dir = r.push }
|
64
|
+
opos = r.pos.add(DIRV[dir])
|
65
|
+
ppos = opos.add(DIRV[dir])
|
66
|
+
ostate = @map.state_of_field(opos)
|
67
|
+
pstate = @map.state_of_field(ppos)
|
68
|
+
|
69
|
+
if pstate==:free || pstate==:energy
|
70
|
+
if ostate==:object
|
71
|
+
if r.power >= @map.fields[opos].weight
|
72
|
+
@map.fields[ppos].weight = @map.fields[opos].weight
|
73
|
+
@map.fields[opos].weight = 0
|
74
|
+
end
|
75
|
+
end
|
76
|
+
if ostate==:robot
|
77
|
+
rob = @robots.values.select { |ro| ro.pos==opos }.first
|
78
|
+
if r.power >= rob.weight
|
79
|
+
rob.pos = ppos
|
80
|
+
rob.restore if pstate==:energy
|
81
|
+
@map.fields[opos].robot = false
|
82
|
+
@map.fields[ppos].robot = true
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
when :shout
|
90
|
+
no_robot_left = false
|
91
|
+
dt += measure { msg = r.shout }
|
92
|
+
@robots.each do |rid, rob|
|
93
|
+
next if rid==k
|
94
|
+
rob.listen(msg) if hex_distance(r.pos, rob.pos) <= r.voice * 10
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
@result.step(k, dt || 0)
|
100
|
+
# end of step
|
101
|
+
visualize(counter, step) if @config.visual && @config.step
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
# end of robot
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
# end of turn
|
112
|
+
visualize(counter) if @config.visual && !@config.step
|
113
|
+
|
114
|
+
if no_robot_left
|
115
|
+
@robots.each { |k, b| b.end_game('looser') }
|
116
|
+
@game_end = true
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
# end of game
|
122
|
+
@result.rounds = counter
|
123
|
+
@result.end = Time.now
|
124
|
+
@result
|
125
|
+
|
126
|
+
end
|
110
127
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
128
|
+
def visualize(round, step=nil)
|
129
|
+
system "tput cup 0 0"
|
130
|
+
print "ROUND: #{round}"
|
131
|
+
print " | STEP: #{step}" if step
|
132
|
+
puts
|
133
|
+
flags = {}
|
134
|
+
@robots.each do |k, r|
|
135
|
+
puts "%s. [% 2s/% 2s] %s" % [k, r.energy_left, r.energy, r]
|
136
|
+
flags.merge!(r.flags) if !@game_end && @config.test
|
137
|
+
end
|
138
|
+
@map.print_map(@robots, flags)
|
139
|
+
gets if @config.wait
|
140
|
+
end
|
120
141
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
end
|
142
|
+
def measure
|
143
|
+
t = Time.now.to_f
|
144
|
+
yield
|
145
|
+
Time.now.to_f - t
|
146
|
+
end
|
128
147
|
|
129
|
-
|
148
|
+
def hex_distance(pos1, pos2) # might fail when map is rotated
|
149
|
+
x, y = pos2.add(pos1.collect { |e| -e })
|
150
|
+
a = 0
|
151
|
+
a = (x==y) ? 2 : 1 if ((x < 0) && (y < 0)) || ((x > 0) && (y > 0))
|
152
|
+
[x.abs, y.abs].max + a
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
data/lib/swint/map.rb
CHANGED
@@ -4,62 +4,75 @@
|
|
4
4
|
# (c) 2008-01-07 Philipp Hofmann <phil@s126.de>
|
5
5
|
|
6
6
|
module Swint
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
attr_reader :start, :fields
|
11
|
-
|
12
|
-
def initialize
|
13
|
-
@min, @max = [0, 0], [0, 0] # THIS IS AN ASUMPTION!
|
14
|
-
@fields = Hash.new(:outside)
|
15
|
-
end
|
16
|
-
|
17
|
-
def load_from_xml(xml)
|
18
|
-
doc = REXML::Document.new(xml)
|
19
|
-
doc.elements.each('map/field') do |e|
|
20
|
-
v = e.attribute('v').value.to_i
|
21
|
-
u = e.attribute('u').value.to_i
|
22
|
-
s = e.attribute('state').value.to_sym
|
23
|
-
f = Swint::Field.new(s, [u, v])
|
24
|
-
@fields[f.pos] = f
|
25
|
-
@min[0] = u if u < @min[0]
|
26
|
-
@min[1] = v if v < @min[1]
|
27
|
-
@max[0] = u if u > @max[0]
|
28
|
-
@max[1] = v if v > @max[1]
|
29
|
-
if s==:start
|
30
|
-
@start = [u, v]
|
31
|
-
# f.robot = true # HACK!
|
32
|
-
end
|
33
|
-
end
|
34
|
-
self
|
35
|
-
end
|
36
|
-
|
37
|
-
def state_of_field(pos)
|
38
|
-
v = @fields[pos]
|
39
|
-
v.is_a?(Symbol) ? v : v.state
|
40
|
-
end
|
7
|
+
|
8
|
+
class Map
|
41
9
|
|
42
|
-
|
43
|
-
w = ((@max[0]-@min[0])*2+(@max[1]-@min[1]))
|
44
|
-
border = '='*(w+6)
|
45
|
-
puts border
|
46
|
-
for y in @min[1]..@max[1]
|
47
|
-
line = ''
|
48
|
-
line += ' '*(y)
|
49
|
-
for x in @min[0]..@max[0]
|
50
|
-
s = state_of_field([x, y])
|
51
|
-
c = s!=:robot ? CHAR[state_of_field([x, y])] : robotkey_at(robots, [x, y]).to_s
|
52
|
-
line += c+' '
|
53
|
-
end
|
54
|
-
puts line
|
55
|
-
end
|
56
|
-
puts border
|
57
|
-
end
|
10
|
+
attr_reader :start, :fields
|
58
11
|
|
59
|
-
|
60
|
-
|
61
|
-
|
12
|
+
def initialize
|
13
|
+
@min, @max = [0, 0], [0, 0] # THIS IS AN ASUMPTION!
|
14
|
+
@fields = Hash.new(:outside)
|
15
|
+
end
|
62
16
|
|
63
|
-
|
17
|
+
def load_from_xml(xml)
|
18
|
+
doc = REXML::Document.new(xml)
|
19
|
+
doc.elements.each('map/field') do |e|
|
20
|
+
v = e.attribute('v').value.to_i
|
21
|
+
u = e.attribute('u').value.to_i
|
22
|
+
s = e.attribute('state').value.to_sym
|
23
|
+
w = nil
|
24
|
+
if s==:object
|
25
|
+
w = e.attribute('weight').value.to_i
|
26
|
+
s = :free
|
27
|
+
end
|
28
|
+
f = Swint::Field.new(s, [u, v], w)
|
29
|
+
@fields[f.pos] = f
|
30
|
+
@min[0] = u if u < @min[0]
|
31
|
+
@min[1] = v if v < @min[1]
|
32
|
+
@max[0] = u if u > @max[0]
|
33
|
+
@max[1] = v if v > @max[1]
|
34
|
+
if s==:start
|
35
|
+
@start = [u, v]
|
36
|
+
# f.robot = true # HACK!
|
37
|
+
end
|
38
|
+
end
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def state_of_field(pos)
|
43
|
+
v = @fields[pos]
|
44
|
+
v.is_a?(Symbol) ? v : v.state
|
45
|
+
end
|
46
|
+
|
47
|
+
def print_map(robots, flags)
|
48
|
+
w = ((@max[0]-@min[0])*2+(@max[1]-@min[1]))
|
49
|
+
border = '='*(w+6)
|
50
|
+
puts border
|
51
|
+
print draw_map(robots, flags)
|
52
|
+
puts border
|
53
|
+
end
|
64
54
|
|
55
|
+
def draw_map(robots, flags)
|
56
|
+
output = []
|
57
|
+
for y in @min[1]..@max[1]
|
58
|
+
line = ''
|
59
|
+
line += ' '*(y)
|
60
|
+
for x in @min[0]..@max[0]
|
61
|
+
s = state_of_field([x, y])
|
62
|
+
c = s!=:robot ? CHAR[state_of_field([x, y])] : robotkey_at(robots, [x, y]).to_s
|
63
|
+
pstr = [x, y].add(@start.collect { |s| -s })*'x'
|
64
|
+
c = flags[pstr] if flags[pstr]
|
65
|
+
line += c+' '
|
66
|
+
end
|
67
|
+
output << line
|
68
|
+
end
|
69
|
+
output.join("\n")+"\n"
|
70
|
+
end
|
71
|
+
|
72
|
+
def robotkey_at(robots, pos)
|
73
|
+
robots.each { |k, r| return k if r.pos==pos }
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
65
78
|
end
|
data/lib/swint/xmlrpc_robot.rb
CHANGED
@@ -42,6 +42,18 @@ module Swint
|
|
42
42
|
@server.call('end_game', @gameid, msg)
|
43
43
|
end
|
44
44
|
|
45
|
+
def listen(msg)
|
46
|
+
@server.call('listen', @gameid, msg)
|
47
|
+
end
|
48
|
+
|
49
|
+
def shout
|
50
|
+
@server.call('shout', @gameid)
|
51
|
+
end
|
52
|
+
|
53
|
+
def flags
|
54
|
+
@server.call('flags', @gameid)
|
55
|
+
end
|
56
|
+
|
45
57
|
end
|
46
58
|
|
47
59
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# (c) 2008-01-22 Philipp Hofmann <phil@s126.de>
|
4
|
+
|
5
|
+
require 'rexml/document'
|
6
|
+
|
7
|
+
module SwintExec
|
8
|
+
|
9
|
+
module AsciiToMap
|
10
|
+
|
11
|
+
STATE = {
|
12
|
+
'S' => 'start',
|
13
|
+
'G' => 'goal',
|
14
|
+
'_' => 'free',
|
15
|
+
'o' => 'object',
|
16
|
+
'#' => 'outside',
|
17
|
+
'!' => 'energy'
|
18
|
+
}
|
19
|
+
|
20
|
+
def AsciiToMap.start(args)
|
21
|
+
|
22
|
+
filename = args.first
|
23
|
+
lines = File.open(filename).read.split("\n")
|
24
|
+
xmldoc = REXML::Document.new
|
25
|
+
map = xmldoc.add_element('map')
|
26
|
+
|
27
|
+
lines.size.times do |i|
|
28
|
+
line = lines[i].strip.split(' ')
|
29
|
+
line.size.times do |j|
|
30
|
+
map.add_element('field', {'state'=>STATE[line[j]], 'u'=>j, 'v'=>i })
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
puts xmldoc
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#-*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
# (c) 2008-01-17 Philipp Hofmann <phil@s126.de>
|
5
|
+
|
6
|
+
require 'optparse'
|
7
|
+
require 'ostruct'
|
8
|
+
require 'xmlrpc/client'
|
9
|
+
require 'rexml/document'
|
10
|
+
|
11
|
+
require 'array'
|
12
|
+
|
13
|
+
require 'swint/_constants'
|
14
|
+
require 'swint/game'
|
15
|
+
require 'swint/map'
|
16
|
+
require 'swint/field'
|
17
|
+
require 'swint/result'
|
18
|
+
require 'swint/abstract_robot'
|
19
|
+
require 'swint/xmlrpc_robot'
|
20
|
+
require 'swint/class_robot'
|
21
|
+
|
22
|
+
module SwintExec
|
23
|
+
|
24
|
+
module Race
|
25
|
+
|
26
|
+
def Race.start(args)
|
27
|
+
|
28
|
+
config = OpenStruct.new
|
29
|
+
config.step = false
|
30
|
+
config.wait = false
|
31
|
+
config.visual = true
|
32
|
+
config.map = 'example.map'
|
33
|
+
config.robots = []
|
34
|
+
config.statistics = false
|
35
|
+
|
36
|
+
opts = OptionParser.new do |o|
|
37
|
+
o.on('-r', '--robot URI', 'URI of robot') do |r|
|
38
|
+
r = "http://localhost:#{r}/" if /[0-9]+/.match(r)
|
39
|
+
config.robots << r
|
40
|
+
end
|
41
|
+
o.on('-m', '--map URI', 'URI of map') { |m| config.map = m }
|
42
|
+
o.on('-s', '--step', 'Show each step') { config.step = true }
|
43
|
+
o.on('-w', '--wait', 'Wait for return after visual') { config.wait = true }
|
44
|
+
o.on('-v', '--no-visual', 'No visual at all') { config.visual = false }
|
45
|
+
o.on('-t', '--test', 'Do not rotate map') { config.test = true }
|
46
|
+
o.on('-i', '--statistics', 'Display statistics') { config.statistics = true }
|
47
|
+
o.on('-e', '--require FILENAME', 'Provide a file to require') { |e| require(e) }
|
48
|
+
o.on('-c', '--class CLASS', 'Provide a Ruby Robot Class') { |c| config.robots << Kernel.const_get(c) }
|
49
|
+
end
|
50
|
+
|
51
|
+
opts.parse!(args)
|
52
|
+
|
53
|
+
Swint.rotate_map! unless config.test
|
54
|
+
|
55
|
+
unless File.exist?(config.map)
|
56
|
+
puts "mapfile #{config.map} not found"
|
57
|
+
exit
|
58
|
+
end
|
59
|
+
|
60
|
+
result = Swint::Game.new(config).run
|
61
|
+
puts "winner after % 3s rounds robot %s" % [result.rounds, result.winner]
|
62
|
+
if config.statistics
|
63
|
+
puts "\ntiming statistics\n-----------------"
|
64
|
+
puts "game took %5.2f seconds" % result.time
|
65
|
+
result.data.each do |r, d|
|
66
|
+
time = 0
|
67
|
+
d[:times].each { |t| time += t }
|
68
|
+
puts "% 5.2f seconds %s (%s)" % [time, d[:robot].name, d[:robot].owner]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#-*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
# (c) 2008-02-02 Philipp Hofmann <phil@s126.de>
|
5
|
+
|
6
|
+
require 'optparse'
|
7
|
+
require 'ostruct'
|
8
|
+
require 'xmlrpc/client'
|
9
|
+
require 'rexml/document'
|
10
|
+
|
11
|
+
require 'array'
|
12
|
+
|
13
|
+
require 'swint/_constants'
|
14
|
+
require 'swint/game'
|
15
|
+
require 'swint/map'
|
16
|
+
require 'swint/field'
|
17
|
+
require 'swint/result'
|
18
|
+
require 'swint/abstract_robot'
|
19
|
+
require 'swint/xmlrpc_robot'
|
20
|
+
require 'swint/class_robot'
|
21
|
+
|
22
|
+
module SwintExec
|
23
|
+
|
24
|
+
module Tournament
|
25
|
+
|
26
|
+
def Tournament.start(args)
|
27
|
+
|
28
|
+
puts 'sorry, not implemented yet'
|
29
|
+
exit
|
30
|
+
|
31
|
+
### config = OpenStruct.new
|
32
|
+
### config.step = false
|
33
|
+
### config.wait = false
|
34
|
+
### config.visual = true
|
35
|
+
### config.map = 'example.map'
|
36
|
+
### config.robots = []
|
37
|
+
### config.statistics = false
|
38
|
+
###
|
39
|
+
### opts = OptionParser.new do |o|
|
40
|
+
### o.on('-r', '--robot URI', 'URI of robot') do |r|
|
41
|
+
### r = "http://localhost:#{r}/" if /[0-9]+/.match(r)
|
42
|
+
### config.robots << r
|
43
|
+
### end
|
44
|
+
### o.on('-m', '--map URI', 'URI of map') { |m| config.map = m }
|
45
|
+
### o.on('-s', '--step', 'Show each step') { config.step = true }
|
46
|
+
### o.on('-w', '--wait', 'Wait for return after visual') { config.wait = true }
|
47
|
+
### o.on('-v', '--no-visual', 'No visual at all') { config.visual = false }
|
48
|
+
### o.on('-t', '--test', 'Do not rotate map') { config.test = true }
|
49
|
+
### o.on('-i', '--statistics', 'Display statistics') { config.statistics = true }
|
50
|
+
### o.on('-e', '--require FILENAME', 'Provide a file to require') { |e| require(e) }
|
51
|
+
### o.on('-c', '--class CLASS', 'Provide a Ruby Robot Class') { |c| config.robots << Kernel.const_get(c) }
|
52
|
+
### end
|
53
|
+
###
|
54
|
+
### opts.parse!(args)
|
55
|
+
###
|
56
|
+
### Swint.rotate_map! unless config.test
|
57
|
+
###
|
58
|
+
### unless File.exist?(config.map)
|
59
|
+
### puts "mapfile #{config.map} not found"
|
60
|
+
### exit
|
61
|
+
### end
|
62
|
+
###
|
63
|
+
### game = Swint::Game.new(config)
|
64
|
+
### result = game.run
|
65
|
+
### puts "winner after % 3s rounds robot %s" % [result.rounds, result.winner]
|
66
|
+
### if config.statistics
|
67
|
+
### puts "\ntiming statistics\n-----------------"
|
68
|
+
### puts "game took %5.2f seconds" % result.time
|
69
|
+
### result.data.each do |r, d|
|
70
|
+
### time = 0
|
71
|
+
### d[:times].each { |t| time += t }
|
72
|
+
### puts "% 5.2f seconds %s (%s)" % [time, d[:robot].name, d[:robot].owner]
|
73
|
+
### end
|
74
|
+
### end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: swint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.6"
|
5
5
|
platform: ""
|
6
6
|
authors:
|
7
7
|
- Philipp Hofmann
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-02-02 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -24,22 +24,23 @@ extra_rdoc_files:
|
|
24
24
|
- LICENSE
|
25
25
|
- CHANGELOG
|
26
26
|
files:
|
27
|
-
- lib/
|
28
|
-
- lib/swint/game.rb
|
27
|
+
- lib/array.rb
|
29
28
|
- lib/swint/map.rb
|
30
|
-
- lib/swint/robot.rb
|
31
29
|
- lib/swint/result.rb
|
30
|
+
- lib/swint/field.rb
|
31
|
+
- lib/swint/abstract_robot.rb
|
32
|
+
- lib/swint/game.rb
|
33
|
+
- lib/swint/class_robot.rb
|
32
34
|
- lib/swint/xmlrpc_robot.rb
|
33
35
|
- lib/swint/_constants.rb
|
34
|
-
- lib/
|
35
|
-
- lib/
|
36
|
-
- lib/
|
37
|
-
- lib/swint_basics/hash.rb
|
36
|
+
- lib/swint_exec/tournament.rb
|
37
|
+
- lib/swint_exec/ascii_to_map.rb
|
38
|
+
- lib/swint_exec/race.rb
|
38
39
|
- bin/swint
|
40
|
+
- LICENSE
|
39
41
|
- Rakefile
|
40
42
|
- CHANGELOG
|
41
43
|
- README
|
42
|
-
- LICENSE
|
43
44
|
has_rdoc: false
|
44
45
|
homepage: http://branch14.org/swint/
|
45
46
|
post_install_message:
|
@@ -59,8 +60,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
59
60
|
- !ruby/object:Gem::Version
|
60
61
|
version: "0"
|
61
62
|
version:
|
62
|
-
requirements:
|
63
|
-
|
63
|
+
requirements:
|
64
|
+
- tput binary from ncurses
|
65
|
+
- swarm intelligence maps, see http://branch14.org/swint/
|
64
66
|
rubyforge_project: swint
|
65
67
|
rubygems_version: 0.9.5
|
66
68
|
signing_key:
|
data/lib/swint/robot.rb
DELETED
@@ -1,125 +0,0 @@
|
|
1
|
-
#! /usr/bin/env ruby
|
2
|
-
#-*- coding: utf-8 -*-
|
3
|
-
|
4
|
-
# (c) 2008-01-07 Philipp Hofmann <phil@s126.de>
|
5
|
-
|
6
|
-
module Swint
|
7
|
-
|
8
|
-
class Robot
|
9
|
-
|
10
|
-
attr_accessor :pos
|
11
|
-
|
12
|
-
attr_reader :speed, :sight, :power, :energy, :weight, :energy_left, :uri, :name, :owner
|
13
|
-
|
14
|
-
# --------------------------------------------------------------------------------
|
15
|
-
# --- stub
|
16
|
-
|
17
|
-
def initialize(uri, pos)
|
18
|
-
@uri = uri
|
19
|
-
@pos = pos
|
20
|
-
restore
|
21
|
-
end
|
22
|
-
|
23
|
-
def next(map)
|
24
|
-
end
|
25
|
-
|
26
|
-
def move
|
27
|
-
# check_direction(...)
|
28
|
-
end
|
29
|
-
|
30
|
-
def push
|
31
|
-
end
|
32
|
-
|
33
|
-
def end_game(msg)
|
34
|
-
end
|
35
|
-
|
36
|
-
# --------------------------------------------------------------------------------
|
37
|
-
|
38
|
-
def is_valid?
|
39
|
-
(@speed + @sight + @power + @energy + @weight) == 22
|
40
|
-
end
|
41
|
-
|
42
|
-
def check_direction(d)
|
43
|
-
unless (0..5).include?(d)
|
44
|
-
puts "#{@name}, what is this? '#{d}' is not a drection."
|
45
|
-
exit
|
46
|
-
end
|
47
|
-
d
|
48
|
-
end
|
49
|
-
|
50
|
-
def check_action(a)
|
51
|
-
unless [:do_nothing, :move_to, :push_object, :shout].include?(a)
|
52
|
-
puts "#{@name}, what is this? '#{a}' is not an action."
|
53
|
-
exit
|
54
|
-
end
|
55
|
-
a
|
56
|
-
end
|
57
|
-
|
58
|
-
def to_s
|
59
|
-
a = ["#{@name} (#{@owner})", @speed, @sight, @power, @weight, @energy]
|
60
|
-
"%-30s [sp: % 2s, si: % 2s, po: % 2s, we: % 2s, en: % 2s]" % a
|
61
|
-
end
|
62
|
-
|
63
|
-
def use_energy?
|
64
|
-
return false unless has_energy?
|
65
|
-
@energy_left -= 1
|
66
|
-
true
|
67
|
-
end
|
68
|
-
|
69
|
-
def has_energy?
|
70
|
-
@energy_left>0
|
71
|
-
end
|
72
|
-
|
73
|
-
def restore
|
74
|
-
@energy_left = @energy
|
75
|
-
end
|
76
|
-
|
77
|
-
def calculate_view(map)
|
78
|
-
|
79
|
-
# A centered hexagonal number, or hex number, is a centered figurate
|
80
|
-
# number that represents a hexagon with a dot in the center and all
|
81
|
-
# other dots surrounding the center dot in a hexagonal lattice.
|
82
|
-
# 1, 7, 19, 37, 61, 91, 127, 169, 217, 271, 331, 397, 469, 547, 631, 721, 817, 919
|
83
|
-
|
84
|
-
# relative directions
|
85
|
-
reld = [2, 3, 4, 5, 0, 1]
|
86
|
-
|
87
|
-
data = []
|
88
|
-
cpos = pos.clone # that was tough!
|
89
|
-
|
90
|
-
### stef's version
|
91
|
-
|
92
|
-
sight.times do |depth|
|
93
|
-
cpos.add!(DIRV[0])
|
94
|
-
data << map.state_of_field(cpos)
|
95
|
-
5.times do |dir|
|
96
|
-
(depth+1).times do |i|
|
97
|
-
cpos.add!(DIRV[reld[dir]])
|
98
|
-
data << map.state_of_field(cpos)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
depth.times do |i|
|
102
|
-
cpos.add!(DIRV[reld[5]])
|
103
|
-
data << map.state_of_field(cpos)
|
104
|
-
end
|
105
|
-
cpos.add!(DIRV[1])
|
106
|
-
end
|
107
|
-
|
108
|
-
### sight.times do |depth|
|
109
|
-
### cpos.add!(DIRV[0])
|
110
|
-
### data << map.state_of_field(cpos)
|
111
|
-
### 6.times do |dir|
|
112
|
-
### (depth+1).times do |i|
|
113
|
-
### cpos.add!(DIRV[reld[dir]])
|
114
|
-
### data << map.state_of_field(cpos)
|
115
|
-
### end
|
116
|
-
### end
|
117
|
-
### end
|
118
|
-
|
119
|
-
data
|
120
|
-
|
121
|
-
end
|
122
|
-
|
123
|
-
end
|
124
|
-
|
125
|
-
end
|