teek 0.1.1 → 0.1.3
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 +4 -4
- data/README.md +46 -0
- data/Rakefile +162 -5
- data/ext/teek/extconf.rb +1 -1
- data/ext/teek/tcltkbridge.c +9 -0
- data/ext/teek/tcltkbridge.h +3 -0
- data/ext/teek/tkeventsource.c +195 -0
- data/ext/teek/tkphoto.c +169 -5
- data/ext/teek/tkwin.c +84 -0
- data/lib/teek/background_ractor4x.rb +32 -4
- data/lib/teek/photo.rb +232 -0
- data/lib/teek/version.rb +1 -1
- data/lib/teek.rb +202 -5
- data/sample/gamepad_viewer/assets/controller.png +0 -0
- data/sample/gamepad_viewer/gamepad_viewer.rb +554 -0
- data/sample/optcarrot/thwaite.nes +0 -0
- data/sample/optcarrot/vendor/optcarrot/apu.rb +856 -0
- data/sample/optcarrot/vendor/optcarrot/config.rb +257 -0
- data/sample/optcarrot/vendor/optcarrot/cpu.rb +1162 -0
- data/sample/optcarrot/vendor/optcarrot/driver.rb +144 -0
- data/sample/optcarrot/vendor/optcarrot/mapper/cnrom.rb +14 -0
- data/sample/optcarrot/vendor/optcarrot/mapper/mmc1.rb +105 -0
- data/sample/optcarrot/vendor/optcarrot/mapper/mmc3.rb +153 -0
- data/sample/optcarrot/vendor/optcarrot/mapper/uxrom.rb +14 -0
- data/sample/optcarrot/vendor/optcarrot/nes.rb +105 -0
- data/sample/optcarrot/vendor/optcarrot/opt.rb +168 -0
- data/sample/optcarrot/vendor/optcarrot/pad.rb +92 -0
- data/sample/optcarrot/vendor/optcarrot/palette.rb +65 -0
- data/sample/optcarrot/vendor/optcarrot/ppu.rb +1468 -0
- data/sample/optcarrot/vendor/optcarrot/rom.rb +143 -0
- data/sample/optcarrot/vendor/optcarrot.rb +14 -0
- data/sample/optcarrot.rb +354 -0
- data/sample/paint/assets/bucket.png +0 -0
- data/sample/paint/assets/cursor.png +0 -0
- data/sample/paint/assets/eraser.png +0 -0
- data/sample/paint/assets/pencil.png +0 -0
- data/sample/paint/assets/spray.png +0 -0
- data/sample/paint/layer.rb +255 -0
- data/sample/paint/layer_manager.rb +179 -0
- data/sample/paint/paint_demo.rb +837 -0
- data/sample/paint/sparse_pixel_buffer.rb +202 -0
- data/sample/sdl2_demo.rb +318 -0
- data/sample/yam/assets/click.wav +0 -0
- data/sample/yam/assets/explosion.wav +0 -0
- data/sample/yam/assets/flag.wav +0 -0
- data/sample/yam/assets/music.mp3 +0 -0
- data/sample/yam/assets/sweep.wav +0 -0
- data/sample/{minesweeper/minesweeper.rb → yam/yam.rb} +147 -12
- metadata +50 -14
- /data/sample/{minesweeper → yam}/assets/MINESWEEPER_0.png +0 -0
- /data/sample/{minesweeper → yam}/assets/MINESWEEPER_1.png +0 -0
- /data/sample/{minesweeper → yam}/assets/MINESWEEPER_2.png +0 -0
- /data/sample/{minesweeper → yam}/assets/MINESWEEPER_3.png +0 -0
- /data/sample/{minesweeper → yam}/assets/MINESWEEPER_4.png +0 -0
- /data/sample/{minesweeper → yam}/assets/MINESWEEPER_5.png +0 -0
- /data/sample/{minesweeper → yam}/assets/MINESWEEPER_6.png +0 -0
- /data/sample/{minesweeper → yam}/assets/MINESWEEPER_7.png +0 -0
- /data/sample/{minesweeper → yam}/assets/MINESWEEPER_8.png +0 -0
- /data/sample/{minesweeper → yam}/assets/MINESWEEPER_F.png +0 -0
- /data/sample/{minesweeper → yam}/assets/MINESWEEPER_M.png +0 -0
- /data/sample/{minesweeper → yam}/assets/MINESWEEPER_X.png +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
# teek-record: title=Yet Another Minesweeper, audio=1
|
|
2
3
|
#
|
|
3
4
|
# Minesweeper clone built with Teek.
|
|
4
5
|
#
|
|
@@ -13,8 +14,14 @@
|
|
|
13
14
|
#
|
|
14
15
|
# Tile artwork: "Minesweeper Tile Set" by eugeneloza (CC0)
|
|
15
16
|
# https://opengameart.org/content/minesweeper-tile-set
|
|
17
|
+
#
|
|
18
|
+
# Sound effects: generated with jsfxr (https://sfxr.me), public domain
|
|
19
|
+
# Music: "Vaporware" by The Cynic Project (CC0)
|
|
20
|
+
# https://opengameart.org/content/calm-piano-1-vaporware
|
|
21
|
+
# cynicmusic.com / pixelsphere.org
|
|
16
22
|
|
|
17
23
|
require_relative '../../lib/teek'
|
|
24
|
+
require_relative '../../teek-sdl2/lib/teek/sdl2'
|
|
18
25
|
|
|
19
26
|
class Minesweeper
|
|
20
27
|
# The source PNGs are 216x216. Tk can shrink them with "copy -subsample N N"
|
|
@@ -28,15 +35,22 @@ class Minesweeper
|
|
|
28
35
|
expert: { cols: 30, rows: 16, mines: 99 }
|
|
29
36
|
}.freeze
|
|
30
37
|
|
|
38
|
+
attr_reader :app
|
|
39
|
+
|
|
31
40
|
def initialize(app, level: :beginner)
|
|
32
41
|
@app = app
|
|
33
42
|
@level = level
|
|
34
43
|
apply_level
|
|
35
44
|
load_images
|
|
45
|
+
load_sounds
|
|
36
46
|
build_ui
|
|
37
47
|
new_game
|
|
38
48
|
end
|
|
39
49
|
|
|
50
|
+
# Simulate press/release on a cell for demo/test automation.
|
|
51
|
+
def press_cell(r, c) = on_left_press(r, c)
|
|
52
|
+
def release_cell(r, c) = on_left_release(r, c)
|
|
53
|
+
|
|
40
54
|
private
|
|
41
55
|
|
|
42
56
|
# -- Setup ---------------------------------------------------------------
|
|
@@ -83,10 +97,21 @@ class Minesweeper
|
|
|
83
97
|
end
|
|
84
98
|
end
|
|
85
99
|
|
|
100
|
+
def load_sounds
|
|
101
|
+
dir = File.join(__dir__, 'assets')
|
|
102
|
+
@snd_click = Teek::SDL2::Sound.new(File.join(dir, 'click.wav'))
|
|
103
|
+
@snd_sweep = Teek::SDL2::Sound.new(File.join(dir, 'sweep.wav'))
|
|
104
|
+
@snd_flag = Teek::SDL2::Sound.new(File.join(dir, 'flag.wav'))
|
|
105
|
+
@snd_explosion = Teek::SDL2::Sound.new(File.join(dir, 'explosion.wav'))
|
|
106
|
+
@music = Teek::SDL2::Music.new(File.join(dir, 'music.mp3'))
|
|
107
|
+
@music.volume = 48
|
|
108
|
+
@music_on = true
|
|
109
|
+
end
|
|
110
|
+
|
|
86
111
|
def build_ui
|
|
87
112
|
# "wm" commands control the window manager -- title, resizability, etc.
|
|
88
113
|
# "." is the root Tk window (every widget path starts from here).
|
|
89
|
-
@app.command(:wm, :title, '.', 'Minesweeper')
|
|
114
|
+
@app.command(:wm, :title, '.', 'Yet Another Minesweeper')
|
|
90
115
|
@app.command(:wm, :resizable, '.', 0, 0)
|
|
91
116
|
|
|
92
117
|
build_menu
|
|
@@ -165,6 +190,13 @@ class Minesweeper
|
|
|
165
190
|
font: 'TkFixedFont 14 bold', fg: :red, bg: :black,
|
|
166
191
|
relief: :sunken, anchor: :center)
|
|
167
192
|
@app.command(:pack, '.hdr.time', side: :right, padx: 5, pady: 3)
|
|
193
|
+
|
|
194
|
+
# Music toggle (right, next to timer)
|
|
195
|
+
@music_btn = '.hdr.music'
|
|
196
|
+
@app.command(:button, @music_btn, text: "\u266A", width: 2,
|
|
197
|
+
font: 'TkDefaultFont 10',
|
|
198
|
+
command: proc { |*| toggle_music })
|
|
199
|
+
@app.command(:pack, @music_btn, side: :right, padx: 2, pady: 3)
|
|
168
200
|
end
|
|
169
201
|
|
|
170
202
|
# The game grid is a single Tk canvas filled with image items.
|
|
@@ -184,15 +216,27 @@ class Minesweeper
|
|
|
184
216
|
@app.command(:canvas, @canvas, width: cw, height: ch, highlightthickness: 0)
|
|
185
217
|
@app.command(:pack, @canvas)
|
|
186
218
|
|
|
187
|
-
# Left-click:
|
|
188
|
-
|
|
219
|
+
# Left-click: press shows sunken tile + suspense face, release reveals.
|
|
220
|
+
# This mimics classic Windows Minesweeper's press-and-hold behavior.
|
|
221
|
+
@pressed_cell = nil
|
|
222
|
+
|
|
223
|
+
press_cb = @app.register_callback(proc { |*|
|
|
189
224
|
row, col = canvas_cell
|
|
190
|
-
|
|
225
|
+
on_left_press(row, col) if row
|
|
191
226
|
})
|
|
192
|
-
@app.tcl_eval("bind #{@canvas} <
|
|
227
|
+
@app.tcl_eval("bind #{@canvas} <ButtonPress-1> " \
|
|
193
228
|
"{set ::_ms_x [#{@canvas} canvasx %x]; " \
|
|
194
229
|
"set ::_ms_y [#{@canvas} canvasy %y]; " \
|
|
195
|
-
"ruby_callback #{
|
|
230
|
+
"ruby_callback #{press_cb}}")
|
|
231
|
+
|
|
232
|
+
release_cb = @app.register_callback(proc { |*|
|
|
233
|
+
row, col = canvas_cell
|
|
234
|
+
on_left_release(row, col) if row
|
|
235
|
+
})
|
|
236
|
+
@app.tcl_eval("bind #{@canvas} <ButtonRelease-1> " \
|
|
237
|
+
"{set ::_ms_x [#{@canvas} canvasx %x]; " \
|
|
238
|
+
"set ::_ms_y [#{@canvas} canvasy %y]; " \
|
|
239
|
+
"ruby_callback #{release_cb}}")
|
|
196
240
|
|
|
197
241
|
# Right-click: toggle flag. Binding all three events covers:
|
|
198
242
|
# Button-2 -- right-click on macOS
|
|
@@ -240,6 +284,7 @@ class Minesweeper
|
|
|
240
284
|
@app.command(@face, :configure, text: ':)')
|
|
241
285
|
|
|
242
286
|
draw_board
|
|
287
|
+
@music.play if @music_on && !@music.playing?
|
|
243
288
|
end
|
|
244
289
|
|
|
245
290
|
# Changing difficulty resizes the canvas and resets. The window auto-shrinks
|
|
@@ -285,7 +330,8 @@ class Minesweeper
|
|
|
285
330
|
|
|
286
331
|
candidates = []
|
|
287
332
|
@rows.times { |r| @cols.times { |c| candidates << [r, c] unless safe[[r, c]] } }
|
|
288
|
-
|
|
333
|
+
rng = ENV['SEED'] ? Random.new(ENV['SEED'].to_i) : Random.new
|
|
334
|
+
candidates.shuffle!(random: rng).first(@num_mines).each { |r, c| @mine[r][c] = true }
|
|
289
335
|
|
|
290
336
|
# Precompute how many mines neighbor each cell
|
|
291
337
|
@rows.times do |r|
|
|
@@ -298,7 +344,29 @@ class Minesweeper
|
|
|
298
344
|
|
|
299
345
|
# -- Click handlers ------------------------------------------------------
|
|
300
346
|
|
|
301
|
-
def
|
|
347
|
+
def on_left_press(r, c)
|
|
348
|
+
return if @game_over || @flagged[r][c] || @revealed[r][c]
|
|
349
|
+
|
|
350
|
+
# Show sunken/pressed tile and suspense face
|
|
351
|
+
@pressed_cell = [r, c]
|
|
352
|
+
set_cell_image(r, c, :empty)
|
|
353
|
+
@app.command(@face, :configure, text: ':o')
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def on_left_release(r, c)
|
|
357
|
+
prev = @pressed_cell
|
|
358
|
+
@pressed_cell = nil
|
|
359
|
+
|
|
360
|
+
# Restore face
|
|
361
|
+
@app.command(@face, :configure, text: ':)') unless @game_over
|
|
362
|
+
|
|
363
|
+
# If released on a different cell than pressed, restore the pressed cell
|
|
364
|
+
if prev && prev != [r, c]
|
|
365
|
+
pr, pc = prev
|
|
366
|
+
set_cell_image(pr, pc, :hidden) unless @revealed[pr][pc]
|
|
367
|
+
return
|
|
368
|
+
end
|
|
369
|
+
|
|
302
370
|
return if @game_over || @flagged[r][c] || @revealed[r][c]
|
|
303
371
|
|
|
304
372
|
if @first_click
|
|
@@ -308,8 +376,10 @@ class Minesweeper
|
|
|
308
376
|
end
|
|
309
377
|
|
|
310
378
|
if @mine[r][c]
|
|
379
|
+
@snd_explosion.play
|
|
311
380
|
game_over_lose(r, c)
|
|
312
381
|
else
|
|
382
|
+
@cascading = false
|
|
313
383
|
reveal(r, c)
|
|
314
384
|
check_win
|
|
315
385
|
end
|
|
@@ -318,6 +388,7 @@ class Minesweeper
|
|
|
318
388
|
def on_right_click(r, c)
|
|
319
389
|
return if @game_over || @revealed[r][c]
|
|
320
390
|
|
|
391
|
+
@snd_flag.play
|
|
321
392
|
if @flagged[r][c]
|
|
322
393
|
@flagged[r][c] = false
|
|
323
394
|
@flags_placed -= 1
|
|
@@ -344,8 +415,13 @@ class Minesweeper
|
|
|
344
415
|
|
|
345
416
|
if count == 0
|
|
346
417
|
set_cell_image(r, c, :empty)
|
|
418
|
+
unless @cascading
|
|
419
|
+
@cascading = true
|
|
420
|
+
@snd_sweep.play
|
|
421
|
+
end
|
|
347
422
|
neighbors(r, c).each { |nr, nc| reveal(nr, nc) }
|
|
348
423
|
else
|
|
424
|
+
@snd_click.play unless @cascading
|
|
349
425
|
set_cell_image(r, c, count)
|
|
350
426
|
end
|
|
351
427
|
end
|
|
@@ -375,6 +451,7 @@ class Minesweeper
|
|
|
375
451
|
@game_over = true
|
|
376
452
|
stop_timer
|
|
377
453
|
@app.command(@face, :configure, text: ':(')
|
|
454
|
+
Teek::SDL2.fade_out_music(1500) if @music_on
|
|
378
455
|
|
|
379
456
|
@rows.times do |r|
|
|
380
457
|
@cols.times do |c|
|
|
@@ -405,6 +482,24 @@ class Minesweeper
|
|
|
405
482
|
@app.after(1000) { tick_timer }
|
|
406
483
|
end
|
|
407
484
|
|
|
485
|
+
# -- Music ---------------------------------------------------------------
|
|
486
|
+
|
|
487
|
+
def toggle_music
|
|
488
|
+
if @music_on
|
|
489
|
+
@music.pause
|
|
490
|
+
@music_on = false
|
|
491
|
+
@app.command(@music_btn, :configure, text: '--')
|
|
492
|
+
else
|
|
493
|
+
if @music.paused?
|
|
494
|
+
@music.resume
|
|
495
|
+
else
|
|
496
|
+
@music.play
|
|
497
|
+
end
|
|
498
|
+
@music_on = true
|
|
499
|
+
@app.command(@music_btn, :configure, text: "\u266A")
|
|
500
|
+
end
|
|
501
|
+
end
|
|
502
|
+
|
|
408
503
|
# -- Helpers -------------------------------------------------------------
|
|
409
504
|
|
|
410
505
|
def in_bounds?(r, c)
|
|
@@ -437,16 +532,56 @@ app = Teek::App.new(track_widgets: false)
|
|
|
437
532
|
# The root window starts withdrawn by default in Teek -- show it.
|
|
438
533
|
app.show
|
|
439
534
|
|
|
440
|
-
Minesweeper.new(app)
|
|
535
|
+
game = Minesweeper.new(app)
|
|
441
536
|
|
|
442
537
|
# Automated demo support (for rake docker:test and recording)
|
|
443
538
|
require_relative '../../lib/teek/demo_support'
|
|
444
539
|
TeekDemo.app = app
|
|
445
540
|
|
|
446
|
-
if TeekDemo.
|
|
447
|
-
|
|
448
|
-
|
|
541
|
+
if TeekDemo.active?
|
|
542
|
+
ENV['SEED'] = '42'
|
|
543
|
+
game.send(:new_game) # restart with deterministic layout
|
|
544
|
+
|
|
545
|
+
if TeekDemo.recording?
|
|
546
|
+
app.set_window_geometry('+0+0')
|
|
547
|
+
app.tcl_eval('. configure -cursor none')
|
|
548
|
+
TeekDemo.signal_recording_ready
|
|
449
549
|
end
|
|
550
|
+
|
|
551
|
+
# Capture all audio output to WAV when TEEK_RECORD_AUDIO is set.
|
|
552
|
+
# The WAV can be muxed with the screen recording via ffmpeg:
|
|
553
|
+
# ffmpeg -i screen.mp4 -i yam_audio.wav -c:v copy -c:a aac -shortest out.mp4
|
|
554
|
+
audio_capture_path = ENV['TEEK_RECORD_AUDIO']
|
|
555
|
+
audio_capture_path = nil if audio_capture_path&.empty?
|
|
556
|
+
Teek::SDL2.start_audio_capture(audio_capture_path) if audio_capture_path
|
|
557
|
+
|
|
558
|
+
TeekDemo.after_idle {
|
|
559
|
+
d = TeekDemo.method(:delay)
|
|
560
|
+
|
|
561
|
+
# Click (row=2, col=3) — safe reveal, then (row=0, col=4) — mine. Boom!
|
|
562
|
+
steps = [
|
|
563
|
+
-> { game.press_cell(2, 3) },
|
|
564
|
+
-> { game.release_cell(2, 3) },
|
|
565
|
+
nil,
|
|
566
|
+
-> { game.press_cell(0, 4) },
|
|
567
|
+
-> { game.release_cell(0, 4) },
|
|
568
|
+
nil, nil,
|
|
569
|
+
-> {
|
|
570
|
+
Teek::SDL2.stop_audio_capture if audio_capture_path
|
|
571
|
+
TeekDemo.finish
|
|
572
|
+
},
|
|
573
|
+
]
|
|
574
|
+
|
|
575
|
+
i = 0
|
|
576
|
+
run_step = proc {
|
|
577
|
+
steps[i]&.call
|
|
578
|
+
i += 1
|
|
579
|
+
if i < steps.length
|
|
580
|
+
app.after(d.call(test: 50, record: 1500)) { run_step.call }
|
|
581
|
+
end
|
|
582
|
+
}
|
|
583
|
+
run_step.call
|
|
584
|
+
}
|
|
450
585
|
end
|
|
451
586
|
|
|
452
587
|
app.mainloop
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: teek
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- James Cook
|
|
@@ -124,6 +124,7 @@ files:
|
|
|
124
124
|
- ext/teek/tcl9compat.h
|
|
125
125
|
- ext/teek/tcltkbridge.c
|
|
126
126
|
- ext/teek/tcltkbridge.h
|
|
127
|
+
- ext/teek/tkeventsource.c
|
|
127
128
|
- ext/teek/tkfont.c
|
|
128
129
|
- ext/teek/tkphoto.c
|
|
129
130
|
- ext/teek/tkwin.c
|
|
@@ -134,27 +135,62 @@ files:
|
|
|
134
135
|
- lib/teek/debugger.rb
|
|
135
136
|
- lib/teek/demo_support.rb
|
|
136
137
|
- lib/teek/method_coverage_service.rb
|
|
138
|
+
- lib/teek/photo.rb
|
|
137
139
|
- lib/teek/ractor_support.rb
|
|
138
140
|
- lib/teek/version.rb
|
|
139
141
|
- lib/teek/widget.rb
|
|
140
142
|
- sample/calculator.rb
|
|
141
143
|
- sample/debug_demo.rb
|
|
144
|
+
- sample/gamepad_viewer/assets/controller.png
|
|
145
|
+
- sample/gamepad_viewer/gamepad_viewer.rb
|
|
142
146
|
- sample/goldberg.rb
|
|
143
147
|
- sample/goldberg_helpers.rb
|
|
144
|
-
- sample/
|
|
145
|
-
- sample/
|
|
146
|
-
- sample/
|
|
147
|
-
- sample/
|
|
148
|
-
- sample/
|
|
149
|
-
- sample/
|
|
150
|
-
- sample/
|
|
151
|
-
- sample/
|
|
152
|
-
- sample/
|
|
153
|
-
- sample/
|
|
154
|
-
- sample/
|
|
155
|
-
- sample/
|
|
156
|
-
- sample/
|
|
148
|
+
- sample/optcarrot.rb
|
|
149
|
+
- sample/optcarrot/thwaite.nes
|
|
150
|
+
- sample/optcarrot/vendor/optcarrot.rb
|
|
151
|
+
- sample/optcarrot/vendor/optcarrot/apu.rb
|
|
152
|
+
- sample/optcarrot/vendor/optcarrot/config.rb
|
|
153
|
+
- sample/optcarrot/vendor/optcarrot/cpu.rb
|
|
154
|
+
- sample/optcarrot/vendor/optcarrot/driver.rb
|
|
155
|
+
- sample/optcarrot/vendor/optcarrot/mapper/cnrom.rb
|
|
156
|
+
- sample/optcarrot/vendor/optcarrot/mapper/mmc1.rb
|
|
157
|
+
- sample/optcarrot/vendor/optcarrot/mapper/mmc3.rb
|
|
158
|
+
- sample/optcarrot/vendor/optcarrot/mapper/uxrom.rb
|
|
159
|
+
- sample/optcarrot/vendor/optcarrot/nes.rb
|
|
160
|
+
- sample/optcarrot/vendor/optcarrot/opt.rb
|
|
161
|
+
- sample/optcarrot/vendor/optcarrot/pad.rb
|
|
162
|
+
- sample/optcarrot/vendor/optcarrot/palette.rb
|
|
163
|
+
- sample/optcarrot/vendor/optcarrot/ppu.rb
|
|
164
|
+
- sample/optcarrot/vendor/optcarrot/rom.rb
|
|
165
|
+
- sample/paint/assets/bucket.png
|
|
166
|
+
- sample/paint/assets/cursor.png
|
|
167
|
+
- sample/paint/assets/eraser.png
|
|
168
|
+
- sample/paint/assets/pencil.png
|
|
169
|
+
- sample/paint/assets/spray.png
|
|
170
|
+
- sample/paint/layer.rb
|
|
171
|
+
- sample/paint/layer_manager.rb
|
|
172
|
+
- sample/paint/paint_demo.rb
|
|
173
|
+
- sample/paint/sparse_pixel_buffer.rb
|
|
174
|
+
- sample/sdl2_demo.rb
|
|
157
175
|
- sample/threading_demo.rb
|
|
176
|
+
- sample/yam/assets/MINESWEEPER_0.png
|
|
177
|
+
- sample/yam/assets/MINESWEEPER_1.png
|
|
178
|
+
- sample/yam/assets/MINESWEEPER_2.png
|
|
179
|
+
- sample/yam/assets/MINESWEEPER_3.png
|
|
180
|
+
- sample/yam/assets/MINESWEEPER_4.png
|
|
181
|
+
- sample/yam/assets/MINESWEEPER_5.png
|
|
182
|
+
- sample/yam/assets/MINESWEEPER_6.png
|
|
183
|
+
- sample/yam/assets/MINESWEEPER_7.png
|
|
184
|
+
- sample/yam/assets/MINESWEEPER_8.png
|
|
185
|
+
- sample/yam/assets/MINESWEEPER_F.png
|
|
186
|
+
- sample/yam/assets/MINESWEEPER_M.png
|
|
187
|
+
- sample/yam/assets/MINESWEEPER_X.png
|
|
188
|
+
- sample/yam/assets/click.wav
|
|
189
|
+
- sample/yam/assets/explosion.wav
|
|
190
|
+
- sample/yam/assets/flag.wav
|
|
191
|
+
- sample/yam/assets/music.mp3
|
|
192
|
+
- sample/yam/assets/sweep.wav
|
|
193
|
+
- sample/yam/yam.rb
|
|
158
194
|
- teek.gemspec
|
|
159
195
|
homepage: https://github.com/jamescook/teek
|
|
160
196
|
licenses:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|