/
engine.rb
executable file
·70 lines (58 loc) · 1.58 KB
/
engine.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class Engine
attr_reader :database
attr_reader :rules
attr_reader :stack
attr_reader :steps
def initialize(database, rules)
@database = database
@rules = rules
@stack = []
@steps = []
end
# Run Forward chaining by iterating over
# the `rules` and running them in order
def forward
@rules.each do |rule|
@steps.push("Running rule #{rule.id}")
rule.run(@database)
end
end
# Run Backward chaining by setting a `goal`
# and a desired value
def backward(goal, value)
rules = @rules.select { |r| r.has_desired_solution(goal, value) }
if rules.count == 1
rule = rules.first
elsif rules.count > 1
u_goal = prompt("What is the next goal?")
u_value = prompt("What is the next value?")
rule = rules.select { |r| r.has_antecedent(u_goal, u_value) }.first
end
if rule.nil?
@steps.push("Asking the user for the correct #{goal}")
@database[goal] = prompt("What is the #{goal}?")
@stack = @stack.reverse.reject! do |rule|
if rule.has_antecedent(goal, value)
@steps.push("Running rule #{rule.id}")
rule.run(@database)
end
end
return
end
if @database.matches(rule.antecedents.map { |a| a.object })
@steps.push("Running rule #{rule.id}")
return rule.run(@database)
end
@stack.push(rule)
rule.antecedents.each do |a|
unless rule.passed
backward(a.object, a.value)
end
end
end
# Ask the user a question
def prompt(question)
print("#{question}\n")
gets.chomp.to_sym
end
end