aboutsummaryrefslogtreecommitdiff
path: root/03-switch3.rb
blob: f8809d7db264026bfef8a6d863ba4932400585db (plain)
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
require './level'
require './frame2'

$levels << Level.new do
  @interfaces = %w(1 2 3)
  @description = <<~EOD
    You are now a three-port switch.
    When a frame comes in on a port, you should keep track of the source address,
      and any frames destined for that address in future clicks should only be
      forwarded to that port. All other frames should be broadcast as before.
  EOD
  @clicks = 8

  @fib = @interfaces.product([nil]).to_h
  @next_fib = @fib.dup

  def target(frame)
    ifib = @fib.invert
    if ifib.keys.include?(frame.dst_addr)
      [frame.to(ifib[frame.dst_addr])]
    else
      case frame.iface
      when ?1
        [frame.to(?2), frame.to(?3)]
      when ?2
        [frame.to(?1), frame.to(?3)]
      when ?3
        [frame.to(?1), frame.to(?2)]
      else
        []
      end
    end
  end

  def generate
    iface = interfaces.sample

    if rand < 0.4 || @fib[iface].nil?
      src = Frame2.gen_addr
      @next_fib[iface] = src
    else
      src = @fib[iface]
    end

    dst = nil
    dst = (@fib.values.compact - [src]).sample if rand < 0.5
    dst = Frame2.gen_addr if dst.nil?

    frame = Frame2.new(iface, src, dst)
    @count += 1
    frame
  end

  def click
    @fib = @next_fib
    @next_fib = @fib.dup
  end
end