ceml 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/ceml.gemspec +6 -3
- data/cemltest +15 -0
- data/lib/ceml.rb +65 -0
- data/lib/ceml/models.rb +2 -1
- data/lib/ceml/models/bundle.rb +48 -19
- data/lib/ceml/models/cast.rb +1 -0
- data/lib/ceml/models/castable.rb +9 -27
- data/lib/ceml/models/casting_pool.rb +26 -0
- data/lib/ceml/models/casting_tokens.rb +51 -0
- data/lib/ceml/models/incident.rb +8 -6
- data/lib/ceml/models/incident_model.rb +7 -6
- data/lib/ceml/models/player.rb +14 -6
- data/lib/ceml/models/waiting_room.rb +3 -15
- data/lib/ceml/processor.rb +21 -15
- data/lib/ceml/recognizer.rb +9 -0
- data/test/dialogues/jordan.ceml +40 -38
- data/test/helper.rb +2 -2
- data/test/test_dialogues.rb +13 -44
- metadata +8 -5
- data/lib/ceml/models/audition.rb +0 -65
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.9.0
|
data/ceml.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ceml}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.9.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Joe Edelman"]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-06-07}
|
13
13
|
s.description = %q{a language for coordinating real world events}
|
14
14
|
s.email = %q{joe@citizenlogistics.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -24,6 +24,7 @@ Gem::Specification.new do |s|
|
|
24
24
|
"Rakefile",
|
25
25
|
"VERSION",
|
26
26
|
"ceml.gemspec",
|
27
|
+
"cemltest",
|
27
28
|
"editors/CEML.tmbundle/Syntaxes/ceml.tmLanguage",
|
28
29
|
"editors/CEML.tmbundle/info.plist",
|
29
30
|
"examples/breakfast-exchange.ceml",
|
@@ -48,10 +49,11 @@ Gem::Specification.new do |s|
|
|
48
49
|
"lib/ceml/lang/tt/scripts.rb",
|
49
50
|
"lib/ceml/lang/tt/scripts.treetop",
|
50
51
|
"lib/ceml/models.rb",
|
51
|
-
"lib/ceml/models/audition.rb",
|
52
52
|
"lib/ceml/models/bundle.rb",
|
53
53
|
"lib/ceml/models/cast.rb",
|
54
54
|
"lib/ceml/models/castable.rb",
|
55
|
+
"lib/ceml/models/casting_pool.rb",
|
56
|
+
"lib/ceml/models/casting_tokens.rb",
|
55
57
|
"lib/ceml/models/incident.rb",
|
56
58
|
"lib/ceml/models/incident_model.rb",
|
57
59
|
"lib/ceml/models/incident_role_slot.rb",
|
@@ -59,6 +61,7 @@ Gem::Specification.new do |s|
|
|
59
61
|
"lib/ceml/models/queue.rb",
|
60
62
|
"lib/ceml/models/waiting_room.rb",
|
61
63
|
"lib/ceml/processor.rb",
|
64
|
+
"lib/ceml/recognizer.rb",
|
62
65
|
"test/askchain.ceml",
|
63
66
|
"test/compliment.ceml",
|
64
67
|
"test/dialogues/accept.ceml",
|
data/cemltest
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'ceml'
|
4
|
+
|
5
|
+
f = ARGV.shift
|
6
|
+
name = File.basename(f, '.ceml')
|
7
|
+
err, log = CEML.test(File.new(f).read)
|
8
|
+
if !err
|
9
|
+
puts "PASS cemltest #{name}. logged #{log.split("\n").size} lines"
|
10
|
+
elsif RuntimeError === err
|
11
|
+
puts log
|
12
|
+
raise "ERROR with cemltest #{name}: #{err.message}!"
|
13
|
+
else
|
14
|
+
raise err
|
15
|
+
end
|
data/lib/ceml.rb
CHANGED
@@ -2,17 +2,40 @@ require 'forwardable'
|
|
2
2
|
|
3
3
|
require 'ceml/models'
|
4
4
|
require 'ceml/lang'
|
5
|
+
require 'ceml/recognizer'
|
5
6
|
require 'ceml/processor'
|
7
|
+
require 'stringio'
|
6
8
|
|
7
9
|
module CEML
|
8
10
|
extend self
|
9
11
|
@extra_seconds = 0
|
12
|
+
@log_io = STDERR
|
13
|
+
attr_reader :tells
|
10
14
|
def clock; Time.now.utc.to_i + @extra_seconds; end
|
11
15
|
def incr_clock(s); @extra_seconds += s; end
|
12
16
|
def dur(n, unit)
|
13
17
|
n * case unit
|
14
18
|
when /^h/; 60*60; when /^mi/; 60; else 1; end
|
15
19
|
end
|
20
|
+
|
21
|
+
def capture_log
|
22
|
+
log = ""
|
23
|
+
err = nil
|
24
|
+
prev_io, @log_io = @log_io, StringIO.new(log)
|
25
|
+
yield
|
26
|
+
rescue Exception => err
|
27
|
+
@log_io.puts "\nERROR: #{err}\n\n\n"
|
28
|
+
ensure
|
29
|
+
@log_io = prev_io
|
30
|
+
return err, log
|
31
|
+
end
|
32
|
+
|
33
|
+
def log lvl, msg
|
34
|
+
if lvl > 1
|
35
|
+
msg = " #{msg}"
|
36
|
+
end
|
37
|
+
@log_io.puts msg
|
38
|
+
end
|
16
39
|
end
|
17
40
|
|
18
41
|
module CEML
|
@@ -39,4 +62,46 @@ module CEML
|
|
39
62
|
end
|
40
63
|
result
|
41
64
|
end
|
65
|
+
|
66
|
+
def test test, p = CEML::Processor
|
67
|
+
scripts, test = test.split("\n---\n")
|
68
|
+
s = CEML.parse(:scripts, scripts).map(&:castable)
|
69
|
+
bundle_id = gen_code # s.hash.to_s
|
70
|
+
@tells = Hash.new{ |h,k| h[k] = [] }
|
71
|
+
p.set_bundle(bundle_id, s)
|
72
|
+
p.reset_bundle(bundle_id)
|
73
|
+
pl = Set.new
|
74
|
+
CEML.capture_log do
|
75
|
+
test.each_line do |line|
|
76
|
+
line = line.strip
|
77
|
+
next if line =~ /^#/ or line =~ /^\s*$/
|
78
|
+
CEML.log 1, "#{line}"
|
79
|
+
case line
|
80
|
+
when /^(\w+) *< *(.*)$/
|
81
|
+
player_id, msg = $1, $2
|
82
|
+
heard = tells[player_id].shift
|
83
|
+
next if msg.empty? and !heard
|
84
|
+
raise "Expected silence from #{player_id}, got #{heard}" if msg.empty? and heard
|
85
|
+
raise "Expected #{player_id} < #{msg}, got silence" if !msg.empty? and !heard
|
86
|
+
heard = (heard||={})[:msg] || (heard||={})[:q] || ''
|
87
|
+
raise "Expected #{player_id} < #{msg}, got #{heard}" unless heard =~ /#{msg}/
|
88
|
+
next
|
89
|
+
when /^(\w+) *> *(.*)$/
|
90
|
+
player_id, msg = $1, $2
|
91
|
+
player = {:id => player_id, :received => msg }
|
92
|
+
if !pl.include?(player_id)
|
93
|
+
player[:tags] = ['new']
|
94
|
+
p.reset_player(bundle_id, player_id)
|
95
|
+
pl << player_id
|
96
|
+
end
|
97
|
+
player[:recognized] = CEML::Recognizer.recognize(msg)
|
98
|
+
p.ping(bundle_id, player)
|
99
|
+
when /^\((\d+)\s*(\w+)\)$/
|
100
|
+
CEML.incr_clock CEML.dur($1.to_i, $2)
|
101
|
+
p.run_latest
|
102
|
+
end
|
103
|
+
p.run
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
42
107
|
end
|
data/lib/ceml/models.rb
CHANGED
@@ -6,7 +6,8 @@ Redis::Objects.redis = Redis.new
|
|
6
6
|
require 'ceml/models/cast'
|
7
7
|
require 'ceml/models/castable'
|
8
8
|
require 'ceml/models/incident'
|
9
|
-
require 'ceml/models/
|
9
|
+
require 'ceml/models/casting_pool'
|
10
|
+
require 'ceml/models/casting_tokens'
|
10
11
|
require 'ceml/models/incident_model'
|
11
12
|
require 'ceml/models/incident_role_slot'
|
12
13
|
require 'ceml/models/player'
|
data/lib/ceml/models/bundle.rb
CHANGED
@@ -3,31 +3,68 @@ module CEML
|
|
3
3
|
include Redis::Objects
|
4
4
|
value :castables, :marshal => true
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
# =============
|
7
|
+
# = castables =
|
8
|
+
# =============
|
9
9
|
|
10
10
|
def find_castables(stanza_name = nil)
|
11
11
|
return castables.value unless stanza_name
|
12
12
|
return [castables.value.find{ |c| c.stanza_name == stanza_name }]
|
13
13
|
end
|
14
14
|
|
15
|
+
|
16
|
+
# =================
|
17
|
+
# = waiting rooms =
|
18
|
+
# =================
|
19
|
+
|
20
|
+
def clear_from_all_rooms(player_id)
|
21
|
+
CastingPool.destroy_everywhere(id, player_id)
|
22
|
+
end
|
23
|
+
|
15
24
|
def all_rooms
|
16
25
|
find_castables.map(&:all_rooms).flatten.uniq
|
17
26
|
end
|
18
27
|
|
19
28
|
def reset
|
20
|
-
|
29
|
+
# puts "TOTAL RESET"
|
30
|
+
CastingTokens.destroy_all(id)
|
31
|
+
all_rooms.each{ |room| room.waiting_incident_roles.clear }
|
21
32
|
end
|
22
33
|
|
23
34
|
def rooms_for_player(player, stanza_name = nil)
|
24
|
-
|
25
|
-
|
35
|
+
find_castables(stanza_name).map{ |c| c.waiting_rooms_for_player(player, stanza_name) }.flatten.uniq
|
36
|
+
end
|
37
|
+
|
38
|
+
def register_in_rooms(player, stanza_name = nil)
|
39
|
+
room_ids = rooms_for_player(player, stanza_name)
|
40
|
+
CastingPool.new(room_ids).post(id, player[:id])
|
26
41
|
end
|
27
42
|
|
43
|
+
def reset_player(player_id)
|
44
|
+
CastingPool.destroy_everywhere(id, player_id)
|
45
|
+
Player.new(player_id).reset
|
46
|
+
end
|
47
|
+
|
48
|
+
def grab_cast?(player, castable, seeded_p)
|
49
|
+
room_ids = castable.hot_waiting_rooms_given_player(player, seeded_p)
|
50
|
+
# CEML.log 1, "Checking cast for #{castable.stanza_name}: #{room_ids.inspect}"
|
51
|
+
casting_pool = CastingPool.new(room_ids)
|
52
|
+
loop do
|
53
|
+
hot_players = casting_pool.hot_players + [player]
|
54
|
+
# CEML.log 1, "Hot players: #{hot_players.inspect}"
|
55
|
+
return nil unless cast = castable.cast_from(hot_players)
|
56
|
+
return cast if casting_pool.claim(cast.player_ids - [player[:id]])
|
57
|
+
sleep 0.02
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# ==============================
|
62
|
+
# = incident joining/launching =
|
63
|
+
# ==============================
|
64
|
+
|
28
65
|
def join_running_incident?(player, stanza_name = nil)
|
29
|
-
rooms_for_player(player, stanza_name).each do |
|
30
|
-
if incident_id =
|
66
|
+
rooms_for_player(player, stanza_name).each do |room_id|
|
67
|
+
if incident_id = WaitingRoom.new(room_id).audition_for_incidents(player)
|
31
68
|
return incident_id
|
32
69
|
end
|
33
70
|
end
|
@@ -37,7 +74,8 @@ module CEML
|
|
37
74
|
def cast_player?(player, stanza_name = nil)
|
38
75
|
incident_id = gen_code
|
39
76
|
find_castables(stanza_name).each do |castable|
|
40
|
-
if cast =
|
77
|
+
if cast = grab_cast?(player, castable, seeded=stanza_name)
|
78
|
+
castable.advertise_roles(incident_id, cast)
|
41
79
|
i = IncidentModel.new(incident_id)
|
42
80
|
i.bytecode.value = castable.bytecode
|
43
81
|
i.add_castings(cast.castings)
|
@@ -48,16 +86,7 @@ module CEML
|
|
48
86
|
end
|
49
87
|
|
50
88
|
def absorb?(player, stanza_name = nil)
|
51
|
-
|
52
|
-
puts "X1: #{x.inspect}"
|
53
|
-
return x if x
|
54
|
-
x = cast_player?(player, stanza_name)
|
55
|
-
puts "X2: #{x.inspect}"
|
56
|
-
x
|
57
|
-
end
|
58
|
-
|
59
|
-
def register_in_rooms(player, stanza_name = nil)
|
60
|
-
Audition.new("#{player[:id]}").list_in_rooms(rooms_for_player(player, stanza_name)) ##{gen_code}:
|
89
|
+
join_running_incident?(player, stanza_name) or cast_player?(player, stanza_name)
|
61
90
|
end
|
62
91
|
|
63
92
|
end
|
data/lib/ceml/models/cast.rb
CHANGED
@@ -102,6 +102,7 @@ module CEML
|
|
102
102
|
|
103
103
|
class Tagspec < Struct.new :with, :without
|
104
104
|
def =~(c)
|
105
|
+
return false if (c[:tags]||[]).include?('new') and not with.include?('new')
|
105
106
|
with.all?{ |t| (c[:tags]||[]).include?(t) } and without.all?{ |t| !(c[:tags]||[]).include?(t) }
|
106
107
|
end
|
107
108
|
end
|
data/lib/ceml/models/castable.rb
CHANGED
@@ -1,30 +1,12 @@
|
|
1
1
|
module CEML
|
2
|
-
class Castable < Struct.new :type, :stanza_name, :matching, :radius, :timewindow, :roles, :bytecode
|
2
|
+
class Castable < Struct.new :type, :stanza_name, :matching, :radius, :timewindow, :roles, :bytecode, :bundle_id
|
3
3
|
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
hot_players = hotties.keys.map{ |id| Player.new(id).data.value } + [player]
|
9
|
-
# puts "casting from #{hot_players.inspect}"
|
10
|
-
if cast = cast_from(hot_players)
|
11
|
-
puts "...cast with cast #{cast.player_ids.inspect}"
|
12
|
-
audition_ids = (cast.player_ids & hotties.keys).map{ |id| hotties[id] }
|
13
|
-
puts "consuming #{audition_ids.inspect}"
|
14
|
-
if Audition.consume(audition_ids, room_ids)
|
15
|
-
# post audition signs in waiting rooms for remaining parts
|
16
|
-
with_open_roles(cast) do |idx, role, count|
|
17
|
-
waiting_rooms_to_watch(role, cast).each do |room|
|
18
|
-
room.list_job(incident_id, idx, role.name, count)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
return cast
|
22
|
-
else
|
23
|
-
sleep 0.02
|
24
|
-
return cast_player?(incident_id, player)
|
4
|
+
def advertise_roles(incident_id, cast)
|
5
|
+
with_open_roles(cast) do |idx, role, count|
|
6
|
+
waiting_rooms_to_watch(role, cast).each do |room|
|
7
|
+
room.list_job(incident_id, idx, role.name, count)
|
25
8
|
end
|
26
9
|
end
|
27
|
-
return
|
28
10
|
end
|
29
11
|
|
30
12
|
def waiting_rooms_for_player(player, seeded=false)
|
@@ -37,8 +19,8 @@ module CEML
|
|
37
19
|
|
38
20
|
def hot_waiting_rooms_given_player(player, seeded=false)
|
39
21
|
rooms = waiting_rooms_for_player(player, seeded)
|
40
|
-
roles.each{ |r| rooms.concat(["#{stanza_name}:#{r.name}", *r.tagspec.with]) }
|
41
|
-
rooms << "#{stanza_name}:*"
|
22
|
+
roles.each{ |r| rooms.concat(["#{bundle_id}:#{stanza_name}:#{r.name}", *r.tagspec.with]) }
|
23
|
+
rooms << "#{bundle_id}:#{stanza_name}:*"
|
42
24
|
# rooms << 'generic'
|
43
25
|
rooms.uniq
|
44
26
|
end
|
@@ -47,8 +29,8 @@ module CEML
|
|
47
29
|
# skip for now: radius, timewindow, matching, general
|
48
30
|
result = []
|
49
31
|
if stanza_name
|
50
|
-
result << "#{stanza_name}:#{role.name}"
|
51
|
-
result << "#{stanza_name}:*"
|
32
|
+
result << "#{bundle_id}:#{stanza_name}:#{role.name}"
|
33
|
+
result << "#{bundle_id}:#{stanza_name}:*"
|
52
34
|
end
|
53
35
|
if !role.tagspec.with.empty?
|
54
36
|
result.concat role.tagspec.with
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module CEML
|
2
|
+
class CastingPool < Struct.new :room_ids
|
3
|
+
def self.destroy_everywhere(bundle_id, player_id)
|
4
|
+
CastingTokens.destroy([player_id])
|
5
|
+
end
|
6
|
+
|
7
|
+
def player_ids
|
8
|
+
tokens = CastingTokens.all_tokens(room_ids)
|
9
|
+
@tokens_by_player_id = tokens.inject({}){ |m,o| m[o]=o; m }
|
10
|
+
@tokens_by_player_id.keys
|
11
|
+
end
|
12
|
+
|
13
|
+
def hot_players
|
14
|
+
player_ids.map{ |id| Player.new(id).data.value }
|
15
|
+
end
|
16
|
+
|
17
|
+
def claim(player_ids)
|
18
|
+
tokens = @tokens_by_player_id.values_at(*player_ids)
|
19
|
+
CastingTokens.collect(tokens)
|
20
|
+
end
|
21
|
+
|
22
|
+
def post(bundle_id, player_id)
|
23
|
+
CastingTokens.post(bundle_id, player_id, room_ids)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module CEML
|
2
|
+
class Audition < Struct.new(:id)
|
3
|
+
include Redis::Objects
|
4
|
+
set :rooms
|
5
|
+
end
|
6
|
+
|
7
|
+
module CastingTokens
|
8
|
+
def self.post(bundle_id, token, room_ids)
|
9
|
+
room_ids << bundle_id
|
10
|
+
room_ids.each do |room_id|
|
11
|
+
Audition.new(token).rooms << room_id
|
12
|
+
WaitingRoom.new(room_id).waiting_auditions << token
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.all_tokens(room_ids)
|
17
|
+
rooms = room_ids.map{ |r| WaitingRoom.new(r) }
|
18
|
+
rooms.map{ |r| r.waiting_auditions.members }.flatten.uniq
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.destroy_all(bundle_id)
|
22
|
+
all = WaitingRoom.new(bundle_id).waiting_auditions.members
|
23
|
+
# puts "DESTROYING tokens: #{all.inspect}"
|
24
|
+
destroy(all)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.destroy(tokens)
|
28
|
+
roomsets = tokens.map{ |id| Audition.new(id).rooms }
|
29
|
+
rooms = roomsets.map(&:members).flatten.uniq
|
30
|
+
# puts "Consuming ids #{ids.inspect} from rooms #{rooms.inspect}"
|
31
|
+
# TODO: install new redis and re-enable watchlist
|
32
|
+
# redis.watch(*roomsets.map(&:key))
|
33
|
+
# redis.multi do
|
34
|
+
# rooms = roomsets.first.union(roomsets[1,-1]) || []
|
35
|
+
rooms.product(tokens).each do |r, id|
|
36
|
+
# puts "DELETING #{id} from room #{r}"
|
37
|
+
WaitingRoom.new(r).waiting_auditions.delete(id)
|
38
|
+
end
|
39
|
+
roomsets.map(&:clear)
|
40
|
+
# end
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
# this one should collect none unless all can be collected
|
45
|
+
# using multi/exec
|
46
|
+
def self.collect(tokens)
|
47
|
+
destroy(tokens)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
data/lib/ceml/models/incident.rb
CHANGED
@@ -31,13 +31,14 @@ module CEML
|
|
31
31
|
guyroles = roles.to_a - [:everyone, :players, :them, :all, :either, :each, :agents, :both]
|
32
32
|
instr ||= []
|
33
33
|
|
34
|
-
|
34
|
+
# CEML.log 3, "#{p[:id]}: #{state} -- #{instr[1]}/#{instr[0]} -- #{instr[2].inspect} -- #{id}##{pc}(#{guyroles})"
|
35
35
|
end
|
36
36
|
|
37
|
-
|
38
37
|
def run(players, &blk)
|
39
38
|
@players = players
|
40
39
|
@callback = blk
|
40
|
+
was_blocked = {}
|
41
|
+
# CEML.log 1, "running players: #{players.inspect}"
|
41
42
|
|
42
43
|
loop do
|
43
44
|
players = @players
|
@@ -45,24 +46,25 @@ module CEML
|
|
45
46
|
players.each do |p|
|
46
47
|
@this = p
|
47
48
|
instr = seq[pc]
|
49
|
+
# log "running: #{pc}: #{instr.inspect}"
|
48
50
|
unless instr = seq[pc]
|
49
|
-
log 'off schedule'
|
50
51
|
@players.delete(p)
|
51
|
-
cb :released
|
52
52
|
next
|
53
53
|
end
|
54
54
|
instr = instr.dup
|
55
55
|
rolespec = instr.shift
|
56
56
|
if not rolematch(rolespec)
|
57
|
-
log "skipping[#{rolespec}]"
|
57
|
+
# log "skipping[#{rolespec}]"
|
58
58
|
this[:pc]+=1
|
59
59
|
advanced = true
|
60
60
|
else
|
61
61
|
instr << role_info if instr.first == :start #tmp hack
|
62
62
|
if send(*instr)
|
63
63
|
log 'completed'
|
64
|
+
was_blocked[p] = false
|
64
65
|
else
|
65
|
-
log 'blocked'
|
66
|
+
log 'blocked' unless was_blocked[p]
|
67
|
+
was_blocked[p] = true
|
66
68
|
next
|
67
69
|
end
|
68
70
|
cb(*instr)
|
@@ -20,13 +20,13 @@ module CEML
|
|
20
20
|
folks.each do |player|
|
21
21
|
Player.new(player[:id]).touch(id)
|
22
22
|
player_roles[player[:id]] = [rolename.to_sym]
|
23
|
-
|
23
|
+
CEML.log 3, "#{player[:id]}: added as #{rolename.to_sym} (#{id})"
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
def release(player_id)
|
29
|
-
|
29
|
+
CEML.log 3, "#{player_id}: releasing from incident #{id}"
|
30
30
|
Player.new(player_id).clear_incident(id)
|
31
31
|
player_roles.delete(player_id)
|
32
32
|
end
|
@@ -51,17 +51,17 @@ module CEML
|
|
51
51
|
metadata, player_data = *data.value
|
52
52
|
metadata ||= { :id => id }
|
53
53
|
player_data ||= {}
|
54
|
-
puts "[#{id}] Player data loaded: #{player_data.inspect}"
|
55
54
|
players = []
|
56
55
|
|
57
|
-
|
56
|
+
CEML.log 3, ">>> #{player_roles.all.inspect} (#{id})"
|
58
57
|
player_roles.each do |player_id, roles|
|
59
|
-
|
58
|
+
CEML.log 3, "#{player_id}: casted as #{roles.inspect} -- #{id}: #{player_data[player_id].inspect}"
|
60
59
|
player = { :id => player_id, :roles => Set.new(roles) }
|
61
60
|
player[:roles] << :agents << :players << :both << :all << :each << :everyone << :them << :either
|
62
61
|
player.merge! player_data[player_id] if player_data[player_id]
|
63
62
|
p = Player.new(player_id)
|
64
63
|
stored_player = p.data.value
|
64
|
+
PLAYER_THREAD_FIELDS.each{ |x| stored_player.delete x }
|
65
65
|
msg = p.message.value
|
66
66
|
player.merge! msg if msg
|
67
67
|
player.merge! stored_player if stored_player
|
@@ -86,8 +86,9 @@ module CEML
|
|
86
86
|
players.each do |p|
|
87
87
|
Player.new(p[:id]).message.value = p.like(:received, :recognized, :situation)
|
88
88
|
player_data[p[:id]] = p.like *PLAYER_THREAD_FIELDS
|
89
|
+
# PLAYER_THREAD_FIELDS.each{ |x| p.delete x }
|
89
90
|
end
|
90
|
-
|
91
|
+
# CEML.log 1, "Player data saving: #{player_data.inspect}"
|
91
92
|
data.value = [metadata, player_data]
|
92
93
|
|
93
94
|
if next_run = players.map{ |p| p[:continue_at] }.compact.min
|
data/lib/ceml/models/player.rb
CHANGED
@@ -6,17 +6,20 @@ module CEML
|
|
6
6
|
value :message, :marshal => true
|
7
7
|
sorted_set :current_incidents
|
8
8
|
|
9
|
-
def touch(incident_id)
|
10
|
-
current_incidents[incident_id] = Time.now.to_i
|
11
|
-
end
|
12
|
-
|
13
9
|
def reset
|
14
|
-
Audition.new(id).clear_from_all_rooms
|
15
10
|
data.clear
|
16
11
|
message.clear
|
17
12
|
current_incidents.clear
|
18
13
|
end
|
19
14
|
|
15
|
+
# =============
|
16
|
+
# = incidents =
|
17
|
+
# =============
|
18
|
+
|
19
|
+
def touch(incident_id)
|
20
|
+
current_incidents[incident_id] = Time.now.to_i
|
21
|
+
end
|
22
|
+
|
20
23
|
def top_incident_id
|
21
24
|
current_incidents.last
|
22
25
|
end
|
@@ -31,6 +34,11 @@ module CEML
|
|
31
34
|
current_incidents.delete(id)
|
32
35
|
end
|
33
36
|
|
37
|
+
|
38
|
+
# ========
|
39
|
+
# = data =
|
40
|
+
# ========
|
41
|
+
|
34
42
|
def self.update bundle_id, player, cb_obj, &blk
|
35
43
|
player[:bundle_id] = player[:squad_id] = bundle_id
|
36
44
|
new(player[:id].to_s).update player, cb_obj, &blk
|
@@ -69,7 +77,7 @@ module CEML
|
|
69
77
|
new_message, player = split(player)
|
70
78
|
merge_new_player_data(player)
|
71
79
|
cmd = new_message[:recognized]
|
72
|
-
if cmd and cb_obj.recognize_override(cmd, new_message, player, self)
|
80
|
+
if cmd and cb_obj and cb_obj.recognize_override(cmd, new_message, player, self)
|
73
81
|
message.delete
|
74
82
|
else
|
75
83
|
message.value = new_message
|
@@ -5,18 +5,11 @@ module CEML
|
|
5
5
|
set :waiting_auditions
|
6
6
|
set :waiting_incident_roles
|
7
7
|
|
8
|
-
def clear
|
9
|
-
waiting_auditions.each do |audition_id|
|
10
|
-
Audition.new(audition_id).clear_from_all_rooms(id)
|
11
|
-
end
|
12
|
-
waiting_incident_roles.clear
|
13
|
-
end
|
14
|
-
|
15
8
|
def audition_for_incidents(player)
|
16
|
-
|
17
|
-
|
9
|
+
reorder = waiting_incident_roles.members.sort_by{ |irs| irs.split(':')[1] }
|
10
|
+
reorder.each do |key|
|
18
11
|
incident_id, idx, role, count = *key.split(':')
|
19
|
-
|
12
|
+
CEML.log 3, "#{player[:id]}: auditioning against #{incident_id}: #{role}"
|
20
13
|
count = count.to_i
|
21
14
|
role_slot = IncidentRoleSlot.new(incident_id, role, count)
|
22
15
|
next unless role_slot.reserve_spot!
|
@@ -30,11 +23,6 @@ module CEML
|
|
30
23
|
def list_job(incident_id, idx, rolename, count)
|
31
24
|
waiting_incident_roles << [incident_id, idx, rolename, count].join(':')
|
32
25
|
end
|
33
|
-
|
34
|
-
def add(audition_id)
|
35
|
-
puts "adding #{audition_id} to waiting room #{id.inspect}"
|
36
|
-
waiting_auditions << audition_id
|
37
|
-
end
|
38
26
|
end
|
39
27
|
|
40
28
|
end
|
data/lib/ceml/processor.rb
CHANGED
@@ -15,6 +15,7 @@ module CEML
|
|
15
15
|
|
16
16
|
def set_bundle(id, castables)
|
17
17
|
# log "set_bundle(): #{id}, #{castables.inspect}"
|
18
|
+
castables.each{ |c| c.bundle_id = id }
|
18
19
|
Bundle.new(id).castables = castables
|
19
20
|
end
|
20
21
|
|
@@ -62,7 +63,7 @@ module CEML
|
|
62
63
|
end
|
63
64
|
|
64
65
|
def reset_player(bundle_id, player_id)
|
65
|
-
|
66
|
+
Bundle.new(bundle_id).reset_player(player_id)
|
66
67
|
end
|
67
68
|
|
68
69
|
# =============
|
@@ -70,9 +71,10 @@ module CEML
|
|
70
71
|
# =============
|
71
72
|
|
72
73
|
def simple_audition(bundle_id, player)
|
73
|
-
log "audition(): #{bundle_id}, #{player[:id]}"
|
74
|
+
# log "audition(): #{bundle_id}, #{player[:id]}"
|
74
75
|
b = Bundle.new(bundle_id)
|
75
|
-
b.clear_from_all_rooms(player)
|
76
|
+
b.clear_from_all_rooms(player[:id])
|
77
|
+
|
76
78
|
if incident_id = b.absorb?(player)
|
77
79
|
IncidentModel.new(incident_id).run(self)
|
78
80
|
return true
|
@@ -82,13 +84,20 @@ module CEML
|
|
82
84
|
end
|
83
85
|
|
84
86
|
def seed(bundle_id, stanza_name, player)
|
85
|
-
log "seed(): #{bundle_id}, #{stanza_name}, #{player[:id]}"
|
87
|
+
# log "seed(): #{bundle_id}, #{stanza_name}, #{player[:id]}"
|
88
|
+
player[:tags].delete('new')
|
89
|
+
Player.new(player[:id]).merge_new_player_data(player)
|
90
|
+
|
91
|
+
# CEML.log 1, "UPDATED"
|
92
|
+
|
86
93
|
b = Bundle.new(bundle_id)
|
87
94
|
if incident_id = b.absorb?(player, stanza_name)
|
88
95
|
IncidentModel.new(incident_id).run(self)
|
89
|
-
|
96
|
+
true
|
97
|
+
else
|
98
|
+
b.register_in_rooms(player, stanza_name)
|
99
|
+
false
|
90
100
|
end
|
91
|
-
b.register_in_rooms(player, stanza_name)
|
92
101
|
end
|
93
102
|
|
94
103
|
# =============
|
@@ -107,16 +116,16 @@ module CEML
|
|
107
116
|
if incident
|
108
117
|
incident.release(player_obj.id)
|
109
118
|
unlatch(player[:squad_id], player[:id], incident.id)
|
110
|
-
|
119
|
+
reset_player(player[:squad_id], player[:id])
|
111
120
|
tell(player[:squad_id], player[:id], :message, :msg => 'aborted')
|
112
121
|
else
|
113
|
-
|
122
|
+
reset_player(player[:squad_id], player[:id])
|
114
123
|
tell(player[:squad_id], player[:id], :message, :msg => 'nothing to abort from')
|
115
124
|
end
|
116
125
|
end
|
117
126
|
|
118
127
|
def log(s)
|
119
|
-
|
128
|
+
CEML.log 1, s
|
120
129
|
end
|
121
130
|
|
122
131
|
def player_said(data, what)
|
@@ -127,11 +136,8 @@ module CEML
|
|
127
136
|
#no op
|
128
137
|
end
|
129
138
|
|
130
|
-
JUST_SAID = {}
|
131
139
|
def tell(sqid, player_id, key, meta)
|
132
|
-
|
133
|
-
JUST_SAID[player_id] << meta.merge(:key => key)
|
134
|
-
# puts "Said #{key} #{meta.inspect}"
|
140
|
+
CEML.tells[player_id] << meta.merge(:key => key) if CEML.tells
|
135
141
|
end
|
136
142
|
|
137
143
|
def player_answered_q(data, what)
|
@@ -142,8 +148,8 @@ module CEML
|
|
142
148
|
def player_seeded(data, what)
|
143
149
|
p = data[:player].dup
|
144
150
|
p.delete(:roles)
|
145
|
-
p[:seeded] = "#{what[:target]}:#{what[:role]}"
|
146
|
-
|
151
|
+
p[:seeded] = "#{p[:bundle_id]}:#{what[:target]}:#{what[:role]}"
|
152
|
+
CEML.log 3, "#{p[:id]}: seeded as #{p[:seeded]}"
|
147
153
|
|
148
154
|
self.class.seed(p[:bundle_id], what[:target], p)
|
149
155
|
end
|
data/test/dialogues/jordan.ceml
CHANGED
@@ -81,41 +81,43 @@ D < Please text
|
|
81
81
|
D > done
|
82
82
|
D <
|
83
83
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
84
|
+
K > Kiley
|
85
|
+
|
86
|
+
P > Paul
|
87
|
+
P < Welcome
|
88
|
+
P < You wanna
|
89
|
+
P > Yes
|
90
|
+
|
91
|
+
# P < Awesome!
|
92
|
+
# (20s)
|
93
|
+
# P < If you want to opt out
|
94
|
+
#
|
95
|
+
# K < Welcome
|
96
|
+
# K < You wanna
|
97
|
+
# K > Yes
|
98
|
+
# K < Awesome!
|
99
|
+
# (20s)
|
100
|
+
# K < If you want to opt out
|
101
|
+
#
|
102
|
+
# D < Amazing work
|
103
|
+
# D > Yes
|
104
|
+
# D < new challenge
|
105
|
+
# D > Wave and smile at three strangers on the street
|
106
|
+
# D < Thanks for playing
|
107
|
+
# K < Another player has issued
|
108
|
+
# K > Yes
|
109
|
+
# K < Please text
|
110
|
+
# K > done
|
111
|
+
# K <
|
112
|
+
#
|
113
|
+
# (challenge_loop2)
|
114
|
+
# K < Amazing work
|
115
|
+
# K > Yes
|
116
|
+
# K < new challenge
|
117
|
+
# K > Wave and smile at three strangers on the street
|
118
|
+
# K < Thanks for playing
|
119
|
+
# P < Another player has issued
|
120
|
+
# P > Yes
|
121
|
+
# P < Please text
|
122
|
+
# P > done
|
123
|
+
# P <
|
data/test/helper.rb
CHANGED
@@ -18,7 +18,7 @@ class Test::Unit::TestCase
|
|
18
18
|
end
|
19
19
|
if script
|
20
20
|
@iid = gen_code
|
21
|
-
puts "launching w. bytecode #{script.bytecode.inspect}"
|
21
|
+
# puts "launching w. bytecode #{script.bytecode.inspect}"
|
22
22
|
CEML::Processor.launch(@iid, script.bytecode)
|
23
23
|
CEML::Processor.run
|
24
24
|
end
|
@@ -40,7 +40,7 @@ class Test::Unit::TestCase
|
|
40
40
|
player = {:id => id.to_s, :received => str}
|
41
41
|
player[:recognized] = :yes if str.downcase == 'y' || str.downcase == 'yes'
|
42
42
|
player[:recognized] = :abort if str == 'abort'
|
43
|
-
puts "SAYING(#{id}): #{str}"
|
43
|
+
# puts "SAYING(#{id}): #{str}"
|
44
44
|
CEML::Processor.ping(nil, player)
|
45
45
|
CEML::Processor.run
|
46
46
|
end
|
data/test/test_dialogues.rb
CHANGED
@@ -8,51 +8,20 @@ class TestCemlTests < Test::Unit::TestCase
|
|
8
8
|
CEML::Queue.new.calls.clear
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
puts
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
CEML::Processor.set_bundle(bundle_id, s)
|
22
|
-
CEML::Processor.reset_bundle(bundle_id)
|
23
|
-
pl = Set.new
|
24
|
-
play do
|
25
|
-
test.each_line do |line|
|
26
|
-
puts ">>>> #{line}"
|
27
|
-
case line.strip
|
28
|
-
when /^(\w+) *< *(.*)$/
|
29
|
-
if $2.empty?
|
30
|
-
silent $1
|
31
|
-
else
|
32
|
-
told $1, /#{$2}/
|
33
|
-
end
|
34
|
-
when /^(\w+) *> *(.*)$/
|
35
|
-
player_id, msg = $1, $2
|
36
|
-
player = {:id => player_id, :received => msg }
|
37
|
-
if !pl.include?(player_id)
|
38
|
-
player[:tags] = ['new']
|
39
|
-
pl << player_id
|
40
|
-
end
|
41
|
-
player[:recognized] = :yes if msg == 'y' || msg =~ /^yes/i
|
42
|
-
player[:recognized] = :abort if msg == 'abort'
|
43
|
-
player[:recognized] = :done if msg =~ /^done/i || msg == 'd'
|
44
|
-
CEML::Processor.ping(bundle_id, player)
|
45
|
-
CEML::Processor.run
|
46
|
-
when /^\((\d+)\s*(\w+)\)$/
|
47
|
-
CEML.incr_clock CEML.dur($1.to_i, $2)
|
48
|
-
CEML::Processor.run_latest
|
49
|
-
CEML::Processor.run
|
50
|
-
when /^#/
|
51
|
-
else "Skipping line #{line}..."
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
11
|
+
def run_cemltest f
|
12
|
+
name = File.basename(f, '.ceml')
|
13
|
+
err, log = CEML.test(File.new(f).read)
|
14
|
+
if !err
|
15
|
+
puts "PASS cemltest #{name}. logged #{log.split("\n").size} lines"
|
16
|
+
elsif RuntimeError === err
|
17
|
+
puts log
|
18
|
+
raise "ERROR with cemltest #{name}: #{err.message}!"
|
19
|
+
else
|
20
|
+
raise err
|
55
21
|
end
|
56
22
|
end
|
57
23
|
|
24
|
+
def test_cemltests
|
25
|
+
Dir["test/dialogues/*.ceml"].each{ |f| run_cemltest(f) }
|
26
|
+
end
|
58
27
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ceml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 59
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 9
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.9.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Joe Edelman
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-06-07 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -49,6 +49,7 @@ files:
|
|
49
49
|
- Rakefile
|
50
50
|
- VERSION
|
51
51
|
- ceml.gemspec
|
52
|
+
- cemltest
|
52
53
|
- editors/CEML.tmbundle/Syntaxes/ceml.tmLanguage
|
53
54
|
- editors/CEML.tmbundle/info.plist
|
54
55
|
- examples/breakfast-exchange.ceml
|
@@ -73,10 +74,11 @@ files:
|
|
73
74
|
- lib/ceml/lang/tt/scripts.rb
|
74
75
|
- lib/ceml/lang/tt/scripts.treetop
|
75
76
|
- lib/ceml/models.rb
|
76
|
-
- lib/ceml/models/audition.rb
|
77
77
|
- lib/ceml/models/bundle.rb
|
78
78
|
- lib/ceml/models/cast.rb
|
79
79
|
- lib/ceml/models/castable.rb
|
80
|
+
- lib/ceml/models/casting_pool.rb
|
81
|
+
- lib/ceml/models/casting_tokens.rb
|
80
82
|
- lib/ceml/models/incident.rb
|
81
83
|
- lib/ceml/models/incident_model.rb
|
82
84
|
- lib/ceml/models/incident_role_slot.rb
|
@@ -84,6 +86,7 @@ files:
|
|
84
86
|
- lib/ceml/models/queue.rb
|
85
87
|
- lib/ceml/models/waiting_room.rb
|
86
88
|
- lib/ceml/processor.rb
|
89
|
+
- lib/ceml/recognizer.rb
|
87
90
|
- test/askchain.ceml
|
88
91
|
- test/compliment.ceml
|
89
92
|
- test/dialogues/accept.ceml
|
data/lib/ceml/models/audition.rb
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
module CEML
|
2
|
-
|
3
|
-
class Audition < Struct.new(:id) # "#{code}:#{player_id}"
|
4
|
-
include Redis::Objects
|
5
|
-
set :rooms
|
6
|
-
|
7
|
-
def list_in_rooms(da_rooms)
|
8
|
-
# p "Listing in rooms #{da_rooms.map(&:id)}"
|
9
|
-
da_rooms.each{ |room| self.rooms << room.id; room.add(id) }
|
10
|
-
end
|
11
|
-
|
12
|
-
def clear_from_all_rooms(*extra_rooms)
|
13
|
-
rooms_to_clear = rooms.members + extra_rooms
|
14
|
-
redis.multi do
|
15
|
-
rooms_to_clear.each do |r|
|
16
|
-
WaitingRoom.new(r).waiting_auditions.delete(id)
|
17
|
-
end
|
18
|
-
redis.del rooms.key
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.consume(ids, extra_rooms = [])
|
23
|
-
roomsets = ids.map{ |id| Audition.new(id).rooms }
|
24
|
-
rooms = (roomsets.map(&:members) + extra_rooms).flatten.uniq
|
25
|
-
# puts "Consuming ids #{ids.inspect} from rooms #{rooms.inspect}"
|
26
|
-
# TODO: install new redis and re-enable watchlist
|
27
|
-
# redis.watch(*roomsets.map(&:key))
|
28
|
-
# redis.multi do
|
29
|
-
# rooms = roomsets.first.union(roomsets[1,-1]) || []
|
30
|
-
rooms.each do |r|
|
31
|
-
# puts "PROCESSING ROOM #{r.key}"
|
32
|
-
ids.each do |id|
|
33
|
-
# puts "DELETING #{id} from room #{r}"
|
34
|
-
WaitingRoom.new(r).waiting_auditions.delete(id)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
roomsets.map(&:clear)
|
38
|
-
# end
|
39
|
-
true
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.from_rooms(room_ids)
|
43
|
-
players = {}
|
44
|
-
rooms = room_ids.map{ |r| WaitingRoom.new(r) }
|
45
|
-
auditions = rooms.map{ |r| r.waiting_auditions.members }.flatten
|
46
|
-
|
47
|
-
# clear old style
|
48
|
-
auditions.each do |a|
|
49
|
-
next unless a =~ /:/
|
50
|
-
Audition.new(a).rooms.clear
|
51
|
-
rooms.each{ |r| r.waiting_auditions.delete(a) }
|
52
|
-
end
|
53
|
-
|
54
|
-
puts "Auditions found: #{auditions.inspect}"
|
55
|
-
auditions.each do |audition|
|
56
|
-
# next if audition =~ /:/
|
57
|
-
# code, player_id = audition.split(':')
|
58
|
-
player_id = audition
|
59
|
-
players[player_id] ||= audition
|
60
|
-
end
|
61
|
-
players
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
end
|