Skip to content

Commit 617f9e6

Browse files
committed
Observer Pattern
1 parent d9943e2 commit 617f9e6

11 files changed

+319
-0
lines changed

ObserverPattern/Observer.pdf

313 KB
Binary file not shown.

ObserverPattern/binary.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
2+
class Binary < Participant
3+
4+
def init_limits(lower, upper)
5+
num = (lower+upper)/2
6+
end
7+
8+
def do_play(lower, num, upper)
9+
while ((result = @oracle.is_this_the_number?(num)) != :correct) && (@num_attempts <= @max_num_attempts) do
10+
if result == :less_than
11+
upper = num-1
12+
elsif result == :greater_than
13+
lower = num+1
14+
end
15+
num=init_limits(lower, upper)
16+
@num_attempts+=1
17+
end
18+
notify_observers
19+
end
20+
21+
def player_name
22+
self.class.name
23+
end
24+
end

ObserverPattern/linear.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
class Linear < Participant
3+
4+
def init_limits(lower, upper)
5+
num = lower
6+
end
7+
8+
def do_play(lower, num, upper)
9+
notify_observers
10+
while @oracle.is_this_the_number?(num)!=:correct && (@num_attempts <= @max_num_attempts) do
11+
num+=1
12+
@num_attempts+=1
13+
end
14+
end
15+
16+
def player_name
17+
self.class.name
18+
end
19+
end

ObserverPattern/main.rb

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
2+
# Evaluate the performance of participants using different guessing strategies
3+
4+
require_relative 'oracle.rb'
5+
require_relative 'participant.rb'
6+
require_relative 'random_.rb'
7+
require_relative 'linear.rb'
8+
require_relative 'smart_random.rb'
9+
require_relative 'binary.rb'
10+
require_relative 'play_game.rb'
11+
12+
NUM_OF_RUNS = 8
13+
14+
oracle = Oracle.new
15+
16+
total_num_attempts = 0
17+
total_num_failures = 0
18+
19+
players = Array.new
20+
21+
random_player = Random_.new(1,NUM_OF_RUNS, oracle, max_num_attempts: NUM_OF_RUNS*2)
22+
random_player.add_observer do |player|
23+
puts("#{player.player_name} finished the game and took him #{player.num_attempts} to guess the number!")
24+
end
25+
26+
linear_player = Linear.new(1,NUM_OF_RUNS, oracle, max_num_attempts:NUM_OF_RUNS*2)
27+
linear_player.add_observer do |player|
28+
puts("#{player.player_name} is playing !")
29+
end
30+
31+
smart_random_player = SmartRandom.new(1,NUM_OF_RUNS, oracle, max_num_attempts:NUM_OF_RUNS*5)
32+
smart_random_player.add_observer do |player|
33+
puts("#{player.player_name} finished the game and took him #{player.num_attempts} to guess the number!")
34+
end
35+
36+
binary_player = Binary.new(1,NUM_OF_RUNS, oracle, max_num_attempts:NUM_OF_RUNS*5)
37+
binary_player.add_observer do |player|
38+
puts("#{player.player_name} made an successful attempt and took him #{player.num_attempts}!")
39+
end
40+
41+
players.push(PlayGame.new(random_player))
42+
players.push(PlayGame.new(linear_player))
43+
players.push(PlayGame.new(smart_random_player))
44+
players.push(PlayGame.new(binary_player))
45+
46+
47+
players.each { |player|
48+
total_num_attempts = 0
49+
total_num_failures = 0
50+
1.upto(NUM_OF_RUNS) do |i|
51+
oracle.secret_number = i
52+
player.reset
53+
if player.play==:success
54+
total_num_attempts += player.num_attempts
55+
else
56+
total_num_failures += 1
57+
end
58+
end
59+
player.delete_observer(player)
60+
61+
puts "Player with strategy #{player.player_name} took on average #{total_num_attempts/(NUM_OF_RUNS-total_num_failures)} attempts to succeed"
62+
}
63+
64+
65+

ObserverPattern/observable_subject.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
module ObservableSubject
3+
4+
def initialize
5+
@observers=[]
6+
end
7+
8+
def add_observer(&observer)
9+
@observers.push(observer)
10+
end
11+
12+
def delete_observer(observer)
13+
puts("#{observer.player_name} has been deleted!")
14+
@observers.delete(observer)
15+
end
16+
17+
def notify_observers
18+
@observers.each do |observer|
19+
observer.call(self)
20+
end
21+
end
22+
23+
end

ObserverPattern/oracle.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
# Knows the number the participants are trying to guess
3+
class Oracle
4+
attr_writer :secret_number
5+
6+
def initialize(secret_num:0)
7+
@secret_number = secret_num
8+
end
9+
10+
def is_this_the_number? num
11+
if num == @secret_number
12+
:correct
13+
elsif num > @secret_number
14+
:less_than
15+
elsif num < @secret_number
16+
:greater_than
17+
end
18+
end
19+
20+
end

ObserverPattern/participant.rb

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
2+
require_relative 'oracle.rb'
3+
require_relative 'observable_subject.rb'
4+
5+
# Tries to guess the 'secret' number using several different strategies
6+
class Participant
7+
attr_accessor :num_attempts, :oracle
8+
attr_reader :lower, :upper
9+
10+
include ObservableSubject
11+
12+
def initialize(lower, upper, oracle, max_num_attempts:10)
13+
super()
14+
@oracle, @max_num_attempts, @lower, @upper = oracle, max_num_attempts, lower, upper
15+
@num_attempts = 0
16+
end
17+
18+
#Template method
19+
def play
20+
num = init_limits(@lower, @upper)
21+
@num_attempts+=1
22+
do_play(@lower, num, @upper)
23+
compare
24+
end
25+
26+
def init_limits(lower, upper)
27+
raise "Abstract method called"
28+
end
29+
30+
def do_play(lower, num, upper)
31+
raise "Abstract method called"
32+
end
33+
34+
def compare
35+
if (@num_attempts <= @max_num_attempts)
36+
:success
37+
else
38+
fail
39+
end
40+
end
41+
42+
43+
def reset
44+
@num_attempts = 0
45+
end
46+
47+
def player_name
48+
self.class.name
49+
end
50+
51+
private
52+
def fail
53+
:fail
54+
end
55+
56+
end

ObserverPattern/participant_spec.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
require 'rspec'
2+
require_relative 'participant'
3+
require_relative 'oracle'
4+
5+
rand_values = [10, 7, 4, 9, 6, 5, 2, 8, 1, 3, 0] # for rand
6+
7+
describe 'participant behaviour' do
8+
9+
before do
10+
@oracle = Oracle.new(secret_num:4)
11+
@participant = Participant.new(@oracle, max_num_attempts:5)
12+
allow(Kernel).to receive(:rand).and_return(*rand_values) # mocking Kernel.rand
13+
end
14+
15+
it 'guesses the number 4 in 3 attempts using play_randomly' do
16+
expect(@participant.play(0, 10)).to eq(:success)
17+
expect(@participant.num_attempts).to eq(3)
18+
end
19+
20+
it 'guesses the number 4 in 5 attempts using play_linear' do
21+
expect(@participant.play(0, 0)).to eq(:success)
22+
expect(@participant.num_attempts).to eq(5)
23+
end
24+
25+
it 'guesses the number 4 in 3 attempts using play_smart_random' do
26+
expect(@participant.play(0, 10)).to eq(:success)
27+
expect(@participant.num_attempts).to eq(3)
28+
end
29+
30+
it 'guesses the number 4 in 4 attempts using play_binary_search' do
31+
expect(@participant.play(0, 10)).to eq(:success)
32+
expect(@participant.num_attempts).to eq(4)
33+
end
34+
35+
end

ObserverPattern/play_game.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
require_relative 'observable_subject.rb'
2+
3+
class PlayGame
4+
5+
include ObservableSubject
6+
7+
def initialize(player)
8+
super()
9+
@player = player
10+
end
11+
12+
def play
13+
@player.play
14+
end
15+
16+
def reset
17+
@player.reset
18+
end
19+
20+
def num_attempts
21+
@player.num_attempts
22+
end
23+
24+
def player_name
25+
@player.player_name
26+
end
27+
end

ObserverPattern/random_.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
require_relative 'observable_subject.rb'
3+
4+
class Random_ < Participant
5+
6+
7+
def init_limits(lower, upper)
8+
num = Kernel.rand(lower..upper)
9+
end
10+
11+
def do_play(lower, num, upper)
12+
while @oracle.is_this_the_number?(num)!=:correct && (@num_attempts <= @max_num_attempts) do
13+
num = init_limits(lower, upper)
14+
@num_attempts+=1
15+
end
16+
notify_observers
17+
end
18+
19+
def player_name
20+
self.class.name
21+
end
22+
23+
def player_name
24+
self.class.name
25+
end
26+
end

ObserverPattern/smart_random.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
2+
class SmartRandom < Participant
3+
4+
def init_limits(lower, upper)
5+
num = Kernel.rand(lower..upper)
6+
end
7+
8+
def do_play(lower, num, upper)
9+
while ((result = @oracle.is_this_the_number?(num)) != :correct) && (@num_attempts <= @max_num_attempts) do
10+
if result == :less_than
11+
upper = num-1
12+
elsif result == :greater_than
13+
lower = num+1
14+
end
15+
num = init_limits(lower, upper)
16+
@num_attempts+=1
17+
end
18+
notify_observers
19+
end
20+
21+
def player_name
22+
self.class.name
23+
end
24+
end

0 commit comments

Comments
 (0)