Module: StackingOrder

Defined in:
lib/stacking_order.rb,
lib/stacking_order/version.rb

Overview

Calculates how to print entries in a grid so that stack-cut pages reassemble into sequential order.

Constant Summary collapse

VERSION =
'1.1.0'

Class Method Summary collapse

Class Method Details

.apply_two_sided_flip(result, rows, columns) ⇒ Object



80
81
82
83
84
85
86
# File 'lib/stacking_order.rb', line 80

def apply_two_sided_flip(result, rows, columns)
  cells_per_page = rows * columns
  result.each_slice(cells_per_page).with_index.flat_map do |page, page_index|
    padded_page = pad_page(page, cells_per_page)
    page_index.odd? ? flip_page_rows(padded_page, rows, columns) : padded_page
  end
end

.flip_page_rows(page, rows, columns) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/stacking_order.rb', line 94

def flip_page_rows(page, rows, columns)
  if rows == 1
    row_slice = page.slice(0, columns) || []
    return row_slice.reverse
  end

  flipped = []
  rows.times do |row_index|
    source_row_index = rows - 1 - row_index
    row_slice = page.slice(source_row_index * columns, columns) || []
    flipped.concat(row_slice)
  end
  flipped
end

.order(entries:, rows:, columns:, two_sided_flipped: false) ⇒ Array<Integer, nil>

Public API for calculating the stacking order for printing entries on pages with a grid layout. See README for details.

Parameters:

  • entries (Integer)

    Total number of entries to print

  • rows (Integer)

    Number of rows in the grid on each page

  • columns (Integer)

    Number of columns in the grid on each page

Returns:

  • (Array<Integer, nil>)

    The order in which to print entries (with nil for empty cells)



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/stacking_order.rb', line 17

def order(entries:, rows:, columns:, two_sided_flipped: false)
  validate_arguments!(entries, rows, columns)

  return [] if entries.zero?

  cells_per_page = rows * columns
  num_pages = (entries.to_f / cells_per_page).ceil

  result = []

  num_pages.times do |page_index|
    cells_per_page.times do |cell_index|
      entry_number = (cell_index * num_pages) + page_index + 1
      result << (entry_number <= entries ? entry_number : nil)
    end
  end

  if two_sided_flipped
    result = apply_two_sided_flip(result, rows, columns)
  end

  result.pop while result.last.nil?
  result
end

.pad_page(page, cells_per_page) ⇒ Object



88
89
90
91
92
# File 'lib/stacking_order.rb', line 88

def pad_page(page, cells_per_page)
  return page if page.length == cells_per_page

  page + Array.new(cells_per_page - page.length)
end

.visualize(entries:, rows:, columns:, two_sided_flipped: false, io: $stdout) ⇒ Object

Utility method that prints the layout for the provided configuration, showing the entries on each page and the resulting stacks after cutting. Useful for debugging or CLI demos.



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
# File 'lib/stacking_order.rb', line 45

def visualize(entries:, rows:, columns:, two_sided_flipped: false, io: $stdout)
  result = order(entries: entries, rows: rows, columns: columns, two_sided_flipped: two_sided_flipped)
  cells_per_page = rows * columns
  num_pages = (entries.to_f / cells_per_page).ceil

  io.puts
  io.puts('=' * 60)
  io.puts("Visualizing stacking order for #{entries} entries, #{rows} row(s), #{columns} column(s)")
  io.puts('=' * 60)
  io.puts("Result: #{result.inspect}")
  io.puts("\nPages layout:")

  result.each_slice(cells_per_page).with_index do |page, page_num|
    io.puts("\nPage #{page_num + 1}:")
    page.each_slice(columns).with_index do |row_values, row_num|
      formatted = row_values.map { |value| value ? format('%3d', value) : 'nil' }.join(' | ')
      io.puts("  Row #{row_num + 1}: #{formatted}")
    end
  end

  io.puts("\nAfter cutting and stacking:")
  cells_per_page.times do |cell_idx|
    row_idx = cell_idx / columns
    col_idx = cell_idx % columns
    stack = []

    num_pages.times do |page_idx|
      pos = (page_idx * cells_per_page) + cell_idx
      stack << (pos < result.length ? result[pos] : nil)
    end

    io.puts("  Position [#{row_idx + 1},#{col_idx + 1}] stack (bottom→top): #{stack.compact.join(', ')}")
  end
end