swint 0.5
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 +23 -0
- data/LICENSE +20 -0
- data/README +80 -0
- data/Rakefile +59 -0
- data/bin/swint +75 -0
- data/lib/swint/_constants.rb +30 -0
- data/lib/swint/abstract_robot.rb +125 -0
- data/lib/swint/class_robot.rb +48 -0
- data/lib/swint/field.rb +27 -0
- data/lib/swint/game.rb +129 -0
- data/lib/swint/map.rb +65 -0
- data/lib/swint/result.rb +33 -0
- data/lib/swint/robot.rb +125 -0
- data/lib/swint/xmlrpc_robot.rb +47 -0
- data/lib/swint_basics/array.rb +18 -0
- data/lib/swint_basics/hash.rb +11 -0
- metadata +70 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
2008-01-17 v0.5 features
|
2
|
+
|
3
|
+
* -e und -c to require and use a ruby robot class
|
4
|
+
for debugging and profiling purposes
|
5
|
+
|
6
|
+
2008-01-14 v0.4 features
|
7
|
+
|
8
|
+
* use -n <n> for more than one game
|
9
|
+
* use -i for timing statistics
|
10
|
+
|
11
|
+
2008-01-07 v0.3 bug fixes
|
12
|
+
|
13
|
+
* map is rotated, turn this behavior off with option -t
|
14
|
+
* code now splited in several files
|
15
|
+
* walking on start is now possible
|
16
|
+
|
17
|
+
2008-01-06 v0.2 lots of minor improvements
|
18
|
+
|
19
|
+
* less flickering
|
20
|
+
* use -s to see every step
|
21
|
+
* use -w to wait for input each step
|
22
|
+
|
23
|
+
2008-01-02 v0.1 initial release
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Philipp Hofmann <phil@s126.de>
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
|
2
|
+
================================================================================
|
3
|
+
__ __ __
|
4
|
+
.-----.--.--.--.|__|.-----.| |_ .----.| |--.
|
5
|
+
|__ --| | | || || || _|__| _|| _ |
|
6
|
+
|_____|________||__||__|__||____|__|__| |_____|
|
7
|
+
|
8
|
+
(c) 2008-01-07 Philipp Hofmann <phil@s126.de>
|
9
|
+
================================================================================
|
10
|
+
|
11
|
+
swint.rb is an entirely in Ruby written client for the SwarmIntelligence
|
12
|
+
programming game originally created by Stefan Schwarzburg-Benz.
|
13
|
+
|
14
|
+
Usage:
|
15
|
+
|
16
|
+
./swint.rb [options]
|
17
|
+
|
18
|
+
|
19
|
+
Options:
|
20
|
+
|
21
|
+
-r|--robot <uri>
|
22
|
+
|
23
|
+
supply a URL to your robot's XMLRPC interface here, may be used repeatedly
|
24
|
+
|
25
|
+
|
26
|
+
-m|--map <filename>
|
27
|
+
|
28
|
+
supply a filename to the XML map of the game
|
29
|
+
|
30
|
+
|
31
|
+
-s|--step
|
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
|
67
|
+
|
68
|
+
add a ruby robot class as player
|
69
|
+
|
70
|
+
|
71
|
+
Example:
|
72
|
+
|
73
|
+
For a quick match on example.map:
|
74
|
+
|
75
|
+
./swint.rb -r http://localhost:8000/ -r http://localhost:8001/
|
76
|
+
|
77
|
+
For testing your bot:
|
78
|
+
|
79
|
+
./swint.rb -r http://localhost:8000/ -s -t -w -m maps/example.map
|
80
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
Gem::manage_gems
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
|
5
|
+
spec = Gem::Specification.new do |s|
|
6
|
+
|
7
|
+
# REQUIRED
|
8
|
+
|
9
|
+
s.name = "swint"
|
10
|
+
s.version = "0.5"
|
11
|
+
s.summary = "a console client for the swarm intelligence programming game"
|
12
|
+
|
13
|
+
# REQUIRED AND SET BY DEFAULT
|
14
|
+
|
15
|
+
# s.platform = Gem::Platform::RUBY
|
16
|
+
# s.date = Time.now
|
17
|
+
# s.require_paths = ['lib']
|
18
|
+
|
19
|
+
# OPTIONAL
|
20
|
+
|
21
|
+
s.description = s.summary
|
22
|
+
#s.files = Dir.glob("**/*").delete_if { |item| /(.svn|~$|Rakefile|pkg)/.match(item) }
|
23
|
+
s.files = FileList['lib/**/*.rb', 'bin/*', '[A-Z]*', 'test/**/*'].to_a
|
24
|
+
#s.authors = ['Philipp Hofmann']
|
25
|
+
s.author = 'Philipp Hofmann'
|
26
|
+
s.email = "phil @nospam@ branch14.org"
|
27
|
+
s.homepage = "http://branch14.org/swint/"
|
28
|
+
s.rubyforge_project = s.name
|
29
|
+
s.extra_rdoc_files = ['README', 'LICENSE', 'CHANGELOG']
|
30
|
+
s.executables = [s.name]
|
31
|
+
# s.default_executable = s.name
|
32
|
+
|
33
|
+
# OPTIONAL AND SET BY DEFAULT
|
34
|
+
|
35
|
+
# s.autorequire = nil
|
36
|
+
# s.bindir = 'bin'
|
37
|
+
# s.has_rdoc = false
|
38
|
+
# s.rdoc_options = []
|
39
|
+
# s.required_ruby_version = '> 0.0.0'
|
40
|
+
# s.requirements = []
|
41
|
+
# s.test_files = []
|
42
|
+
# s.dependencies = []
|
43
|
+
# s.add_dependency('log4r', '>= 1.0.5')
|
44
|
+
# s.extensions = []
|
45
|
+
|
46
|
+
# SET AUTOMATICALLY
|
47
|
+
|
48
|
+
# rubygems_version, specification_version
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
53
|
+
pkg.need_tar = true
|
54
|
+
end
|
55
|
+
|
56
|
+
task :default => "pkg/#{spec.name}-#{spec.version}.gem" do
|
57
|
+
puts "generated latest version"
|
58
|
+
end
|
59
|
+
|
data/bin/swint
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#-*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
# (c) 2008-01-17 Philipp Hofmann <phil@s126.de>
|
5
|
+
|
6
|
+
##############################
|
7
|
+
|
8
|
+
require 'optparse'
|
9
|
+
require 'ostruct'
|
10
|
+
require 'xmlrpc/client'
|
11
|
+
require 'rexml/document'
|
12
|
+
|
13
|
+
##############################
|
14
|
+
|
15
|
+
# $:.unshift(File.dirname(__FILE__))
|
16
|
+
|
17
|
+
require 'swint_basics/array'
|
18
|
+
require 'swint_basics/hash'
|
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) }
|
51
|
+
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
|
@@ -0,0 +1,30 @@
|
|
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
|
+
CHAR = {
|
9
|
+
:free => '_',
|
10
|
+
:object => 'o',
|
11
|
+
:start => 'S',
|
12
|
+
:goal => 'G',
|
13
|
+
:outside => '#',
|
14
|
+
:energy => '!'
|
15
|
+
}
|
16
|
+
|
17
|
+
DIRV = [
|
18
|
+
[-1, +1],
|
19
|
+
[-1, 0],
|
20
|
+
[ 0, -1],
|
21
|
+
[+1, -1],
|
22
|
+
[+1, 0],
|
23
|
+
[ 0, +1]
|
24
|
+
]
|
25
|
+
|
26
|
+
def Swint.rotate_map!
|
27
|
+
DIRV.push DIRV.shift, DIRV.shift, DIRV.shift
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,125 @@
|
|
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 AbstractRobot
|
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
|
@@ -0,0 +1,48 @@
|
|
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 ClassRobot < AbstractRobot
|
9
|
+
|
10
|
+
attr_accessor :pos
|
11
|
+
|
12
|
+
attr_reader :speed, :sight, :power, :energy, :weight, :energy_left, :uri, :name, :owner
|
13
|
+
|
14
|
+
def initialize(klass, pos)
|
15
|
+
@klass = klass
|
16
|
+
@instance = klass.new
|
17
|
+
# a = [:speed, :sight, :power, :energy, :weight, :name, :owner]
|
18
|
+
# a.each { |attr| send("self.#{attr}=", @instance.send(attr)) }
|
19
|
+
@speed = @instance.speed
|
20
|
+
@sight = @instance.sight
|
21
|
+
@power = @instance.power
|
22
|
+
@energy = @instance.energy
|
23
|
+
@weight = @instance.weight
|
24
|
+
@name = @instance.name
|
25
|
+
@owner = @instance.owner
|
26
|
+
@pos = pos
|
27
|
+
restore
|
28
|
+
end
|
29
|
+
|
30
|
+
def next(map)
|
31
|
+
check_action(@instance.next(calculate_view(map)).to_sym)
|
32
|
+
end
|
33
|
+
|
34
|
+
def move
|
35
|
+
check_direction(@instance.move)
|
36
|
+
end
|
37
|
+
|
38
|
+
def push
|
39
|
+
check_direction(@instance.push)
|
40
|
+
end
|
41
|
+
|
42
|
+
def end_game(msg)
|
43
|
+
@instance.end_game(msg)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
data/lib/swint/field.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#-*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
# (c) 2008-01-07 Philipp Hofmann <phil@s126.de>
|
5
|
+
|
6
|
+
# ------------------------------------------------------------
|
7
|
+
|
8
|
+
module Swint
|
9
|
+
|
10
|
+
class Field
|
11
|
+
|
12
|
+
attr_accessor :robot
|
13
|
+
attr_reader :pos
|
14
|
+
|
15
|
+
def initialize(s, pos)
|
16
|
+
@pos, @state = pos, s
|
17
|
+
@robot = false
|
18
|
+
end
|
19
|
+
|
20
|
+
def state
|
21
|
+
@robot ? :robot : @state
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
data/lib/swint/game.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#-*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
# (c) 2008-01-14 Philipp Hofmann <phil@s126.de>
|
5
|
+
|
6
|
+
module Swint
|
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
|
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
|
93
|
+
|
94
|
+
# end of turn
|
95
|
+
visualize(counter) if @config.visual && !@config.step
|
96
|
+
|
97
|
+
if no_robot_left
|
98
|
+
@robots.each { |k, b| b.end_game('looser') }
|
99
|
+
@game_end = true
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
# end of game
|
105
|
+
@result.rounds = counter
|
106
|
+
@result.end = Time.now
|
107
|
+
@result
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
def visualize(round, step=nil)
|
112
|
+
system "tput cup 0 0"
|
113
|
+
print "ROUND: #{round}"
|
114
|
+
print " | STEP: #{step}" if step
|
115
|
+
puts
|
116
|
+
@robots.each { |k, r| puts "%s. [% 2s/% 2s] %s" % [k, r.energy_left, r.energy, r] }
|
117
|
+
@map.print_map(@robots)
|
118
|
+
gets if @config.wait
|
119
|
+
end
|
120
|
+
|
121
|
+
def measure
|
122
|
+
t = Time.now.to_f
|
123
|
+
yield
|
124
|
+
Time.now.to_f - t
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
data/lib/swint/map.rb
ADDED
@@ -0,0 +1,65 @@
|
|
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 Map
|
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
|
41
|
+
|
42
|
+
def print_map(robots)
|
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
|
58
|
+
|
59
|
+
def robotkey_at(robots, pos)
|
60
|
+
robots.each { |k, r| return k if r.pos==pos }
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
data/lib/swint/result.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#-*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
# (c) 2008-01-14 Philipp Hofmann <phil@s126.de>
|
5
|
+
|
6
|
+
module Swint
|
7
|
+
|
8
|
+
class Result
|
9
|
+
|
10
|
+
attr_accessor :winner, :rounds, :start, :end
|
11
|
+
attr_reader :data
|
12
|
+
|
13
|
+
def initialize(robots)
|
14
|
+
@data = Hash.new
|
15
|
+
@winner = '<no winner>'
|
16
|
+
robots.each do |k, r|
|
17
|
+
@data[k] = Hash.new
|
18
|
+
@data[k][:robot] = r
|
19
|
+
@data[k][:times] = []
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def step(robot, time)
|
24
|
+
@data[robot][:times] << time
|
25
|
+
end
|
26
|
+
|
27
|
+
def time
|
28
|
+
@end.to_f - @start.to_f
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/lib/swint/robot.rb
ADDED
@@ -0,0 +1,125 @@
|
|
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
|
@@ -0,0 +1,47 @@
|
|
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 XmlrpcRobot < AbstractRobot
|
9
|
+
|
10
|
+
attr_accessor :pos
|
11
|
+
|
12
|
+
attr_reader :speed, :sight, :power, :energy, :weight, :energy_left, :uri, :name, :owner
|
13
|
+
|
14
|
+
def initialize(uri, pos)
|
15
|
+
@uri = uri
|
16
|
+
@server = XMLRPC::Client.new2(@uri)
|
17
|
+
@gameid = @server.call('start_game')
|
18
|
+
@speed = @server.call('get_speed', @gameid)
|
19
|
+
@sight = @server.call('get_sight', @gameid)
|
20
|
+
@power = @server.call('get_power', @gameid)
|
21
|
+
@energy = @server.call('get_energy', @gameid)
|
22
|
+
@weight = @server.call('get_weight', @gameid)
|
23
|
+
@name = @server.call('get_name', @gameid)
|
24
|
+
@owner = @server.call('get_owner', @gameid)
|
25
|
+
@pos = pos
|
26
|
+
restore
|
27
|
+
end
|
28
|
+
|
29
|
+
def next(map)
|
30
|
+
check_action(@server.call('next', @gameid, calculate_view(map)).to_sym)
|
31
|
+
end
|
32
|
+
|
33
|
+
def move
|
34
|
+
check_direction(@server.call('move', @gameid))
|
35
|
+
end
|
36
|
+
|
37
|
+
def push
|
38
|
+
check_direction(@server.call('push', @gameid))
|
39
|
+
end
|
40
|
+
|
41
|
+
def end_game(msg)
|
42
|
+
@server.call('end_game', @gameid, msg)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#-*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
# (c) 2008-01-07 Philipp Hofmann <phil@s126.de>
|
5
|
+
|
6
|
+
class Array
|
7
|
+
|
8
|
+
def add(a)
|
9
|
+
n = []
|
10
|
+
each_index { |i| n << (self[i] + a[i]) }
|
11
|
+
n
|
12
|
+
end
|
13
|
+
|
14
|
+
def add!(a)
|
15
|
+
replace(add(a))
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: swint
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.5"
|
5
|
+
platform: ""
|
6
|
+
authors:
|
7
|
+
- Philipp Hofmann
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-01-20 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: a console client for the swarm intelligence programming game
|
17
|
+
email: phil @nospam@ branch14.org
|
18
|
+
executables:
|
19
|
+
- swint
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
- LICENSE
|
25
|
+
- CHANGELOG
|
26
|
+
files:
|
27
|
+
- lib/swint/field.rb
|
28
|
+
- lib/swint/game.rb
|
29
|
+
- lib/swint/map.rb
|
30
|
+
- lib/swint/robot.rb
|
31
|
+
- lib/swint/result.rb
|
32
|
+
- lib/swint/xmlrpc_robot.rb
|
33
|
+
- lib/swint/_constants.rb
|
34
|
+
- lib/swint/class_robot.rb
|
35
|
+
- lib/swint/abstract_robot.rb
|
36
|
+
- lib/swint_basics/array.rb
|
37
|
+
- lib/swint_basics/hash.rb
|
38
|
+
- bin/swint
|
39
|
+
- Rakefile
|
40
|
+
- CHANGELOG
|
41
|
+
- README
|
42
|
+
- LICENSE
|
43
|
+
has_rdoc: false
|
44
|
+
homepage: http://branch14.org/swint/
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project: swint
|
65
|
+
rubygems_version: 0.9.5
|
66
|
+
signing_key:
|
67
|
+
specification_version: 2
|
68
|
+
summary: a console client for the swarm intelligence programming game
|
69
|
+
test_files: []
|
70
|
+
|