rubtris 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 66de87c292b7fa0fe1019576f8d2f3d91d63c9c4
4
+ data.tar.gz: f0230d50dd81c8adfa775fccd3294b0e4fdd1d92
5
+ SHA512:
6
+ metadata.gz: 9bc0f5287f299847a6d9f8e51053b8b2143dfab4db280d1041d00808d852b3ab8a232f3683fc74f87750fa87f39f31c9fd8cb04d83fdccf89dcf19f1dc393ac3
7
+ data.tar.gz: 1e315db7ca55658f079a34483170607fad5e4b931279950d832f48c5d433c00cc7be0341df33daa44da4badc15ae13cf4c363ba0f63dfbb5e09a9eea49569aa8
data/lib/block.rb ADDED
@@ -0,0 +1,59 @@
1
+ require 'timeout'
2
+ require 'io/console'
3
+ require_relative 'pattern'
4
+
5
+ class Block
6
+
7
+ attr_accessor :upper_left, :rotation, :pattern
8
+
9
+ PATTERN = [ # Name, Pattern, Size, Color
10
+ Pattern.new(:square, [[0, 0], [0, 1], [1, 0], [1, 1]], 2, :red),
11
+ Pattern.new(:line, [[0, 1], [1, 1], [2, 1], [3, 1]], 4, :cyan),
12
+ Pattern.new(:left_l, [[0, 0], [1, 0], [2, 0], [2, 1]], 3, :blue),
13
+ Pattern.new(:right_l, [[0, 2], [1, 2], [2, 2], [2, 1]], 3, :green),
14
+ Pattern.new(:t_block, [[1, 1], [2, 0], [2, 1], [2, 2]], 3, :red),
15
+ Pattern.new(:n_block_1, [[0, 0], [1, 0], [1, 1], [2, 1]], 3, :yellow),
16
+ Pattern.new(:n_block_2, [[0, 1], [1, 1], [1, 0], [2, 0]], 3, :black)
17
+ ]
18
+
19
+
20
+ def initialize(pattern, upper_left)
21
+ @pattern, @upper_left, @rotation = pattern, upper_left, 0
22
+ end
23
+
24
+ def self.random(upper_left)
25
+ Block.new(PATTERN.sample, upper_left)
26
+ end
27
+
28
+ def spaces_occupied(options = {})
29
+ rotation = options[:rotation] || @rotation
30
+ pos = options[:pos] || @upper_left
31
+ get_vectors(rotation).map do |vector|
32
+ [vector.first + pos.first, vector.last + pos.last]
33
+ end
34
+ end
35
+
36
+ def get_vectors(rotation)
37
+ vectors = @pattern.pattern
38
+
39
+ (rotation.abs % 4 ).times do
40
+ vectors.map! do |coord|
41
+ rotation > 0 ? rotate_coord_right(coord) : rotate_coord_left(coord)
42
+ end
43
+ end
44
+
45
+ vectors
46
+ end
47
+
48
+ def rotate_coord_right(coord)
49
+ i, j = coord
50
+ size = @pattern.size
51
+ [j , (size - 1) - i]
52
+ end
53
+
54
+ def rotate_coord_left(coord)
55
+ i, j = coord
56
+ size = @pattern.size
57
+ [(size - 1) - j, i]
58
+ end
59
+ end
data/lib/board.rb ADDED
@@ -0,0 +1,176 @@
1
+ require_relative 'block'
2
+ require_relative 'pattern'
3
+ require 'colorize'
4
+
5
+ class Board
6
+
7
+ attr_reader :completed_lines
8
+
9
+ WIDTH = 10
10
+ HEIGHT = 22
11
+ STARTING_POINT = [0, 4]
12
+ SCORE_MULTIPLIER = 2
13
+
14
+ def initialize
15
+ @grid, @over, @completed_lines = Array.new(HEIGHT) { Array.new(WIDTH) }, false, 0
16
+ @start_time, @time_limit, @line_limit = Time.now, nil, nil
17
+ @score, @level = 0, 0
18
+ end
19
+
20
+ def [](coord)
21
+ @grid[coord.first][coord.last]
22
+ end
23
+
24
+ def []=(coord, val)
25
+ @grid[coord.first][coord.last] = val
26
+ end
27
+
28
+ def render
29
+ str = ""
30
+ @grid.each_with_index do |row, i|
31
+ row.each do |pos|
32
+ str += pos.nil? ? " " : " ".colorize(background: pos.pattern.color)
33
+ end
34
+ str+= "*"
35
+ if i == 1
36
+ str += " WASD to move. '[' and ']' to rotate."
37
+ elsif i == 2
38
+ str += " #{summary_s}"
39
+ end
40
+ str += "\n"
41
+ end
42
+ str = " " * (WIDTH + 1) + "\n" + str + "- " * (WIDTH + 1) + "\n"
43
+ puts str
44
+ end
45
+
46
+ def summary_s
47
+ "LINES: #{@completed_lines} LEVEL: #{level} SCORE: #{@score}"
48
+ end
49
+
50
+ def level
51
+ @completed_lines / 10
52
+ end
53
+
54
+ def filled?(space)
55
+ !self[space].nil?
56
+ end
57
+
58
+ def any_filled?(spaces)
59
+ spaces.any?{ |space| filled?(space) }
60
+ end
61
+
62
+ def all_filled?(spaces)
63
+ spaces.all?{ |space| filled?(space) }
64
+ end
65
+
66
+ def add_to_spaces(block, spaces)
67
+ spaces.each do |space|
68
+ self[space] = block
69
+ end
70
+ end
71
+
72
+ def remove_from_spaces(spaces)
73
+ spaces.each do |space|
74
+ self[space] = nil
75
+ end
76
+ end
77
+
78
+ def add_block
79
+ block = Block.random(STARTING_POINT)
80
+ spaces = block.spaces_occupied
81
+ return false if any_filled?(spaces)
82
+ add_to_spaces(block, spaces)
83
+ @selected.upper_left = nil unless @selected.nil?
84
+ @selected = block
85
+ true
86
+ end
87
+
88
+ def change_direction(block, options = {})
89
+ i, j, turn = options[:i], options[:j], options[:turn]
90
+ new_upper_left = (i && j) ? [block.upper_left.first + i, block.upper_left.last + j] : block.upper_left
91
+ new_rotation = (turn) ? block.rotation + turn : block.rotation
92
+ old_spaces = block.spaces_occupied
93
+ new_spaces = block.spaces_occupied(pos: new_upper_left, rotation: new_rotation)
94
+ old_territory = old_spaces - new_spaces
95
+ new_territory = new_spaces - old_spaces
96
+ # p "i: #{i} j: #{j} turn: #{turn} new_upper_left: #{new_upper_left} new_rotation: #{new_rotation}"
97
+ # p "old_spaces: #{old_spaces} new_spaces: #{new_spaces} old_territory: #{old_territory} new_territory: #{new_territory}"
98
+ return false unless new_spaces.all? { |coord| on_board?(coord) }
99
+ return false if any_filled?(new_territory)
100
+ remove_from_spaces(old_territory)
101
+ add_to_spaces(block, new_territory)
102
+ block.upper_left, block.rotation = new_upper_left, new_rotation
103
+ true
104
+ end
105
+
106
+ def on_board?(space)
107
+ space.first.between?(0, HEIGHT - 1) && space.last.between?(0, WIDTH - 1)
108
+ end
109
+
110
+ def push_selected_down
111
+ unless change_direction(@selected, i: 5, j: 0)
112
+ move_selected_down
113
+ end
114
+ end
115
+
116
+ def move_to_bottom
117
+ id = @selected.object_id
118
+ while change_direction(@selected, i: 1, j: 0) && id == @selected.object_id
119
+ move_selected_down
120
+ end
121
+ end
122
+
123
+ def move_selected_down
124
+ unless change_direction(@selected, i: 1, j: 0)
125
+ remove_completed_line_and_increase_score
126
+ @over = !add_block
127
+ end
128
+ end
129
+
130
+ def move_selected_left
131
+ change_direction(@selected, i: 0, j: -1)
132
+ end
133
+
134
+ def move_selected_right
135
+ change_direction(@selected, i: 0, j: 1)
136
+ end
137
+
138
+ def rotate_selected_left
139
+ change_direction(@selected, turn: -1)
140
+ end
141
+
142
+ def rotate_selected_right
143
+ change_direction(@selected, turn: 1)
144
+ end
145
+
146
+ def remove_and_shift(row_num)
147
+ @grid[row_num] = Array.new(WIDTH)
148
+ until @grid[row_num - 1].all?(&:nil?)
149
+ @grid[row_num] = @grid[row_num -= 1]
150
+ @grid[row_num] = Array.new(WIDTH)
151
+ end
152
+ end
153
+
154
+ def remove_completed_line_and_increase_score
155
+ lines = 0
156
+ i = HEIGHT - 1
157
+ until i == 0
158
+ spaces_on_row = [i].product((0...WIDTH).to_a)
159
+ if all_filled?(spaces_on_row)
160
+ remove_and_shift(i)
161
+ lines += 1
162
+ else
163
+ i -= 1
164
+ end
165
+ end
166
+ @completed_lines += lines
167
+ @score += (lines * SCORE_MULTIPLIER) ** 2
168
+ end
169
+
170
+ def over?
171
+ @over
172
+ end
173
+
174
+
175
+
176
+ end
data/lib/menu.rb ADDED
@@ -0,0 +1,66 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ class Menu
4
+
5
+
6
+ def initialize(options, prompt)
7
+ @prompt = prompt.center(33)
8
+ @options = options
9
+ @selected = 0
10
+ @done = false
11
+ end
12
+
13
+ def open
14
+ until done?
15
+ system "clear" or system "cls"
16
+ render
17
+ input = STDIN.getch
18
+ take_action(input)
19
+ end
20
+ return @options[@selected]
21
+ end
22
+
23
+ def render
24
+ str = @options.map.with_index do |option, i|
25
+ if option[:type] == :increment
26
+ line = "◀ #{option[:title]}: #{option[:value]} #{option[:unit]} ►".center(33)
27
+ else
28
+ line = "#{option[:title]}".center(33)
29
+ end
30
+ i == @selected ? line.on_yellow : line
31
+ end.join("\n")
32
+ puts @prompt
33
+ puts str
34
+ end
35
+
36
+ def take_action(input)
37
+ case input
38
+ when "w"
39
+ @selected = (@selected - 1) % @options.length
40
+ when "a"
41
+ increment_selected(-1)
42
+ when "s"
43
+ @selected = (@selected + 1) % @options.length
44
+ when "d"
45
+ increment_selected(1)
46
+ when "\r"
47
+ @done = true
48
+ when "p"
49
+ @done = true
50
+ when "\e"
51
+ @done = true
52
+ end
53
+ nil
54
+ end
55
+
56
+ def increment_selected(num)
57
+ return nil unless @options[@selected][:type] == :increment
58
+ new_val = @options[@selected][:value] + num
59
+ @options[@selected][:value] = [new_val, 1].max
60
+ end
61
+
62
+ def done?
63
+ @done
64
+ end
65
+
66
+ end
data/lib/pattern.rb ADDED
@@ -0,0 +1,10 @@
1
+ class Pattern
2
+ attr_accessor :name, :size, :color, :pattern
3
+ def initialize(name, pattern, size, color)
4
+ @name, @pattern, @size, @color = name, pattern, size, color
5
+ end
6
+
7
+ def pattern
8
+ @pattern.map(&:dup)
9
+ end
10
+ end
data/lib/rubtris.rb ADDED
@@ -0,0 +1,144 @@
1
+ require_relative 'board'
2
+ require 'timeout'
3
+ require 'io/console'
4
+ require_relative 'menu'
5
+
6
+ class Rubtris
7
+
8
+ REFRESH_RATE = 0.1
9
+ BEGINNING_ADVANCE_RATE = 0.3
10
+ MINIMUM_ADVANCE_RATE = 0.05
11
+ DIF_BTWN_LEVEL = 0.04
12
+
13
+
14
+ def run
15
+ set_up_game
16
+ until over?
17
+ do_turn
18
+ end
19
+ end_game
20
+ run if !force_quit? && play_again
21
+ end
22
+
23
+ def get_mode
24
+ options = [
25
+ {title: "Unlimited", type: :none, value: true},
26
+ {title: "Timed", type: :increment, value: 3, unit: 'min.'},
27
+ {title: "Lines", type: :increment, value: 40}
28
+ ]
29
+ prompt = "Welcome to Rubtris.\nSelect the mode you want to play!"
30
+ menu = Menu.new(options, prompt)
31
+ @game_mode = menu.open
32
+ end
33
+
34
+ def play_again
35
+ options = [
36
+ {title: "Yes", type: :none, value: true},
37
+ {title: "No", type: :none, value: false}
38
+ ]
39
+ prompt = "#{@board.summary_s}\nPlay again?"
40
+ menu = Menu.new(options, prompt)
41
+ menu.open[:value]
42
+ end
43
+
44
+ def set_up_game
45
+ @board = Board.new
46
+ STDIN.echo = false
47
+ @force_quit = false
48
+ @board.add_block
49
+ @board.render
50
+ @start_time, @last_advanced, @level = Time.now, Time.now, 0
51
+ @time_limit, @line_limit = nil, nil
52
+ config = get_mode
53
+ add_win_condition(config[:title], config[:value])
54
+ end
55
+
56
+ def do_turn
57
+ auto_advance if auto_advance_needed?
58
+ system "clear" or system "cls"
59
+ @board.render
60
+ action = get_input
61
+ take_action(action) if action
62
+ end
63
+
64
+ def end_game
65
+ STDIN.echo = true
66
+ end
67
+
68
+ def current_advance_rate
69
+ [BEGINNING_ADVANCE_RATE - (@level * DIF_BTWN_LEVEL), MINIMUM_ADVANCE_RATE].max
70
+ end
71
+
72
+ def auto_advance_needed?
73
+ Time.now - @last_advanced > current_advance_rate
74
+ end
75
+
76
+ def auto_advance
77
+ @last_advanced = Time.now
78
+ @board.move_selected_down
79
+ end
80
+
81
+ def get_input
82
+ action = nil
83
+ begin
84
+ action = Timeout::timeout(REFRESH_RATE) { STDIN.getch }
85
+ rescue
86
+ end
87
+ action
88
+ end
89
+
90
+ def force_quit?
91
+ @force_quit
92
+ end
93
+
94
+ def take_action(action)
95
+ case action.downcase
96
+ when "w"
97
+ @board.move_to_bottom
98
+ when "a"
99
+ @board.move_selected_left
100
+ when "s"
101
+ @board.move_selected_down
102
+ when "d"
103
+ @board.move_selected_right
104
+ when "\r"
105
+ @board.push_selected_down
106
+ when "e"
107
+ @board.rotate_selected_right
108
+ when "q"
109
+ @board.rotate_selected_left
110
+ when "["
111
+ @board.rotate_selected_left
112
+ when "]"
113
+ @board.rotate_selected_right
114
+ when "\e"
115
+ @force_quit = true
116
+ end
117
+ nil
118
+ end
119
+
120
+ def over?
121
+ force_quit? || @board.over? || over_time? || over_lines?
122
+ end
123
+
124
+ def over_time?
125
+ @time_limit && (@last_advanced - @start_time) >= @time_limit
126
+ end
127
+
128
+ def over_lines?
129
+ @line_limit && @board.completed_lines >= @line_limit
130
+ end
131
+
132
+ def add_win_condition(condition, value)
133
+ case condition
134
+ when "Timed"
135
+ @time_limit = value * 60
136
+ when "Lines"
137
+ @line_limit = value
138
+ end
139
+ end
140
+
141
+ end
142
+
143
+ t = Rubtris.new
144
+ t.run
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubtris
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ben Henderson
8
+ - Danny Burt
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-12-09 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Command line Tetrino based puzzle game!
15
+ email: benjamin.c.henderson@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/block.rb
21
+ - lib/board.rb
22
+ - lib/menu.rb
23
+ - lib/pattern.rb
24
+ - lib/rubtris.rb
25
+ homepage: http://rubygems.org/gems/rubtris
26
+ licenses:
27
+ - MIT
28
+ metadata: {}
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubyforge_project:
45
+ rubygems_version: 2.2.2
46
+ signing_key:
47
+ specification_version: 4
48
+ summary: Command line Tetrino based puzzle game!
49
+ test_files: []