swint 0.5 → 0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|