glimmer-dsl-swt 4.18.2.0 → 4.18.2.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,313 @@
1
+ # Copyright (c) 2007-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require_relative 'block'
23
+
24
+ require 'matrix'
25
+
26
+ class Tetris
27
+ module Model
28
+ class Tetromino
29
+ ORIENTATIONS = [:north, :east, :south, :west]
30
+
31
+ LETTER_COLORS = {
32
+ I: :cyan,
33
+ J: :blue,
34
+ L: :dark_yellow,
35
+ O: :yellow,
36
+ S: :green,
37
+ T: :magenta,
38
+ Z: :red,
39
+ }
40
+
41
+ attr_reader :letter, :preview
42
+ alias preview? preview
43
+ attr_accessor :orientation, :blocks, :row, :column
44
+
45
+ def initialize
46
+ @letter = LETTER_COLORS.keys.sample
47
+ @orientation = :north
48
+ @blocks = default_blocks
49
+ @preview = true
50
+ new_row = 0
51
+ new_column = (PREVIEW_PLAYFIELD_WIDTH - width)/2
52
+ update_playfield(new_row, new_column)
53
+ end
54
+
55
+ def playfield
56
+ @preview ? Game.preview_playfield : Game.playfield
57
+ end
58
+
59
+ def launch!
60
+ remove_from_playfield
61
+ @preview = false
62
+ new_row = 1 - height
63
+ new_column = (PLAYFIELD_WIDTH - width)/2
64
+ update_playfield(new_row, new_column)
65
+ Game.tetrominoes << self
66
+ end
67
+
68
+ def update_playfield(new_row = nil, new_column = nil)
69
+ remove_from_playfield
70
+ if !new_row.nil? && !new_column.nil?
71
+ @row = new_row
72
+ @column = new_column
73
+ add_to_playfield
74
+ end
75
+ end
76
+
77
+ def add_to_playfield
78
+ update_playfield_block do |playfield_row, playfield_column, row_index, column_index|
79
+ playfield[playfield_row][playfield_column].color = blocks[row_index][column_index].color if playfield_row >= 0 && playfield[playfield_row][playfield_column]&.clear? && !blocks[row_index][column_index].clear? && playfield[playfield_row][playfield_column].color != blocks[row_index][column_index].color
80
+ end
81
+ end
82
+
83
+ def remove_from_playfield
84
+ return if @row.nil? || @column.nil?
85
+ update_playfield_block do |playfield_row, playfield_column, row_index, column_index|
86
+ playfield[playfield_row][playfield_column].clear if playfield_row >= 0 && !blocks[row_index][column_index].clear? && playfield[playfield_row][playfield_column]&.color == color
87
+ end
88
+ end
89
+
90
+ def stopped?
91
+ return true if @stopped || @preview
92
+ playfield_remaining_heights = Game.playfield_remaining_heights(self)
93
+ result = bottom_most_blocks.any? do |bottom_most_block|
94
+ playfield_column = @column + bottom_most_block[:column_index]
95
+ playfield_remaining_heights[playfield_column] &&
96
+ @row + bottom_most_block[:row] >= playfield_remaining_heights[playfield_column] - 1
97
+ end
98
+ if result && !Game.hypothetical?
99
+ @stopped = result
100
+ Game.consider_eliminating_lines
101
+ Model::Game.consider_adding_tetromino
102
+ end
103
+ result
104
+ end
105
+
106
+ # Returns bottom-most blocks of a tetromino, which could be from multiple rows depending on shape (e.g. T)
107
+ def bottom_most_blocks
108
+ width.times.map do |column_index|
109
+ row_blocks_with_row_index = @blocks.each_with_index.to_a.reverse.detect do |row_blocks, row_index|
110
+ !row_blocks[column_index].clear?
111
+ end
112
+ bottom_most_block = row_blocks_with_row_index[0][column_index]
113
+ bottom_most_block_row = row_blocks_with_row_index[1]
114
+ {
115
+ block: bottom_most_block,
116
+ row: bottom_most_block_row,
117
+ column_index: column_index
118
+ }
119
+ end
120
+ end
121
+
122
+ def bottom_most_block_for_column(column)
123
+ bottom_most_blocks.detect {|bottom_most_block| (@column + bottom_most_block[:column_index]) == column}
124
+ end
125
+
126
+ def right_blocked?
127
+ (@column == PLAYFIELD_WIDTH - width) ||
128
+ right_most_blocks.any? { |right_most_block|
129
+ playfield[@row + right_most_block[:row_index]][@column + right_most_block[:column_index] + 1].occupied?
130
+ }
131
+ end
132
+
133
+ # Returns right-most blocks of a tetromino, which could be from multiple columns depending on shape (e.g. T)
134
+ def right_most_blocks
135
+ @blocks.each_with_index.map do |row_blocks, row_index|
136
+ column_block_with_column_index = row_blocks.each_with_index.to_a.reverse.detect do |column_block, column_index|
137
+ !column_block.clear?
138
+ end
139
+ if column_block_with_column_index
140
+ right_most_block = column_block_with_column_index[0]
141
+ {
142
+ block: right_most_block,
143
+ row_index: row_index,
144
+ column_index: column_block_with_column_index[1]
145
+ }
146
+ end
147
+ end.compact
148
+ end
149
+
150
+ def left_blocked?
151
+ (@column == 0) ||
152
+ left_most_blocks.any? { |left_most_block|
153
+ playfield[@row + left_most_block[:row_index]][@column + left_most_block[:column_index] - 1].occupied?
154
+ }
155
+ end
156
+
157
+ # Returns right-most blocks of a tetromino, which could be from multiple columns depending on shape (e.g. T)
158
+ def left_most_blocks
159
+ @blocks.each_with_index.map do |row_blocks, row_index|
160
+ column_block_with_column_index = row_blocks.each_with_index.to_a.detect do |column_block, column_index|
161
+ !column_block.clear?
162
+ end
163
+ if column_block_with_column_index
164
+ left_most_block = column_block_with_column_index[0]
165
+ {
166
+ block: left_most_block,
167
+ row_index: row_index,
168
+ column_index: column_block_with_column_index[1]
169
+ }
170
+ end
171
+ end.compact
172
+ end
173
+
174
+ def width
175
+ @blocks[0].size
176
+ end
177
+
178
+ def height
179
+ @blocks.size
180
+ end
181
+
182
+ def down
183
+ launch! if preview?
184
+ unless stopped?
185
+ new_row = @row + 1
186
+ update_playfield(new_row, @column)
187
+ end
188
+ end
189
+
190
+ def left
191
+ unless left_blocked?
192
+ new_column = @column - 1
193
+ update_playfield(@row, new_column)
194
+ end
195
+ end
196
+
197
+ def right
198
+ unless right_blocked?
199
+ new_column = @column + 1
200
+ update_playfield(@row, new_column)
201
+ end
202
+ end
203
+
204
+ # Rotate in specified direcation, which can be :right (clockwise) or :left (counterclockwise)
205
+ def rotate(direction)
206
+ return if stopped?
207
+ can_rotate = nil
208
+ new_blocks = nil
209
+ Game.hypothetical do
210
+ hypothetical_rotated_tetromino = hypothetical_tetromino
211
+ new_blocks = hypothetical_rotated_tetromino.rotate_blocks(direction)
212
+ can_rotate = !hypothetical_rotated_tetromino.stopped? && !hypothetical_rotated_tetromino.right_blocked? && !hypothetical_rotated_tetromino.left_blocked?
213
+ end
214
+ if can_rotate
215
+ remove_from_playfield
216
+ self.orientation = ORIENTATIONS[ORIENTATIONS.rotate(direction == :right ? -1 : 1).index(@orientation)]
217
+ self.blocks = new_blocks
218
+ update_playfield(@row, @column)
219
+ end
220
+ rescue => e
221
+ puts e.full_message
222
+ end
223
+
224
+ def rotate_blocks(direction)
225
+ new_blocks = Matrix[*@blocks].transpose.to_a
226
+ if direction == :right
227
+ new_blocks = new_blocks.map(&:reverse)
228
+ else
229
+ new_blocks = new_blocks.reverse
230
+ end
231
+ Matrix[*new_blocks].to_a
232
+ end
233
+
234
+ def hypothetical_tetromino
235
+ clone.tap do |hypo_clone|
236
+ remove_from_playfield
237
+ hypo_clone.blocks = @blocks.map do |row_blocks|
238
+ row_blocks.map do |column_block|
239
+ column_block.clone
240
+ end
241
+ end
242
+ end
243
+ end
244
+
245
+ def default_blocks
246
+ case @letter
247
+ when :I
248
+ [
249
+ [block, block, block, block]
250
+ ]
251
+ when :J
252
+ [
253
+ [block, block, block],
254
+ [empty, empty, block],
255
+ ]
256
+ when :L
257
+ [
258
+ [block, block, block],
259
+ [block, empty, empty],
260
+ ]
261
+ when :O
262
+ [
263
+ [block, block],
264
+ [block, block],
265
+ ]
266
+ when :S
267
+ [
268
+ [empty, block, block],
269
+ [block, block, empty],
270
+ ]
271
+ when :T
272
+ [
273
+ [block, block, block],
274
+ [empty, block, empty],
275
+ ]
276
+ when :Z
277
+ [
278
+ [block, block, empty],
279
+ [empty, block, block],
280
+ ]
281
+ end
282
+ end
283
+
284
+ def color
285
+ LETTER_COLORS[@letter]
286
+ end
287
+
288
+ def include_block?(block)
289
+ @blocks.flatten.include?(block)
290
+ end
291
+
292
+ private
293
+
294
+ def block
295
+ Block.new(color)
296
+ end
297
+
298
+ def empty
299
+ Block.new
300
+ end
301
+
302
+ def update_playfield_block(&updater)
303
+ @row.upto(@row + height - 1) do |playfield_row|
304
+ @column.upto(@column + width - 1) do |playfield_column|
305
+ row_index = playfield_row - @row
306
+ column_index = playfield_column - @column
307
+ updater.call(playfield_row, playfield_column, row_index, column_index)
308
+ end
309
+ end
310
+ end
311
+ end
312
+ end
313
+ end
@@ -0,0 +1,70 @@
1
+ # Copyright (c) 2007-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ class Tetris
23
+ module View
24
+ class Block
25
+ include Glimmer::UI::CustomWidget
26
+
27
+ options :game_playfield, :block_size, :row, :column
28
+
29
+ before_body {
30
+ @bevel_constant = 20
31
+ }
32
+
33
+ body {
34
+ canvas {
35
+ layout nil
36
+ background bind(game_playfield[row][column], :color)
37
+ polygon(0, 0, block_size, 0, block_size - 4, 4, 4, 4, fill: true) {
38
+ background bind(game_playfield[row][column], :color) { |color_value|
39
+ color = color(color_value)
40
+ rgb(color.red + 4*@bevel_constant, color.green + 4*@bevel_constant, color.blue + 4*@bevel_constant)
41
+ }
42
+ }
43
+ polygon(block_size, 0, block_size - 4, 4, block_size - 4, block_size - 4, block_size, block_size, fill: true) {
44
+ background bind(game_playfield[row][column], :color) { |color_value|
45
+ color = color(color_value)
46
+ rgb(color.red - @bevel_constant, color.green - @bevel_constant, color.blue - @bevel_constant)
47
+ }
48
+ }
49
+ polygon(block_size, block_size, 0, block_size, 4, block_size - 4, block_size - 4, block_size - 4, fill: true) {
50
+ background bind(game_playfield[row][column], :color) { |color_value|
51
+ color = color(color_value)
52
+ rgb(color.red - 2*@bevel_constant, color.green - 2*@bevel_constant, color.blue - 2*@bevel_constant)
53
+ }
54
+ }
55
+ polygon(0, 0, 0, block_size, 4, block_size - 4, 4, 4, fill: true) {
56
+ background bind(game_playfield[row][column], :color) { |color_value|
57
+ color = color(color_value)
58
+ rgb(color.red - @bevel_constant, color.green - @bevel_constant, color.blue - @bevel_constant)
59
+ }
60
+ }
61
+ rectangle(0, 0, block_size, block_size) {
62
+ foreground bind(game_playfield[row][column], :color) { |color_value|
63
+ color_value == Model::Block::COLOR_CLEAR ? :gray : color_value
64
+ }
65
+ }
66
+ }
67
+ }
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,72 @@
1
+ # Copyright (c) 2007-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ class Tetris
23
+ module View
24
+ class GameOverDialog
25
+ include Glimmer::UI::CustomShell
26
+
27
+ options :parent_shell
28
+
29
+ body {
30
+ dialog(parent_shell) {
31
+ row_layout {
32
+ type :vertical
33
+ center true
34
+ }
35
+ text 'Tetris'
36
+
37
+ label(:center) {
38
+ text 'Game Over!'
39
+ font name: 'Menlo', height: 30, style: :bold
40
+ }
41
+ label # filler
42
+ button {
43
+ text 'Play Again?'
44
+
45
+ on_widget_selected {
46
+ Model::Game.restart
47
+
48
+ body_root.close
49
+ }
50
+ }
51
+
52
+ on_shell_activated {
53
+ Model::Game.game_over = true
54
+ display.beep
55
+ }
56
+
57
+ on_shell_closed {
58
+ exit_game
59
+ }
60
+
61
+ on_key_pressed { |event|
62
+ exit_game if event.keyCode == swt(:cr)
63
+ }
64
+ }
65
+ }
66
+
67
+ def exit_game
68
+ display.dispose if Model::Game.game_over?
69
+ end
70
+ end
71
+ end
72
+ end