Object oriented solution to The Tower of Hanoi.

by Rabbit

Here’s my solution to the Tower of Hanoi. I suck at math, so I did it with objects and a story. Join the discussion over at the Ruby Forum.

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
71
72
73
74
75
76
77
78
79
80
81
82
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
class Peg
 
  attr_accessor :discs
 
  def initialize(number_of_discs = 0, target = false)
    @discs, @target = Array.new, target
    number_of_discs.times { |x| @discs << Disc.new(x) }
    @discs.reverse!
  end
 
  def take_disc
    @discs.pop
  end
 
  def acceptable_disc?(disc)
    return true if @discs.empty?
    return true if disc.size < @discs.last.size
    false
  end
 
  def accept_disc(disc)
    @discs << disc
  end
 
  def target?
    @target
  end
 
  def full?
    @discs.size.eql?(4)
  end
 
  def last_disc
    @discs.pop
  end
 
  def empty?
    @discs.empty?
  end
 
end
 
class Disc
 
  def initialize(size)
    @size = size
  end
 
  def size
    @size
  end
 
end
 
class Hand
 
  def initialize
    @disc = nil
  end
 
  def disc
    @disc
  end
 
  def get_disc(peg)
    @disc = peg.last_disc
  end
 
  def place_disc_on_peg(peg)
        peg.accept_disc(@disc)
    @disc = nil
  end
 
  def empty?
    @disc.nil?
  end
 
end
 
class Tower
 
  def initialize
    @pegs = [ Peg.new(4), Peg.new, Peg.new(0, true) ]
    @hand = Hand.new
  end
 
  def play
    until solved?
      @pegs.each do |peg|
        if @hand.empty?
          @hand.get_disc(peg) unless peg.empty?
          next
        end
 
        @hand.place_disc_on_peg(peg) if peg.acceptable_disc?(@hand.disc)
      end
    end
  end
 
  def solved?
    target_peg.full?
  end
 
  def target_peg
    @pegs.find { |peg| peg.target? }
  end
 
end