Class: Xudoku::Cli::Screens::Puzzle

Inherits:
Base
  • Object
show all
Defined in:
lib/xudoku/cli/screens/puzzle.rb

Overview

:nodoc:

Constant Summary collapse

CELL_WIDTH =
7
CELL_HEIGHT =
3
BOX_GAP =
1
BOX_GAP_R =
1
TITLE_HEIGHT =
3
4
[
  ["↑↓←→ / HJKL / WASD", "Move"],
  ["1–9",                "Enter digit"],
  ["⌫  Backspace",       "Erase cell"],
  ["U",                  "Undo"],
  ["Q",                  "Quit"],
  ["B",                  "Main menu"],
  ["R",                  "Restart"]
].freeze

Constants inherited from Base

Base::TITLE

Instance Attribute Summary collapse

Attributes inherited from Base

#app, #first_render, #io, #reader

Instance Method Summary collapse

Methods inherited from Base

#initialize, #redraw!, #render

Constructor Details

This class inherits a constructor from Xudoku::Cli::Screens::Base

Instance Attribute Details

#gameObject (readonly)

Returns the value of attribute game.



8
9
10
# File 'lib/xudoku/cli/screens/puzzle.rb', line 8

def game
  @game
end

Instance Method Details

#board_leftObject



58
59
60
# File 'lib/xudoku/cli/screens/puzzle.rb', line 58

def board_left
  [(width - board_px_width) / 2, 0].max
end

#board_px_widthObject



54
55
56
# File 'lib/xudoku/cli/screens/puzzle.rb', line 54

def board_px_width
  9 * CELL_WIDTH + 2 * BOX_GAP # 2 gaps between 3 groups of 3 cols
end

#board_topObject



62
63
64
# File 'lib/xudoku/cli/screens/puzzle.rb', line 62

def board_top
  TITLE_HEIGHT + 1
end

#cell_origin(x, y) ⇒ Object



66
67
68
69
70
71
72
73
# File 'lib/xudoku/cli/screens/puzzle.rb', line 66

def cell_origin(x, y)
  extra_col = (y / 3) * BOX_GAP # 0, 1, or 2 extra cols for box gaps
  extra_row = (x / 3) * BOX_GAP_R

  col = board_left + y * CELL_WIDTH + extra_col
  row = board_top  + x * CELL_HEIGHT + extra_row
  [col, row]
end

#cell_style(x, y) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/xudoku/cli/screens/puzzle.rb', line 75

def cell_style(x, y)
  if game.error?(x, y)
    { style: { bg: :red,          fg: :bright_white,
               border: { fg: :bright_white, bg: :red } } }
  elsif game.selected?(x, y)
    { style: { bg: :green,        fg: :bright_white,
               border: { fg: :bright_white, bg: :green } } }
  elsif game.same_row?(x, y) || game.same_col?(x, y) || game.same_grid?(x, y)
    { style: { bg: :white,        fg: :black,
               border: { fg: :bright_black, bg: :white } } }
  elsif game.clue?(x, y)
    { style: { bg: :bright_black, fg: :bright_white,
               border: { fg: :bright_black, bg: :bright_black } } }
  else
    { style: { border: { fg: :bright_black, bg: :black } } }
  end
end

#clear_boardObject



133
134
135
136
# File 'lib/xudoku/cli/screens/puzzle.rb', line 133

def clear_board
  write cursor.move_to(*cell_origin(0, 0))
  write cursor.clear_lines (CELL_HEIGHT * 10), :down
end

#handle_event(event) ⇒ Object



43
44
45
46
47
48
49
50
51
52
# File 'lib/xudoku/cli/screens/puzzle.rb', line 43

def handle_event(event)
  handle(:quit) if event.quit?
  handle(:menu) if event.menu?

  game.set(event.value) if event.digit?

  %w[up down left right delete undo restart].each do |method|
    game.send(method) if event.send("#{method}?")
  end
end

#paint_screen(event = nil) ⇒ Object



32
33
34
35
36
37
38
39
40
41
# File 'lib/xudoku/cli/screens/puzzle.rb', line 32

def paint_screen(event = nil)
  handle_event(event) unless event.nil?
  if first_render?
    render_title
    render_board
    render_menu
  else
    render_board
  end
end

#render_boardObject



138
139
140
141
142
143
144
145
146
# File 'lib/xudoku/cli/screens/puzzle.rb', line 138

def render_board
  clear_board

  game.each_cell do |x, y, value|
    render_cell(x, y, value)
  end

  render_box_separators
end

#render_box_separatorsObject



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/xudoku/cli/screens/puzzle.rb', line 107

def render_box_separators
  3.times do |group_row|
    3.times do |group_col|
      next if group_col == 2

      # Draw a one-char-wide dim bar in the gap column
      gap_col = board_left + (group_col + 1) * 3 * CELL_WIDTH + group_col * BOX_GAP
      3.times do |cell_row|
        _, row = cell_origin(group_row * 3 + cell_row, 0)
        write cursor.move_to(gap_col, row)
        CELL_HEIGHT.times do |r|
          write cursor.move_to(gap_col, row + r)
          write @pastel.dim("")
        end
      end
    end
  end

  2.times do |sep|
    row = board_top + (sep + 1) * 3 * CELL_HEIGHT + sep * BOX_GAP_R
    bar = @pastel.dim("" * board_px_width)
    write cursor.move_to(board_left, row)
    write bar
  end
end

#render_cell(x, y, num) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/xudoku/cli/screens/puzzle.rb', line 93

def render_cell(x, y, num)
  col, row = cell_origin(x, y)
  label    = num.to_s.match?(/\A[1-9]\z/) ? num.to_s : ""

  box = TTY::Box.frame(
    top: row, left: col,
    width: CELL_WIDTH, height: CELL_HEIGHT,
    align: :center,
    **cell_style(x, y)
  ) { label }

  write box
end

#render_menuObject



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/xudoku/cli/screens/puzzle.rb', line 148

def render_menu
  menu_top  = board_top + 9 * CELL_HEIGHT + 2 * BOX_GAP_R + 1
  separator = @pastel.dim("" * width)

  write cursor.move_to(0, menu_top)
  write separator

  items_str = MENU_ITEMS.map do |key, desc|
    "#{@pastel.bright_yellow(key)} #{@pastel.dim(desc)}"
  end.join(@pastel.dim(""))

  # Centre the menu line
  padding = [(width - strip_ansi(items_str).length) / 2, 0].max
  write cursor.move_to(0, menu_top + 1)
  write(" " * padding + items_str)
end

#render_solved_overlayObject



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/xudoku/cli/screens/puzzle.rb', line 165

def render_solved_overlay
  message = "Puzzle Solved!  Press Q to quit.  "
  w     = message.size + 4
  h     = 5
  left  = (width  - w) / 2
  top   = (height - h) / 2

  box = TTY::Box.frame(
    top: top, left: left,
    width: w, height: h,
    align: :center,
    padding: [1, 2],
    style: { fg: :bright_white, bg: :green,
             border: { fg: :bright_white, bg: :green } }
  ) { msg }

  write box
end

#setupObject



27
28
29
30
# File 'lib/xudoku/cli/screens/puzzle.rb', line 27

def setup
  @game = Game.new
  @pastel = Pastel.new
end

#strip_ansi(str) ⇒ Object



184
185
186
# File 'lib/xudoku/cli/screens/puzzle.rb', line 184

def strip_ansi(str)
  str.gsub(/\e\[[0-9;]*m/, "")
end