good_luck_wizard 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4542c554b53395dec06ab3026510aa4ad8b24511077f0820e607daa8a48eeb57
4
- data.tar.gz: 6991409bd222f25a008b86716cda64f1cb06928637882ade5676e5114a126c5c
3
+ metadata.gz: 4263837619f78bee5caa53a56bfdb94459f936a9ac28d0b9295f5f495c9f8363
4
+ data.tar.gz: 99d4841207fd0ce336f71936fbba360256503eed43f580188dbd834b667898a0
5
5
  SHA512:
6
- metadata.gz: acd95d8a41e16661a57ec519052d91ff93747478ba29d8b4882e1e1c7207297427df4af973f55bed324af70758aca83a078cc81f27e16939c27d334ff8212e2f
7
- data.tar.gz: 5f56f58dc3a2074ab355f2694ae40356f10d5623b1f8186790c75cfbba5dd78e075017bd55d77b37bb324e027b67d624d703041d9904aee952ea6442cb4da0b1
6
+ metadata.gz: 8f6cf8b4eee23afe0934301b4e312a0afed3d6654c49fe59a6f1b7ee4b5b243041598f26b9fa19135145e6ac25ada4dc0292c179a0b745439cc0bb9b230c85e2
7
+ data.tar.gz: 577db893cc18d765420e3104a3839e1defcf71e4e7c4e2b140afe1d4e9b516203a55a755edad479b7588557f94897d231205da7be3aebaddf7fc691793ec2138
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in good_luck_wizard.gemspec
6
6
  gemspec
@@ -10,3 +10,4 @@ gem "rspec", "~> 3.4"
10
10
  gem "standard", "~> 1.45"
11
11
 
12
12
  gem "debug"
13
+ gem "benchmark-ips"
@@ -0,0 +1,21 @@
1
+ module GLW
2
+ module Components
3
+ Input = Data.define(:events) do
4
+ def self.make
5
+ new(events: [])
6
+ end
7
+
8
+ def push(event)
9
+ events << event
10
+ end
11
+
12
+ def pop
13
+ events.pop
14
+ end
15
+
16
+ def peek
17
+ events.last
18
+ end
19
+ end
20
+ end
21
+ end
data/lib/glw/input.rb CHANGED
@@ -1,96 +1,102 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GLW
4
- module Input
5
- class << self
6
- ESCAPE_TIMEOUT = 0.02 # 20ms
7
-
8
- BYTES = {
9
- "\t" => :k_tab,
10
- "\r" => :k_enter,
11
- "\n" => :k_enter,
12
- "\x7F" => :k_backspace,
13
- "\b" => :k_backspace,
14
- " " => :k_space,
15
- "\x03" => :k_ctrl_c,
16
- "[" => :k_left_bracket,
17
- "]" => :k_right_bracket,
18
- ";" => :k_semicolon,
19
- "'" => :k_single_quote,
20
- "," => :k_comma,
21
- "." => :k_period
22
- }.tap do |h|
23
- ("a".."z").each { |c| h[c] = :"k_#{c}" }
24
- ("A".."Z").each { |c| h[c] = :"k_#{c}" }
25
- ("0".."9").each { |c| h[c] = :"k_#{c}" }
26
- end
4
+ class Input
5
+ ESCAPE_TIMEOUT = 0.02 # 20ms
27
6
 
28
- def pop
29
- @queue.pop
30
- end
7
+ BYTES = {
8
+ "\t" => :k_tab,
9
+ "\r" => :k_enter,
10
+ "\n" => :k_enter,
11
+ "\x7F" => :k_backspace,
12
+ "\b" => :k_backspace,
13
+ " " => :k_space,
14
+ "\x03" => :k_ctrl_c,
15
+ "[" => :k_left_bracket,
16
+ "]" => :k_right_bracket,
17
+ ";" => :k_semicolon,
18
+ "'" => :k_single_quote,
19
+ "," => :k_comma,
20
+ "." => :k_period
21
+ }.tap do |h|
22
+ ("a".."z").each { |c| h[c] = :"k_#{c}" }
23
+ ("A".."Z").each { |c| h[c] = :"k_#{c}" }
24
+ ("0".."9").each { |c| h[c] = :"k_#{c}" }
25
+ end
26
+
27
+ def initialize
28
+ @queue = nil
29
+ end
31
30
 
32
- def start!
33
- return if @queue
31
+ def pop
32
+ @queue.pop
33
+ end
34
+
35
+ def empty?
36
+ @queue.empty?
37
+ end
34
38
 
35
- @queue = Thread::Queue.new
39
+ def start!
40
+ return if @queue
36
41
 
37
- Thread.new do
38
- loop do
39
- byte = read_byte
42
+ @queue = Thread::Queue.new
40
43
 
41
- if byte == "\e"
42
- handle_escape byte
43
- else
44
- handle_byte byte
45
- end
46
- rescue EOFError
47
- break
44
+ Thread.new do
45
+ loop do
46
+ byte = read_byte
47
+
48
+ if byte == "\e"
49
+ handle_escape byte
50
+ else
51
+ handle_byte byte
48
52
  end
53
+ rescue EOFError
54
+ break
49
55
  end
50
56
  end
57
+ end
51
58
 
52
- private
59
+ private
53
60
 
54
- def handle_escape(first_byte)
55
- second_byte = read_byte(timeout: true)
61
+ def handle_escape(first_byte)
62
+ second_byte = read_byte(timeout: true)
56
63
 
57
- if second_byte.nil?
58
- @queue << :k_escape
59
- nil
60
- elsif second_byte == "["
61
- third_byte = read_byte(timeout: true)
62
-
63
- case third_byte
64
- when "A"
65
- @queue << :k_up
66
- when "B"
67
- @queue << :k_down
68
- when "C"
69
- @queue << :k_right
70
- when "D"
71
- @queue << :k_left
72
- else
73
- @queue << :k_escape
74
- handle_byte second_byte
75
- handle_byte third_byte if third_byte
76
- end
64
+ if second_byte.nil?
65
+ @queue << :k_escape
66
+ nil
67
+ elsif second_byte == "["
68
+ third_byte = read_byte(timeout: true)
69
+
70
+ case third_byte
71
+ when "A"
72
+ @queue << :k_up
73
+ when "B"
74
+ @queue << :k_down
75
+ when "C"
76
+ @queue << :k_right
77
+ when "D"
78
+ @queue << :k_left
77
79
  else
78
80
  @queue << :k_escape
79
81
  handle_byte second_byte
82
+ handle_byte third_byte if third_byte
80
83
  end
84
+ else
85
+ @queue << :k_escape
86
+ handle_byte second_byte
81
87
  end
88
+ end
82
89
 
83
- def handle_byte(byte)
84
- return unless BYTES.key?(byte)
90
+ def handle_byte(byte)
91
+ return unless BYTES.key?(byte)
85
92
 
86
- @queue << BYTES[byte]
87
- end
93
+ @queue << BYTES[byte]
94
+ end
88
95
 
89
- def read_byte(timeout: false)
90
- return if timeout && !IO.select([STDIN], nil, nil, 0.02)
96
+ def read_byte(timeout: false)
97
+ return if timeout && !IO.select([STDIN], nil, nil, 0.02)
91
98
 
92
- STDIN.readpartial(1)
93
- end
99
+ STDIN.readpartial(1)
94
100
  end
95
101
  end
96
102
  end
data/lib/glw/screen.rb CHANGED
@@ -1,103 +1,105 @@
1
1
  module GLW
2
- module Screen
3
- class << self
4
- UpdateBlock = Data.define(:start_index, :cells) do
5
- def self.make(start_index) = new(start_index, [])
6
-
7
- def to_s(current_fg: nil, current_bg: nil)
8
- output = ""
9
- fg = current_fg
10
- bg = current_bg
11
-
12
- cells.each do |cell|
13
- if cell.fg_color != fg
14
- output << Terminal.set_fg(cell.fg_color)
15
- fg = cell.fg_color
16
- end
17
-
18
- if cell.bg_color != bg
19
- output << Terminal.set_bg(cell.bg_color)
20
- bg = cell.bg_color
21
- end
22
-
23
- output << cell.char
2
+ class Screen
3
+ UpdateBlock = Data.define(:start_index, :cells) do
4
+ def self.make(start_index) = new(start_index, [])
5
+
6
+ def to_s(current_fg: nil, current_bg: nil)
7
+ output = ""
8
+ fg = current_fg
9
+ bg = current_bg
10
+
11
+ cells.each do |cell|
12
+ if cell.fg_color != fg
13
+ output << Terminal.set_fg(cell.fg_color)
14
+ fg = cell.fg_color
24
15
  end
25
16
 
26
- [output, fg, bg]
17
+ if cell.bg_color != bg
18
+ output << Terminal.set_bg(cell.bg_color)
19
+ bg = cell.bg_color
20
+ end
21
+
22
+ output << cell.char
27
23
  end
24
+
25
+ [output, fg, bg]
28
26
  end
27
+ end
29
28
 
30
- def start!
31
- @render_queue = Thread::Queue.new
29
+ def initialize
30
+ @render_queue = nil
31
+ end
32
32
 
33
- @render_queue.push BufferState.blank(
34
- height: IO.console.winsize[0],
35
- width: IO.console.winsize[1]
36
- )
33
+ def start!
34
+ @render_queue = Thread::Queue.new
37
35
 
38
- Thread.new do
39
- STDOUT.print Terminal.hide_cursor
36
+ @render_queue.push BufferState.blank(
37
+ height: IO.console.winsize[0],
38
+ width: IO.console.winsize[1]
39
+ )
40
40
 
41
- last_state = nil
41
+ Thread.new do
42
+ STDOUT.print Terminal.hide_cursor
42
43
 
43
- loop do
44
- state = @render_queue.pop
44
+ last_state = nil
45
45
 
46
- # Throw away stale states until we have the newest one.
47
- state = @render_queue.pop until @render_queue.empty?
46
+ loop do
47
+ state = @render_queue.pop
48
48
 
49
- render(last_state, state)
50
- last_state = state
51
- end
49
+ # Throw away stale states until we have the newest one.
50
+ state = @render_queue.pop until @render_queue.empty?
51
+
52
+ render(last_state, state)
53
+ last_state = state
52
54
  end
53
55
  end
56
+ end
54
57
 
55
- def push_state(state)
56
- @render_queue.push(state)
57
- end
58
+ def push_state(state)
59
+ @render_queue.push(state)
60
+ end
58
61
 
59
- private
62
+ private
60
63
 
61
- def render(last_state, state)
62
- updates = []
63
- current_block = nil
64
+ def render(last_state, state)
65
+ updates = []
66
+ current_block = nil
64
67
 
65
- state.cells.each_with_index do |cell, index|
66
- next if last_state && cell == last_state.cells[index]
68
+ state.cells.each_with_index do |cell, index|
69
+ next if last_state && cell == last_state.cells[index]
67
70
 
68
- if current_block && current_block.start_index + current_block.cells.length == index
69
- current_block.cells << cell
70
- else
71
- updates << current_block if current_block
71
+ if current_block && current_block.start_index + current_block.cells.length == index
72
+ current_block.cells << cell
73
+ else
74
+ updates << current_block if current_block
72
75
 
73
- current_block = UpdateBlock.new(index, [cell])
74
- end
76
+ current_block = UpdateBlock.new(index, [cell])
75
77
  end
78
+ end
76
79
 
77
- updates << current_block if current_block
80
+ updates << current_block if current_block
78
81
 
79
- current_fg = nil
80
- current_bg = nil
82
+ current_fg = nil
83
+ current_bg = nil
81
84
 
82
- STDOUT.print(
83
- updates.flat_map do |block|
84
- y = block.start_index / state.width
85
- x = block.start_index % state.width
85
+ STDOUT.print(
86
+ updates.flat_map do |block|
87
+ y = block.start_index / state.width
88
+ x = block.start_index % state.width
86
89
 
87
- block_output, current_fg, current_bg = block.to_s(
88
- current_fg:,
89
- current_bg:
90
- )
90
+ block_output, current_fg, current_bg = block.to_s(
91
+ current_fg:,
92
+ current_bg:
93
+ )
91
94
 
92
- [
93
- Terminal.move_to(x, y),
94
- block_output
95
- ]
96
- end.join
97
- )
95
+ [
96
+ Terminal.move_to(x, y),
97
+ block_output
98
+ ]
99
+ end.join
100
+ )
98
101
 
99
- STDOUT.flush
100
- end
102
+ STDOUT.flush
101
103
  end
102
104
  end
103
105
  end
@@ -0,0 +1,11 @@
1
+ module GLW
2
+ class Universe
3
+ def singletons
4
+ @singletons ||= Hash.new { |h, k| h[k] = k.make }
5
+ end
6
+
7
+ def render(width:, height:)
8
+ BufferState.blank(width:, height:)
9
+ end
10
+ end
11
+ end
data/lib/glw/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module GLW
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
data/lib/glw.rb CHANGED
@@ -15,17 +15,36 @@ module GLW
15
15
  class << self
16
16
  def start!
17
17
  IO.console.raw do
18
- Screen.start!
19
- Input.start!
18
+ screen = Screen.new
19
+ input = Input.new
20
+
21
+ screen.start!
22
+ input.start!
23
+
24
+ universe = Universe.new
25
+
26
+ target_fps = 20
27
+ frame_time = 1.0 / target_fps
20
28
 
21
29
  loop do
22
- content = Input.pop
30
+ frame_start = Time.now
31
+
32
+ until input.empty?
33
+ key = input.pop
34
+
35
+ exit(0) if key == :k_escape || key == :k_ctrl_c
36
+
37
+ universe.singletons[Components::Input].push key
38
+ end
39
+
40
+ height, width = *IO.console.winsize
41
+ buffer = universe.render(width:, height:)
42
+ screen.push_state(buffer)
23
43
 
24
- exit(0) if content == :k_escape || content == :k_ctrl_c
44
+ elapsed = Time.now - frame_start
45
+ sleep(frame_time - elapsed) if elapsed < frame_time
25
46
  end
26
47
  end
27
- rescue
28
- raise
29
48
  end
30
49
  end
31
50
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: good_luck_wizard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jared Norman
@@ -73,11 +73,13 @@ files:
73
73
  - good_luck_wizard.gemspec
74
74
  - lib/glw.rb
75
75
  - lib/glw/buffer_state.rb
76
+ - lib/glw/components/input.rb
76
77
  - lib/glw/input.rb
77
78
  - lib/glw/random.rb
78
79
  - lib/glw/screen.rb
79
80
  - lib/glw/screen_cell.rb
80
81
  - lib/glw/terminal.rb
82
+ - lib/glw/universe.rb
81
83
  - lib/glw/version.rb
82
84
  - test_input.rb
83
85
  homepage: http://github.com/jarednorman/good_luck_wizard