MonkeyEngine 1.0.0
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.idea/.name +1 -0
- data/.idea/.rakeTasks +7 -0
- data/.idea/MonkeyEngine.iml +133 -0
- data/.idea/codeStyleSettings.xml +13 -0
- data/.idea/encodings.xml +5 -0
- data/.idea/misc.xml +5 -0
- data/.idea/modules.xml +9 -0
- data/.idea/runConfigurations/All_specs_in_test__MonkeyEngine.xml +38 -0
- data/.idea/runConfigurations/IRB_console.xml +25 -0
- data/.idea/runConfigurations/Start_Yard_Server.xml +26 -0
- data/.idea/runConfigurations/monkey_run.xml +26 -0
- data/.idea/scopes/scope_settings.xml +5 -0
- data/.idea/vcs.xml +7 -0
- data/.idea/workspace.xml +886 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +3 -0
- data/lib/Action/action.rb +29 -0
- data/lib/Monkey.rb +1 -0
- data/lib/Monkey/monkey.rb +108 -0
- data/lib/MonkeyAction/monkey_action.rb +14 -0
- data/lib/MonkeyAction/monkey_action_dead.rb +26 -0
- data/lib/MonkeyAction/monkey_action_eat.rb +31 -0
- data/lib/MonkeyAction/monkey_action_pause.rb +32 -0
- data/lib/MonkeyAction/monkey_action_sleep.rb +31 -0
- data/lib/MonkeyAction/monkey_action_type.rb +40 -0
- data/lib/MonkeyAction/monkey_action_wake.rb +26 -0
- data/lib/MonkeyAction/monkey_timed_action.rb +27 -0
- data/lib/MonkeyActions.rb +6 -0
- data/lib/MonkeyEngine.rb +1 -0
- data/lib/MonkeyEngine/action_rules.rb +111 -0
- data/lib/MonkeyEngine/exceptions.rb +21 -0
- data/lib/MonkeyEngine/monkey_engine.rb +53 -0
- data/lib/MonkeyEngine/version.rb +3 -0
- data/lib/MonkeyFactory.rb +1 -0
- data/lib/MonkeyFactory/monkey_factory.rb +14 -0
- data/lib/MonkeyKeyboard/keyboard_char.rb +10 -0
- data/lib/MonkeyKeyboard/keyboard_input.rb +14 -0
- data/lib/MonkeyKeyboard/keyboard_key.rb +26 -0
- data/lib/MonkeyKeyboard/keyboard_key_evaluator.rb +25 -0
- data/lib/MonkeyKeyboard/monkey_keyboard_en_us.rb +137 -0
- data/lib/MonkeyKeyboardEnUs.rb +1 -0
- data/lib/MonkeyManager.rb +1 -0
- data/lib/MonkeyManager/monkey_manager.rb +162 -0
- data/lib/MonkeyService.rb +1 -0
- data/lib/MonkeyService/monkey_service.rb +137 -0
- data/lib/tasks/engine.rb +91 -0
- data/monkeyengine.gemspec +32 -0
- data/spec/action_rules_spec.rb +59 -0
- data/spec/engine_spec.rb +56 -0
- data/spec/keyboard_char_spec.rb +12 -0
- data/spec/keyboard_key_spec.rb +15 -0
- data/spec/monkey_action_eat_spec.rb +86 -0
- data/spec/monkey_action_pause_spec.rb +91 -0
- data/spec/monkey_action_sleep_spec.rb +90 -0
- data/spec/monkey_action_type_spec.rb +94 -0
- data/spec/monkey_action_wake_spec.rb +58 -0
- data/spec/monkey_factory_spec.rb +23 -0
- data/spec/monkey_keyboard_en_us_spec.rb +42 -0
- data/spec/monkey_manager_spec.rb +8 -0
- data/spec/monkey_service_spec.rb +96 -0
- data/spec/monkey_spec.rb +8 -0
- data/spec/spec_helpers.rb +20 -0
- data/spec/support/shared_examples.rb +41 -0
- metadata +258 -0
@@ -0,0 +1,6 @@
|
|
1
|
+
require_relative 'MonkeyAction/monkey_action_dead'
|
2
|
+
require_relative 'MonkeyAction/monkey_action_eat'
|
3
|
+
require_relative 'MonkeyAction/monkey_action_pause'
|
4
|
+
require_relative 'MonkeyAction/monkey_action_sleep'
|
5
|
+
require_relative 'MonkeyAction/monkey_action_type'
|
6
|
+
require_relative 'MonkeyAction/monkey_action_wake'
|
data/lib/MonkeyEngine.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'MonkeyEngine/monkey_engine'
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'singleton'
|
3
|
+
|
4
|
+
require 'MonkeyActions'
|
5
|
+
require 'MonkeyKeyboardEnUs'
|
6
|
+
|
7
|
+
# Handles monkey action rules.
|
8
|
+
class ActionRules
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
# Retrieves tne next action for the monkey
|
12
|
+
#
|
13
|
+
# @param [monkey] the monkey whose next action is to be retrieved
|
14
|
+
# @return [MonkeyAction] the next monkey action
|
15
|
+
def get_next_action(monkey)
|
16
|
+
raise MonkeyEngine::Exceptions::InvalidOperationException.new \
|
17
|
+
"The action [#{monkey.action.class.name}] for Monkey [#{monkey.monkey_symbol}] must be completed before calling get_next_action" \
|
18
|
+
unless monkey.action.nil? || monkey.action.action_completed?
|
19
|
+
|
20
|
+
# current_action = monkey.action
|
21
|
+
|
22
|
+
# If the monkey is sleeping, or first action, wake him up.
|
23
|
+
return MonkeyActionWake.new(monkey) if monkey.action.nil? || monkey.action.is_a?(MonkeyActionSleep)
|
24
|
+
|
25
|
+
return get_next_action_eval(monkey) unless nil
|
26
|
+
|
27
|
+
# Nothing else interesting, monkey takes a breather...
|
28
|
+
# MonkeyActionPause.new(monkey, Random.new.rand(MonkeyActionPause::VALID_VALUES))
|
29
|
+
MonkeyActionPause.new(monkey, 5)
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_next_action_eval(monkey)
|
33
|
+
# TODO: Add logic to determine next logical action.
|
34
|
+
|
35
|
+
keyboard_input = MonkeyEngine::MonkeyKeyboardEnUs.instance.get_keyboard_input
|
36
|
+
|
37
|
+
return MonkeyActionType.new monkey, keyboard_input
|
38
|
+
end
|
39
|
+
|
40
|
+
# Evaluates an action and sets it to completed if the criteria for completion is met.
|
41
|
+
def action_eval!(action)
|
42
|
+
raise MonkeyEngine::Exceptions::NilArgumentException.new "The [action] to be evaluated cannot be nil" \
|
43
|
+
if action.nil?
|
44
|
+
|
45
|
+
raise MonkeyEngine::Exceptions::InvalidArgumentTypeException.new "The [action] is not the correct type" \
|
46
|
+
unless action.is_a? Action
|
47
|
+
|
48
|
+
action_eval_eat(action) if action.is_a?(MonkeyActionEat)
|
49
|
+
action_eval_pause(action) if action.is_a?(MonkeyActionPause)
|
50
|
+
action_eval_sleep(action) if action.is_a?(MonkeyActionSleep)
|
51
|
+
action_eval_type(action) if action.is_a?(MonkeyActionType)
|
52
|
+
action_eval_wake(action) if action.is_a?(MonkeyActionWake)
|
53
|
+
|
54
|
+
# If we don't specifically handle the action, just let it pass through - Action#action_completed will
|
55
|
+
# be set elsewhere.
|
56
|
+
action.action_completed?
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# Action evaluation methods
|
62
|
+
|
63
|
+
def action_eval_eat(action)
|
64
|
+
raise MonkeyEngine::Exceptions::InvalidArgumentTypeException.new "The [action] is not the correct type" \
|
65
|
+
unless action.is_a? MonkeyActionEat
|
66
|
+
|
67
|
+
action_eval_timed_action action
|
68
|
+
end
|
69
|
+
|
70
|
+
def action_eval_pause(action)
|
71
|
+
raise MonkeyEngine::Exceptions::InvalidArgumentTypeException.new "The [action] is not the correct type" \
|
72
|
+
unless action.is_a? MonkeyActionPause
|
73
|
+
|
74
|
+
action_eval_timed_action action
|
75
|
+
end
|
76
|
+
|
77
|
+
def action_eval_sleep(action)
|
78
|
+
raise MonkeyEngine::Exceptions::InvalidArgumentTypeException.new "The [action] is not the correct type" \
|
79
|
+
unless action.is_a? MonkeyActionSleep
|
80
|
+
|
81
|
+
action_eval_timed_action action
|
82
|
+
end
|
83
|
+
|
84
|
+
def action_eval_type(action)
|
85
|
+
raise MonkeyEngine::Exceptions::InvalidArgumentTypeException.new "The [action] is not the correct type" \
|
86
|
+
unless action.is_a? MonkeyActionType
|
87
|
+
|
88
|
+
# TODO: How do I evaluate this?
|
89
|
+
|
90
|
+
action
|
91
|
+
end
|
92
|
+
|
93
|
+
def action_eval_wake(action)
|
94
|
+
raise MonkeyEngine::Exceptions::InvalidArgumentTypeException.new "The [action] is not the correct type" \
|
95
|
+
unless action.is_a? MonkeyActionWake
|
96
|
+
|
97
|
+
action.action_completed = true
|
98
|
+
|
99
|
+
action
|
100
|
+
end
|
101
|
+
|
102
|
+
def action_eval_timed_action(action)
|
103
|
+
raise MonkeyEngine::Exceptions::InvalidArgumentTypeException.new "The [action] is not the correct type" \
|
104
|
+
unless action.is_a? MonkeyTimedAction
|
105
|
+
|
106
|
+
action.action_completed = true if action.action_time_of_completion <= Time.now
|
107
|
+
|
108
|
+
action
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'test/unit/assertions'
|
2
|
+
|
3
|
+
module MonkeyEngine
|
4
|
+
module Exceptions
|
5
|
+
class InvalidArgumentValueException < ArgumentError;
|
6
|
+
end
|
7
|
+
|
8
|
+
class InvalidArgumentTypeException < ArgumentError;
|
9
|
+
end
|
10
|
+
|
11
|
+
class NilArgumentException < ArgumentError;
|
12
|
+
end
|
13
|
+
|
14
|
+
# The object must be unique.
|
15
|
+
class UniqueObjectException < ArgumentError;
|
16
|
+
end
|
17
|
+
|
18
|
+
class InvalidOperationException < ArgumentError;
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'observer'
|
2
|
+
require 'singleton'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
require 'MonkeyActions'
|
6
|
+
require_relative 'action_rules'
|
7
|
+
|
8
|
+
module MonkeyEngine
|
9
|
+
|
10
|
+
# Assigns, executes and evaluates actions.
|
11
|
+
class Engine
|
12
|
+
include Singleton
|
13
|
+
include Observable
|
14
|
+
|
15
|
+
private
|
16
|
+
def initialize
|
17
|
+
end
|
18
|
+
|
19
|
+
public
|
20
|
+
|
21
|
+
# Evaluates whether or not the action is completed.
|
22
|
+
def action_eval!(action)
|
23
|
+
ActionRules.instance.action_eval! action
|
24
|
+
end
|
25
|
+
|
26
|
+
def do_action(action)
|
27
|
+
raise MonkeyEngine::Exceptions::InvalidOperationException.new \
|
28
|
+
"The action [#{action.class.name}] for Monkey [#{action.monkey.monkey_symbol}] is already completed" if action.action_completed?
|
29
|
+
|
30
|
+
do_action_type(action) if action.is_a? MonkeyActionType
|
31
|
+
|
32
|
+
# TODO: Update database for monkey with action detail
|
33
|
+
# TODO: Call observer to notify of action update.
|
34
|
+
# TODO: Set action.action_completed to true if the action is completed.
|
35
|
+
|
36
|
+
action.action_completed?
|
37
|
+
end
|
38
|
+
|
39
|
+
def do_action_type(action)
|
40
|
+
action.action_completed = true
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns a new action.
|
44
|
+
def new_action(monkey)
|
45
|
+
raise MonkeyEngine::Exceptions::InvalidOperationException.new \
|
46
|
+
"The action [#{monkey.action.class.name}] for Monkey [#{monkey.monkey_symbol}] must be completed before calling new_action" \
|
47
|
+
unless monkey.action.nil? || monkey.action.action_completed?
|
48
|
+
|
49
|
+
return ActionRules.instance.get_next_action monkey
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'MonkeyFactory/monkey_factory'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative 'keyboard_char'
|
2
|
+
|
3
|
+
# Represents a keyboard key.
|
4
|
+
class KeyboardKey
|
5
|
+
attr_reader :keyboard_char, :keyboard_shift_char, :keyboard_key_section, :keyboard_key_weight
|
6
|
+
|
7
|
+
def initialize(keyboard_char, keyboard_shift_char, keyboard_key_section, keyboard_key_weight)
|
8
|
+
# TODO: Check keyboard_char is_a? KeyboardChar
|
9
|
+
# TODO: Check keyboard_shift_char is_a? KeyboardChar
|
10
|
+
# TODO: Check keyboard_key_section is :left or :right
|
11
|
+
|
12
|
+
@keyboard_char = keyboard_char
|
13
|
+
@keyboard_shift_char = keyboard_shift_char
|
14
|
+
@keyboard_key_section = keyboard_key_section
|
15
|
+
@keyboard_key_weight = keyboard_key_weight
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.make_key(char, shift_char, keyboard_key_section, keyboard_key_weight)
|
19
|
+
# TODO: Check keyboard_key_section is :left or :right
|
20
|
+
|
21
|
+
keyboard_char = KeyboardChar.new char
|
22
|
+
keyboard_shift_char = KeyboardChar.new shift_char
|
23
|
+
|
24
|
+
KeyboardKey.new keyboard_char, keyboard_shift_char, keyboard_key_section, keyboard_key_weight
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class KeyboardKeyEvaluator
|
2
|
+
def initialize
|
3
|
+
@shift_on = false
|
4
|
+
@caps_on = false
|
5
|
+
end
|
6
|
+
|
7
|
+
def get_char(keyboard_key)
|
8
|
+
@shift_on = !@shift_on if keyboard_key.keyboard_char.char == :shift
|
9
|
+
@caps_on = !@shift_on if keyboard_key.keyboard_char.char == :caps
|
10
|
+
|
11
|
+
return nil if keyboard_key.keyboard_char.char.is_a? Symbol
|
12
|
+
|
13
|
+
if @shift_on
|
14
|
+
return keyboard_key.keyboard_shift_char.char
|
15
|
+
end
|
16
|
+
|
17
|
+
char = keyboard_key.keyboard_char.char
|
18
|
+
|
19
|
+
if @caps_on
|
20
|
+
return char.upcase
|
21
|
+
end
|
22
|
+
|
23
|
+
char
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'LittleWeasel'
|
3
|
+
|
4
|
+
require_relative 'keyboard_char'
|
5
|
+
require_relative 'keyboard_key'
|
6
|
+
require_relative 'keyboard_input'
|
7
|
+
require_relative 'keyboard_key_evaluator'
|
8
|
+
|
9
|
+
|
10
|
+
module MonkeyEngine
|
11
|
+
|
12
|
+
class MonkeyKeyboardEnUs
|
13
|
+
include Singleton
|
14
|
+
|
15
|
+
attr_reader :keys, :left_keys, :right_keys
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
|
19
|
+
@keys = [
|
20
|
+
# Row 1 of 5
|
21
|
+
KeyboardKey::make_key('`', '~', :left, 1),
|
22
|
+
KeyboardKey::make_key('1', '!', :left, 1),
|
23
|
+
KeyboardKey::make_key('2', '@', :left, 1),
|
24
|
+
KeyboardKey::make_key('3', '#', :left, 1),
|
25
|
+
KeyboardKey::make_key('4', '$', :left, 1),
|
26
|
+
KeyboardKey::make_key('5', '%', :left, 1),
|
27
|
+
KeyboardKey::make_key('6', '^', :left, 1),
|
28
|
+
KeyboardKey::make_key('7', '&', :right, 1),
|
29
|
+
KeyboardKey::make_key('8', '*', :right, 1),
|
30
|
+
KeyboardKey::make_key('9', '(', :right, 1),
|
31
|
+
KeyboardKey::make_key('0', ')', :right, 1),
|
32
|
+
KeyboardKey::make_key('-', '_', :right, 1),
|
33
|
+
KeyboardKey::make_key('=', '+', :right, 1),
|
34
|
+
KeyboardKey::make_key(:del, :del, :right, 1),
|
35
|
+
|
36
|
+
# Row 2 of 5
|
37
|
+
KeyboardKey::make_key(:tab, :tab, :left, 2),
|
38
|
+
KeyboardKey::make_key('q', 'Q', :left, 1),
|
39
|
+
KeyboardKey::make_key('w', 'W', :left, 1),
|
40
|
+
KeyboardKey::make_key('e', 'E', :left, 1),
|
41
|
+
KeyboardKey::make_key('r', 'R', :left, 1),
|
42
|
+
KeyboardKey::make_key('t', 'T', :left, 1),
|
43
|
+
KeyboardKey::make_key('y', 'Y', :left, 1),
|
44
|
+
KeyboardKey::make_key('u', 'U', :right, 1),
|
45
|
+
KeyboardKey::make_key('i', 'I', :right, 1),
|
46
|
+
KeyboardKey::make_key('o', 'O', :right, 1),
|
47
|
+
KeyboardKey::make_key('p', 'P', :right, 1),
|
48
|
+
KeyboardKey::make_key('', '{', :right, 1),
|
49
|
+
KeyboardKey::make_key('', '}', :right, 1),
|
50
|
+
KeyboardKey::make_key('\\', '|', :right, 1),
|
51
|
+
|
52
|
+
# Row 3 of 5
|
53
|
+
KeyboardKey::make_key(:caps, :caps, :left, 3),
|
54
|
+
KeyboardKey::make_key('a', 'A', :left, 1),
|
55
|
+
KeyboardKey::make_key('s', 'S', :left, 1),
|
56
|
+
KeyboardKey::make_key('d', 'D', :left, 1),
|
57
|
+
KeyboardKey::make_key('f', 'F', :left, 1),
|
58
|
+
KeyboardKey::make_key('g', 'G', :left, 1),
|
59
|
+
KeyboardKey::make_key('h', 'H', :right, 1),
|
60
|
+
KeyboardKey::make_key('j', 'J', :right, 1),
|
61
|
+
KeyboardKey::make_key('k', 'K', :right, 1),
|
62
|
+
KeyboardKey::make_key('l', 'L', :right, 1),
|
63
|
+
KeyboardKey::make_key(';', ':', :right, 1),
|
64
|
+
KeyboardKey::make_key('\'', '"', :right, 1),
|
65
|
+
KeyboardKey::make_key(:enter, :enter, :right, 2),
|
66
|
+
|
67
|
+
# Row 4 of 5
|
68
|
+
KeyboardKey::make_key(:shift, :shift, :left, 5),
|
69
|
+
KeyboardKey::make_key('z', 'Z', :left, 1),
|
70
|
+
KeyboardKey::make_key('x', 'X', :left, 1),
|
71
|
+
KeyboardKey::make_key('c', 'C', :left, 1),
|
72
|
+
KeyboardKey::make_key('v', 'V', :left, 1),
|
73
|
+
KeyboardKey::make_key('b', 'B', :left, 1),
|
74
|
+
KeyboardKey::make_key('n', 'N', :right, 1),
|
75
|
+
KeyboardKey::make_key('m', 'M', :right, 1),
|
76
|
+
KeyboardKey::make_key(',', '<', :right, 1),
|
77
|
+
KeyboardKey::make_key('.', '>', :right, 1),
|
78
|
+
KeyboardKey::make_key('/', '?', :right, 1),
|
79
|
+
KeyboardKey::make_key(:shift, :shift, :right, 5),
|
80
|
+
|
81
|
+
# Row 5 of 5
|
82
|
+
KeyboardKey::make_key(:space, :space, :left, 2),
|
83
|
+
KeyboardKey::make_key(:space, :space, :right, 2)
|
84
|
+
]
|
85
|
+
|
86
|
+
@left_keys = []
|
87
|
+
@right_keys = []
|
88
|
+
|
89
|
+
@keys.each { |key|
|
90
|
+
# Separate the keys on the left side of the keyboard...
|
91
|
+
key.keyboard_key_weight.times do
|
92
|
+
left_keys.push(key)
|
93
|
+
end if key.keyboard_key_section == :left
|
94
|
+
|
95
|
+
# Separate the keys on the right side of the keyboard...
|
96
|
+
key.keyboard_key_weight.times do
|
97
|
+
right_keys.push(key)
|
98
|
+
end if key.keyboard_key_section == :right
|
99
|
+
}
|
100
|
+
|
101
|
+
@keys.freeze
|
102
|
+
@keys_left.freeze
|
103
|
+
@keys_right.freeze
|
104
|
+
end
|
105
|
+
|
106
|
+
def get_keyboard_input
|
107
|
+
keyboard_input = KeyboardInput.new
|
108
|
+
|
109
|
+
left_keys = @left_keys
|
110
|
+
right_keys = @right_keys
|
111
|
+
|
112
|
+
keys = left_keys.zip(right_keys).flatten.compact.shuffle
|
113
|
+
|
114
|
+
keyboard_key_evaluator = KeyboardKeyEvaluator.new
|
115
|
+
|
116
|
+
# Take the keys until we hit a key that terminates a word...
|
117
|
+
keyboard_input.input = keys.take_while { |key|
|
118
|
+
!keyboard_char_ends_word?(key.keyboard_char.char)
|
119
|
+
}.collect { |key| keyboard_key_evaluator.get_char(key) }.compact
|
120
|
+
|
121
|
+
# Keep going until we get something...
|
122
|
+
keyboard_input = get_keyboard_input if keyboard_input.input.empty?
|
123
|
+
|
124
|
+
keyboard_input.is_word = LittleWeasel::Checker.instance.exists?(keyboard_input.input_to_s,
|
125
|
+
exclude_alphabet: true, strip_whitespace: true, ignore_numeric: false, single_word_mode: true)
|
126
|
+
|
127
|
+
keyboard_input
|
128
|
+
end
|
129
|
+
|
130
|
+
# Returns true if the character causes a word termination.
|
131
|
+
def keyboard_char_ends_word?(char)
|
132
|
+
return char == :tab || char == :enter || char == :space || char == '.'
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'MonkeyKeyboard/monkey_keyboard_en_us'
|