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