Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Audacious Array (RubyConf 2021)

The Audacious Array (RubyConf 2021)

What could be simpler than the array? It's just a list of indexed values, right?

Well, not so fast. Ruby reimagines what an array can be, turning it into a randomizer, a 2D map, a stack, a queue, and a mathematical set. It also provides built-in utilities for unparalleled analysis and search of its contents.

Understanding arrays deeply is a powerful step forward in writing concise, beautiful, semantic Ruby.

Ariel Caplan

November 10, 2021
Tweet

More Decks by Ariel Caplan

Other Decks in Technology

Transcript

  1. []

  2. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • • Ruby

    programmer since 2014 • Backend Developer at • Find me online: @amcaplan • https://amcaplan.ninja Hi! I’m Ariel Caplan.
  3. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • • Ordered

    collection of values • Values can be any Ruby object • Get/set by index (zero-based) • Literal syntax: • Explicit syntax: • Setting by index: • Strict fetching: • Standard retrieval: • Descriptive Information: What is an Array? [1, 2, 3] Array.new(3, :a) #=> [:a, :a, :a] array[2] #=> "val2" array[3] #=> nil array[1..2] #=> ["val1", "val2"] array[1..-1] #=> ["val1", “val2”] array.first #=> "val0" array.last #=> “val2" array.fetch(3) # IndexError (index 3 outside of array bounds: -3...3) array.size #=> 4 array.empty? #=> false array[2] = "val2"
  4. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Front and

    Back array = [1, 2, 3, 4, 5] # adding items array.push(6) #=> [1, 2, 3, 4, 5, 6] array << 7 #=> [1, 2, 3, 4, 5, 6, 7] array.unshift(0) #=> [0, 1, 2, 3, 4, 5, 6, 7] # removing items array.pop #=> 7 array #=> [0, 1, 2, 3, 4, 5, 6] array.shift #=> 0 array #=> [1, 2, 3, 4, 5, 6]
  5. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Stack: #push

    and #pop class Stack def initialize @stack = [] end def push(item) @stack.push(item) end def pop @stack.pop end end
  6. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Stack: #push

    and #pop class Stack def initialize @stack = [] end def push(item) @stack.push(item) end def pop @stack.pop end end s = Stack.new
  7. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Stack: #push

    and #pop class Stack def initialize @stack = [] end def push(item) @stack.push(item) end def pop @stack.pop end end s = Stack.new s.push(:a) :a
  8. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Stack: #push

    and #pop class Stack def initialize @stack = [] end def push(item) @stack.push(item) end def pop @stack.pop end end s = Stack.new s.push(:a) s.push(:b) :a :b
  9. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Stack: #push

    and #pop class Stack def initialize @stack = [] end def push(item) @stack.push(item) end def pop @stack.pop end end s = Stack.new s.push(:a) s.push(:b) s.push(:c) :a :b :c
  10. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Stack: #push

    and #pop class Stack def initialize @stack = [] end def push(item) @stack.push(item) end def pop @stack.pop end end s = Stack.new s.push(:a) s.push(:b) s.push(:c) s.pop #=> :c :a :b
  11. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Stack: #push

    and #pop class Stack def initialize @stack = [] end def push(item) @stack.push(item) end def pop @stack.pop end end s = Stack.new s.push(:a) s.push(:b) s.push(:c) s.pop #=> :c s.pop #=> :b :a
  12. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Stack: #push

    and #pop class Stack def initialize @stack = [] end def push(item) @stack.push(item) end def pop @stack.pop end end s = Stack.new s.push(:a) s.push(:b) s.push(:c) s.pop #=> :c s.pop #=> :b s.pop #=> :a
  13. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: #push

    and #shift class Queue def initialize @queue = [] end def push(item) @queue.push(item) end def pop @queue.shift end end
  14. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: #push

    and #shift class Queue def initialize @queue = [] end def push(item) @queue.push(item) end def pop @queue.shift end end q = Queue.new
  15. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: #push

    and #shift class Queue def initialize @queue = [] end def push(item) @queue.push(item) end def pop @queue.shift end end q = Queue.new q.push(:a) :a
  16. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: #push

    and #shift class Queue def initialize @queue = [] end def push(item) @queue.push(item) end def pop @queue.shift end end q = Queue.new q.push(:a) q.push(:b) :a :b
  17. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: #push

    and #shift class Queue def initialize @queue = [] end def push(item) @queue.push(item) end def pop @queue.shift end end q = Queue.new q.push(:a) q.push(:b) q.push(:c) :a :b :c
  18. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: #push

    and #shift class Queue def initialize @queue = [] end def push(item) @queue.push(item) end def pop @queue.shift end end q = Queue.new q.push(:a) q.push(:b) q.push(:c) q.pop #=> :a :b :c
  19. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: #push

    and #shift class Queue def initialize @queue = [] end def push(item) @queue.push(item) end def pop @queue.shift end end q = Queue.new q.push(:a) q.push(:b) q.push(:c) q.pop #=> :a q.pop #=> :b :c
  20. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: #push

    and #shift class Queue def initialize @queue = [] end def push(item) @queue.push(item) end def pop @queue.shift end end q = Queue.new q.push(:a) q.push(:b) q.push(:c) q.pop #=> :a q.pop #=> :b q.pop #=> :c
  21. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Queue: why

    not #unshift? A B C D F SPACE!!! NO SPACE !
  22. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • A Surprising

    Benchmark require 'benchmark/ips' Benchmark.ips do |x| x.report('Array#unshift') do array = (1..100).to_a 100_000.times { |i| array.unshift(i) } end x.report('Array#push') do array = (1..100).to_a 100_000.times { |i| array.push(i) } end x.compare! end
  23. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • A Surprising

    Benchmark Warming up -------------------------------------- Array#unshift 17.000 i/100ms Array#push 19.000 i/100ms Calculating ------------------------------------- Array#unshift 181.828 (± 6.6%) i/s - 918.000 in 5.076970s Array#push 187.124 (± 8.0%) i/s - 931.000 in 5.011387s Comparison: Array#push: 187.1 i/s Array#unshift: 181.8 i/s - same-ish: difference falls within error " ❓
  24. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • A Moment

    of Gratitude Ufuk Kayserilioglu Peter Zhu Kevin Newton
  25. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Creating randomness

    array = [1, 2, 3, 4, 5] array.shuffle #=> [5, 1, 4, 3, 2] array.shuffle #=> [1, 3, 5, 4, 2] array.shuffle #=> [5, 3, 2, 4, 1] array.sample #=> 4 array.sample(3) => [5, 2, 1]
  26. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Cleaning up

    array = [2, 5, 6, 7, 10, 3, 1, 4, 8, 9] array.sort #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] array.sort_by { |i| -i } #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
  27. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Mixing it

    up array = [1, 2, 3] array.combination(2).to_a #=> [[1, 2], [1, 3], [2, 3]] array.permutation(2).to_a #=> [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]
  28. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Mixing it

    up array = [1, 2, 3] array.combination(2).to_a #=> [[1, 2], [1, 3], [2, 3]] array.permutation(2).to_a #=> [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]
  29. ITEMS = ["chair", "sofa", "bed", "pillow", "cushion", "blanket"] def related_items

    ITEMS.sample(3) end RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Displaying random items ITEM_GROUPS = ITEMS.permutation(3).cycle def related_items_group ITEM_GROUPS.next end
  30. Array includes Enumerable! Iteration #each #each_cons #each_slice Introspection #all? #any?

    #none? #one? Selection #filter/#select #find/#detect #reject Extrapolation #map/#collect #reduce/#inject #each_with_object
  31. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Iteration [1,

    2, 3].each do |int| puts int end # This will print: # 1 # 2 # 3 [1, 2, 3, 4, 5, 6].each_slice(3).to_a => [[1, 2, 3], [4, 5, 6]]
  32. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Selection [1,

    2, 3, 4, 5].select { |i| i >= 4 } #=> [4, 5] [1, 2, 3, 4, 5].find { |i| i >= 4 } #=> 4
  33. [1, 2, 3].map { |i| i * 2 } #=>

    [2, 4, 6] ["a", "b", "c"].inject("start") { |accum, str| accum + ' ' + str } #=> "start a b c" RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Extrapolation "start" => "start a" => "start a b" => "start a b c"
  34. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Minimum and

    Maximum array = [2, 5, 6, 7, 10, 3, 1, 4, 8, 9] array.min #=> 1 array.max #=> 10 array.minmax #=> [1, 10]
  35. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Minimum and

    Maximum words = ["the", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog"] words.minmax #=> ["brown", "the"]
  36. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Adding it

    All Up array = [2, 5, 6, 7, 10, 3, 1, 4, 8, 9] array.sum #=> 55 array.sum { |i| i ** 2 } #=> 385
  37. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Shopping Cart

    catnip = { name: "catnip", price: 6.99 } milk = { name: "milk", price: 2.49 } hat = { name: "Cat in the Hat hat", price: 15.99 } shopping_cart = [[catnip, 2], [milk, 3], [hat, 1]]
  38. most_common_item = shopping_cart. max_by { |product, quantity| quantity }. first[:name]

    #=> "milk" RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Shopping Cart catnip = { name: "catnip", price: 6.99 } milk = { name: "milk", price: 2.49 } hat = { name: "Cat in the Hat hat", price: 15.99 } shopping_cart = [[catnip, 2], [milk, 3], [hat, 1]] most_expensive_item = shopping_cart. max_by { |product, quantity| product[:price] }. first[:name] #=> "Cat in the Hat hat"
  39. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Shopping Cart

    catnip = { name: "catnip", price: 6.99 } milk = { name: "milk", price: 2.49 } hat = { name: "Cat in the Hat hat", price: 15.99 } shopping_cart = [[catnip, 2], [milk, 3], [hat, 1]] order_total = shopping_cart. sum { |product, quantity| product[:price] * quantity } #=> 37.44
  40. array_2d = [ [1, 2, 3], [4, 5, 6], [7,

    8, 9], ] RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Arrays as Maps
  41. array_2d.reverse #=> [ # [7, 8, 9], # [4, 5,

    6], # [1, 2, 3] # ] array_2d = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ] RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Arrays as Maps array_2d.map(&:reverse) #=> [ # [3, 2, 1], # [6, 5, 4], # [9, 8, 7] # ]
  42. array_2d.transpose #=> [ # [1, 4, 7], # [2, 5,

    8], # [3, 6, 9] # ] RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Arrays as Maps array_2d = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]
  43. array_2d.transpose #=> [ # [1, 4, 7], # [2, 5,

    8], # [3, 6, 9] # ] RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Arrays as Maps array_2d = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ] array_2d.transpose.reverse #=> [ # [3, 6, 9], # [2, 5, 8], # [1, 4, 7] # ] array_2d.transpose.map(&:reverse) #=> [ # [7, 4, 1], # [8, 5, 2], # [9, 6, 3] # ]
  44. array_2d.rotate #=> [ # [4, 5, 6], # [7, 8,

    9], # [1, 2, 3] # ] array_2d = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ] RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Arrays as Maps
  45. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Arrays as

    Maps class PuzzlePiece def initialize(array) @array = array end def rotated(i) piece = @array i.times do piece = piece.transpose.reverse end piece end def orientations (0..3).map { |i| rotated(i) } end end
  46. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Autocomplete CAT_BREEDS

    = CatBreed.pluck(:name) user_input = Regexp.escape(params[:breed]) #=> "pe" CAT_BREEDS.grep(Regexp.new(user_input, 'i')) #=> ["European Shorthair", "LaPerm", "Persian", "Peterbald", "Serrade Petit"] CAT_BREEDS.grep(Regexp.new('\b' + user_input, 'i')) #=> ["Persian", "Peterbald", "Serrade Petit"] CAT_BREEDS.grep(Regexp.new('\A' + user_input, 'i')) #=> ["Persian", "Peterbald"]
  47. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Filtering by

    Regexp CAT_BREEDS.grep(/ /) #=> ["American Bobtail", "American Curl", ... "Ukrainian Levkoy", "York Chocolate"] CAT_BREEDS.grep_v(/ /) #=> ["Abyssinian", "Aegean", ... "Thai", "Tonkinese", "Toyger"]
  48. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Finding the

    First array = [
 #<Order date="2020-07-17", items=[...], cost=449>,
 #<Order date="2020-09-21", items=[...], cost=250>,
 #<Order date="2021-01-11", items=[...], cost=140>,
 #<Order date="2021-02-29", items=[...], cost=387>,
 #<Order date="2021-03-04", items=[...], cost=88>,
 #<Order date="2021-06-30", items=[...], cost=154>,
 #<Order date="2021-09-06", items=[...], cost=249>,
 #<Order date="2021-10-05", items=[...], cost=321>
 ]
 array.find { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140>

  49. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Finding the

    First array = [
 #<Order date="2020-07-17", items=[...], cost=449>,
 #<Order date="2020-09-21", items=[...], cost=250>,
 #<Order date="2021-01-11", items=[...], cost=140>,
 #<Order date="2021-02-29", items=[...], cost=387>,
 #<Order date="2021-03-04", items=[...], cost=88>,
 #<Order date="2021-06-30", items=[...], cost=154>,
 #<Order date="2021-09-06", items=[...], cost=249>,
 #<Order date="2021-10-05", items=[...], cost=321>
 ]
 array.find { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140>

  50. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Finding the

    First array = [
 #<Order date="2020-07-17", items=[...], cost=449>,
 #<Order date="2020-09-21", items=[...], cost=250>,
 #<Order date="2021-01-11", items=[...], cost=140>,
 #<Order date="2021-02-29", items=[...], cost=387>,
 #<Order date="2021-03-04", items=[...], cost=88>,
 #<Order date="2021-06-30", items=[...], cost=154>,
 #<Order date="2021-09-06", items=[...], cost=249>,
 #<Order date="2021-10-05", items=[...], cost=321>
 ]
 array.find { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140>

  51. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Finding the

    First array = [
 #<Order date="2020-07-17", items=[...], cost=449>,
 #<Order date="2020-09-21", items=[...], cost=250>,
 #<Order date="2021-01-11", items=[...], cost=140>,
 #<Order date="2021-02-29", items=[...], cost=387>,
 #<Order date="2021-03-04", items=[...], cost=88>,
 #<Order date="2021-06-30", items=[...], cost=154>,
 #<Order date="2021-09-06", items=[...], cost=249>,
 #<Order date="2021-10-05", items=[...], cost=321>
 ]
 array.find { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140>

  52. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Finding the

    First array = [
 #<Order date="2020-07-17", items=[...], cost=449>,
 #<Order date="2020-09-21", items=[...], cost=250>,
 #<Order date="2021-01-11", items=[...], cost=140>,
 #<Order date="2021-02-29", items=[...], cost=387>,
 #<Order date="2021-03-04", items=[...], cost=88>,
 #<Order date="2021-06-30", items=[...], cost=154>,
 #<Order date="2021-09-06", items=[...], cost=249>,
 #<Order date="2021-10-05", items=[...], cost=321>
 ]
 array.find { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140>
 array.bsearch { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140>
  53. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Finding the

    First array = [
 #<Order date="2020-07-17", items=[...], cost=449>,
 #<Order date="2020-09-21", items=[...], cost=250>,
 #<Order date="2021-01-11", items=[...], cost=140>,
 #<Order date="2021-02-29", items=[...], cost=387>,
 #<Order date="2021-03-04", items=[...], cost=88>,
 #<Order date="2021-06-30", items=[...], cost=154>,
 #<Order date="2021-09-06", items=[...], cost=249>,
 #<Order date="2021-10-05", items=[...], cost=321>
 ]
 array.find { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140>
 array.bsearch { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140> true
  54. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Finding the

    First array = [
 #<Order date="2020-07-17", items=[...], cost=449>,
 #<Order date="2020-09-21", items=[...], cost=250>,
 #<Order date="2021-01-11", items=[...], cost=140>,
 #<Order date="2021-02-29", items=[...], cost=387>,
 #<Order date="2021-03-04", items=[...], cost=88>,
 #<Order date="2021-06-30", items=[...], cost=154>,
 #<Order date="2021-09-06", items=[...], cost=249>,
 #<Order date="2021-10-05", items=[...], cost=321>
 ]
 array.find { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140>
 array.bsearch { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140> true false
  55. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Finding the

    First array = [
 #<Order date="2020-07-17", items=[...], cost=449>,
 #<Order date="2020-09-21", items=[...], cost=250>,
 #<Order date="2021-01-11", items=[...], cost=140>,
 #<Order date="2021-02-29", items=[...], cost=387>,
 #<Order date="2021-03-04", items=[...], cost=88>,
 #<Order date="2021-06-30", items=[...], cost=154>,
 #<Order date="2021-09-06", items=[...], cost=249>,
 #<Order date="2021-10-05", items=[...], cost=321>
 ]
 array.find { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140>
 array.bsearch { |order| order.date >= "2021-01-01" }
 #=> #<Order date="2021-01-11", items=[...], cost=140> true false true
  56. array = [
 #<Order date="2020-07-17", items=[...], cost=449>,
 #<Order date="2020-09-21", items=[...],

    cost=250>,
 #<Order date="2021-01-11", items=[...], cost=140>, #<Order date="2021-02-29", items=[...], cost=387>,
 #<Order date="2021-03-04", items=[...], cost=88>,
 #<Order date="2021-06-30", items=[...], cost=154>,
 #<Order date="2021-09-06", items=[...], cost=249>,
 #<Order date="2021-10-05", items=[...], cost=321>
 ]
 index = array.bsearch_index { |order| order.date >= "2021-01-01" } #=> 3 array[index..-1] #=> [#<Order date="2021-01-11", items=[...], cost=140>,…] RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Finding the First }
  57. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Arrays as

    Sets array = [1, 1, 2, 2, 3, 3, 3] array.uniq #=> [1, 2, 3] array - [2, 3] #=> [1, 1]
  58. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Arrays as

    Sets set1 = [1, 2, 3] set2 = [2, 3, 4, 5] set1 | set2 #=> [1, 2, 3, 4, 5] set1 & set2 #=> [2, 3]
  59. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Arrays as

    Sets author.posts.replace(new_posts_array) # under the hood, performs a diff # let current_posts = author's current posts reload(current_posts & new_posts_array) delete(current_posts - new_posts_array) insert(new_posts_array - current_posts)
  60. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • •Arrays are

    indexed collections of elements •Randomize and sort •Iterate/Interpret one-by-one or together •2D arrays can be used as maps •Rudimentary search capabilities •Set-like functionality What have we covered?
  61. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Random Map

    map_items = [:%] * 200 + [:&] * 4 + [:'] * 4 + [:(] * 2 + [')', '*', '+', ','] SIDE_SIZE = 25 map = SIDE_SIZE.times. map { map_items.sample(SIDE_SIZE) } map_items = [:%] * 200 + [:&] * 4 + [:'] * 4 + [:(] * 2 + [')', '*', '+', ',']
  62. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Random Map

    [ [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :' , :% , :% , :% , :& , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :& , :( , :% , :% , :% , :% , :% , :% , :, , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :& , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :+ , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :' , :% , :% , :) , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :, , :% , :* , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :' , :% , :% , :( , :* , :% , :) ], [:% , :% , :% , :% , :% , :% , :' , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :' , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :* , :% , :% , :% , :% , :% , :% , :( , :% , :% , :% , :% , :% , :% , :% , :& , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :& , :% , :) , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :, , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :& , :% , :% , :% , :% , :% , :% , :% , :& ], [:% , :, , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:+ , :% , :% , :% , :% , :& , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :( , :' , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :+ , :( , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :' , :% , :% , :% , :% , :% , :% , :' , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :' , :% , :' , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :' , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :' , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :( , :% , :% , :% , :% , :% , :% , :% , :% , :% ], [:% , :' , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :' , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :( , :% , :% , :% , :% , :% , :% , :% , :% , :' , :% , :% , :% , :% , :% , :% ], [:% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :% , :( , :% , :% , :% ] ]
  63. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Map Shuffling

    , state[:map] = state[:map]. flatten. shuffle. each_slice(SIDE_SIZE). to_a
  64. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Map Shuffling

    , map = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] map.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9] .shuffle #=> [4, 9, 7, 6, 8, 1, 5, 3, 2] .each_slice(3).to_a #=> [ # [4, 9, 7], # [6, 8, 1], # [5, 3, 2] # ]
  65. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Map Movement

    case current_symbol when :& state[:map] = state[:map].transpose.map(&:reverse) else state[:map].each { |line| line.rotate!(-1) } end
  66. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Controls #

    move up = move the map down state[:map].rotate!(-1) # move down = move the map up state[:map].rotate!(1)
  67. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items # Poor performance as array grows def active_items(temp_items) temp_items.select(&:active?) end
  68. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1] end
  69. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1] end ) * * + ) * * + , ) ,
  70. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1] end ) * * + ) * * + , ) ,
  71. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1] end ) * * + ) * * + , ) , -
  72. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1] end ) * * + ) * * + , ) , -
  73. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1] end ) * * + ) * * + , ) , - .
  74. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1] end ) * * + ) * * + , ) , - .
  75. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1] end ) * * + ) * * + , ) , - . .
  76. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1] end ) * * + ) * * + , ) , - . .
  77. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end
  78. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end * + * + , ) ,
  79. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end * + * + , ) ,
  80. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end * + * + , ) , .
  81. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end * + * + , ) , .
  82. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end * + * + , ) , - .
  83. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end * + * + , ) , - .
  84. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end * + * + , ) , - . .
  85. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end * + * + , ) , - . .
  86. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items) current_temp_item_index = temp_items.bsearch_index(&:active?) temp_items[current_temp_item_index..-1].select(&:active?) end * + * + , ) , - . .
  87. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Tracking Active

    Items def active_items(temp_items:, **) earliest_active_start_time = Time.now - Item::MAX_DURATION current_temp_item_index = temp_items.bsearch_index { |i| i.start_time > earliest_active_start_time } temp_items[current_temp_item_index..-1].select(&:active?) end
  88. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • •Multiplicative items

    implemented with #inject •Cheat codes use a queue-based keylogger •Final score uses #tally CatWalk Miscellany
  89. RUBYCONF 2021 • ARIEL CAPLAN • @AMCAPLAN • Appreciation Circle

    array = %w(Alex Ariel Daniel Erez Ira Omer Oren) array.shuffle.cycle.each_cons(2).first(array.size).to_h #=> { # "Erez"=>"Omer", # "Omer"=>"Ira", # "Ira"=>"Alex", # "Alex"=>"Oren", # "Oren"=>"Ariel", # "Ariel"=>"Daniel", # "Daniel"=>"Erez" # }