shoes 4.0.0.pre2 → 4.0.0.pre3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (311) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +32 -21
  3. metadata +18 -337
  4. data/CHANGELOG +0 -84
  5. data/Gemfile +0 -24
  6. data/Guardfile +0 -11
  7. data/Rakefile +0 -14
  8. data/app.yaml +0 -60
  9. data/benchmark/app_clear.rb +0 -21
  10. data/benchmark/clear.rb +0 -69
  11. data/benchmark/memory/text_dispose.rb +0 -9
  12. data/benchmark/para_creator.rb +0 -9
  13. data/benchmark/paras.rb +0 -52
  14. data/benchmark/urls.rb +0 -40
  15. data/bin/ruby-shoes +0 -6
  16. data/bin/shoes-guard +0 -8
  17. data/bin/shoes-stub +0 -59
  18. data/ext/install/Rakefile +0 -29
  19. data/ext/install/shoes.bat +0 -9
  20. data/lib/shoes.rb +0 -5
  21. data/lib/shoes/ui/cli.rb +0 -102
  22. data/lib/shoes/ui/help.rb +0 -535
  23. data/lib/shoes/ui/manual.rb +0 -6
  24. data/lib/shoes/version.rb +0 -3
  25. data/manifests/common.rb +0 -34
  26. data/manifests/shoes.rb +0 -44
  27. data/samples/Gemfile +0 -3
  28. data/samples/Gemfile.lock +0 -35
  29. data/samples/README +0 -97
  30. data/samples/boom.rb +0 -239
  31. data/samples/class-book-adjusted.rb +0 -45
  32. data/samples/class-book.rb +0 -43
  33. data/samples/class-book.yaml +0 -387
  34. data/samples/clicky.rb +0 -24
  35. data/samples/cy.png +0 -0
  36. data/samples/expert-definr.rb +0 -23
  37. data/samples/expert-funnies.rb +0 -60
  38. data/samples/expert-game-of-life-adjusted.rb +0 -249
  39. data/samples/expert-game-of-life.rb +0 -243
  40. data/samples/expert-irb-adjusted.rb +0 -110
  41. data/samples/expert-irb.rb +0 -112
  42. data/samples/expert-minesweeper-adjusted.rb +0 -272
  43. data/samples/expert-minesweeper.rb +0 -267
  44. data/samples/expert-othello-adjusted.rb +0 -325
  45. data/samples/expert-othello.rb +0 -318
  46. data/samples/expert-pong.rb +0 -62
  47. data/samples/expert-snake.rb +0 -78
  48. data/samples/expert-tankspank.rb +0 -385
  49. data/samples/flow.rb +0 -63
  50. data/samples/good-arc.rb +0 -45
  51. data/samples/good-clock.rb +0 -51
  52. data/samples/good-displace.rb +0 -98
  53. data/samples/good-follow.rb +0 -26
  54. data/samples/good-potato-chopping.rb +0 -22
  55. data/samples/good-reminder.rb +0 -174
  56. data/samples/good-vjot.rb +0 -58
  57. data/samples/gray.rb +0 -11
  58. data/samples/loogink.png +0 -0
  59. data/samples/nks_booklist.rb +0 -24
  60. data/samples/nks_breadsticks.rb +0 -7
  61. data/samples/nks_dancing_circle.rb +0 -13
  62. data/samples/nks_dictionary.rb +0 -23
  63. data/samples/nks_edit_box.rb +0 -4
  64. data/samples/nks_edit_line.rb +0 -6
  65. data/samples/nks_notes.rb +0 -16
  66. data/samples/nks_poem.rb +0 -22
  67. data/samples/nks_self.rb +0 -6
  68. data/samples/nks_text_sizes.rb +0 -10
  69. data/samples/nks_trurl.rb +0 -5
  70. data/samples/original-manual-adjusted.rb +0 -475
  71. data/samples/original-manual.rb +0 -472
  72. data/samples/packaging/package_me.rb +0 -6
  73. data/samples/potato_chopping/1258_s001.gif +0 -0
  74. data/samples/potato_chopping/1258_s002.gif +0 -0
  75. data/samples/potato_chopping/1258_s003.gif +0 -0
  76. data/samples/potato_chopping/1258_s004.gif +0 -0
  77. data/samples/potato_chopping/1258_s005.gif +0 -0
  78. data/samples/potato_chopping/1258_s006.gif +0 -0
  79. data/samples/potato_chopping/1258_s007.gif +0 -0
  80. data/samples/potato_chopping/1258_s008.gif +0 -0
  81. data/samples/potato_chopping/1258_s009.gif +0 -0
  82. data/samples/potato_chopping/1258_s010.gif +0 -0
  83. data/samples/potato_chopping/1258_s011.gif +0 -0
  84. data/samples/potato_chopping/1258_s012.gif +0 -0
  85. data/samples/potato_chopping/1258_s013.gif +0 -0
  86. data/samples/potato_chopping/1258_s014.gif +0 -0
  87. data/samples/potato_chopping/1258_s015.gif +0 -0
  88. data/samples/potato_chopping/1258_s016.gif +0 -0
  89. data/samples/potato_chopping/1258_s017.gif +0 -0
  90. data/samples/potato_chopping/1258_s018.gif +0 -0
  91. data/samples/potato_chopping/1258_s019.gif +0 -0
  92. data/samples/potato_chopping/1258_s020.gif +0 -0
  93. data/samples/potato_chopping/1258_s021.gif +0 -0
  94. data/samples/potato_chopping/1258_s022.gif +0 -0
  95. data/samples/potato_chopping/1258_s023.gif +0 -0
  96. data/samples/potato_chopping/1258_s024.gif +0 -0
  97. data/samples/potato_chopping/1258_s025.gif +0 -0
  98. data/samples/potato_chopping/1258_s026.gif +0 -0
  99. data/samples/potato_chopping/1258_s027.gif +0 -0
  100. data/samples/potato_chopping/1258_s028.gif +0 -0
  101. data/samples/potato_chopping/1258_s029.gif +0 -0
  102. data/samples/potato_chopping/1258_s030.gif +0 -0
  103. data/samples/potato_chopping/1258_s031.gif +0 -0
  104. data/samples/potato_chopping/1258_s032.gif +0 -0
  105. data/samples/potato_chopping/1258_s033.gif +0 -0
  106. data/samples/potato_chopping/1258_s034.gif +0 -0
  107. data/samples/potato_chopping/1258_s035.gif +0 -0
  108. data/samples/potato_chopping/1258_s036.gif +0 -0
  109. data/samples/potato_chopping/1258_s037.gif +0 -0
  110. data/samples/potato_chopping/1258_s038.gif +0 -0
  111. data/samples/potato_chopping/1258_s039.gif +0 -0
  112. data/samples/potato_chopping/1258_s040.gif +0 -0
  113. data/samples/potato_chopping/1258_s041.gif +0 -0
  114. data/samples/potato_chopping/1258_s042.gif +0 -0
  115. data/samples/potato_chopping/1258_s043.gif +0 -0
  116. data/samples/potato_chopping/1258_s044.gif +0 -0
  117. data/samples/potato_chopping/1258_s045.gif +0 -0
  118. data/samples/potato_chopping/1258_s046.gif +0 -0
  119. data/samples/potato_chopping/1258_s047.gif +0 -0
  120. data/samples/potato_chopping/1258_s048.gif +0 -0
  121. data/samples/potato_chopping/1258_s049.gif +0 -0
  122. data/samples/potato_chopping/1258_s050.gif +0 -0
  123. data/samples/potato_chopping/1258_s051.gif +0 -0
  124. data/samples/potato_chopping/1258_s052.gif +0 -0
  125. data/samples/potato_chopping/1258_s053.gif +0 -0
  126. data/samples/potato_chopping/1258_s054.gif +0 -0
  127. data/samples/potato_chopping/1258_s055.gif +0 -0
  128. data/samples/potato_chopping/1258_s056.gif +0 -0
  129. data/samples/potato_chopping/1258_s057.gif +0 -0
  130. data/samples/potato_chopping/1258_s058.gif +0 -0
  131. data/samples/potato_chopping/1258_s059.gif +0 -0
  132. data/samples/present.rb +0 -27
  133. data/samples/progress.rb +0 -10
  134. data/samples/sample1.rb +0 -30
  135. data/samples/sample12.rb +0 -21
  136. data/samples/sample13.rb +0 -13
  137. data/samples/sample14.rb +0 -64
  138. data/samples/sample15.rb +0 -18
  139. data/samples/sample16.rb +0 -10
  140. data/samples/sample17.rb +0 -10
  141. data/samples/sample2.rb +0 -14
  142. data/samples/sample21.rb +0 -5
  143. data/samples/sample23.rb +0 -8
  144. data/samples/sample24.rb +0 -21
  145. data/samples/sample27.rb +0 -18
  146. data/samples/sample3.rb +0 -14
  147. data/samples/sample31.rb +0 -22
  148. data/samples/sample34.rb +0 -27
  149. data/samples/sample35.rb +0 -32
  150. data/samples/sample37.rb +0 -8
  151. data/samples/sample4.rb +0 -7
  152. data/samples/sample42.rb +0 -14
  153. data/samples/sample45.rb +0 -11
  154. data/samples/sample56.rb +0 -10
  155. data/samples/sample6.rb +0 -9
  156. data/samples/sample7.rb +0 -3
  157. data/samples/sample8.rb +0 -7
  158. data/samples/sample9.rb +0 -10
  159. data/samples/simple-accordion.rb +0 -75
  160. data/samples/simple-anim-shapes.rb +0 -17
  161. data/samples/simple-anim-text.rb +0 -13
  162. data/samples/simple-animate.rb +0 -12
  163. data/samples/simple-arc.rb +0 -23
  164. data/samples/simple-bounce.rb +0 -24
  165. data/samples/simple-brightness-transitions.rb +0 -8
  166. data/samples/simple-button-animate.rb +0 -16
  167. data/samples/simple-calc-2.rb +0 -34
  168. data/samples/simple-calc.rb +0 -70
  169. data/samples/simple-color-selector.rb +0 -10
  170. data/samples/simple-color-transitions.rb +0 -11
  171. data/samples/simple-control-sizes.rb +0 -24
  172. data/samples/simple-curve.rb +0 -26
  173. data/samples/simple-dialogs-outside.rb +0 -12
  174. data/samples/simple-dialogs.rb +0 -32
  175. data/samples/simple-displace.rb +0 -15
  176. data/samples/simple-downloader.rb +0 -27
  177. data/samples/simple-draw.rb +0 -13
  178. data/samples/simple-editor.rb +0 -28
  179. data/samples/simple-face.rb +0 -14
  180. data/samples/simple-flow-wrap.rb +0 -11
  181. data/samples/simple-font.rb +0 -17
  182. data/samples/simple-form.rb +0 -29
  183. data/samples/simple-form.shy +0 -0
  184. data/samples/simple-fullscreen.rb +0 -4
  185. data/samples/simple-guess-game.rb +0 -28
  186. data/samples/simple-keypress.rb +0 -14
  187. data/samples/simple-manual.rb +0 -2
  188. data/samples/simple-mask.rb +0 -21
  189. data/samples/simple-menu.rb +0 -47
  190. data/samples/simple-mouse-follow.rb +0 -8
  191. data/samples/simple-move.rb +0 -13
  192. data/samples/simple-oval.rb +0 -3
  193. data/samples/simple-sample-executor.rb +0 -6
  194. data/samples/simple-shoes-intro.rb +0 -22
  195. data/samples/simple-slide.rb +0 -56
  196. data/samples/simple-sound.rb +0 -30
  197. data/samples/simple-sphere.rb +0 -28
  198. data/samples/simple-stripes.rb +0 -8
  199. data/samples/simple-tictactoe.rb +0 -238
  200. data/samples/simple-timer.rb +0 -15
  201. data/samples/simple-video.rb +0 -13
  202. data/samples/simple-visibility.rb +0 -11
  203. data/samples/simple-widget.rb +0 -9
  204. data/samples/sounds/102719__sarge4267__explosion.mp3 +0 -0
  205. data/samples/sounds/145622__andybrannan__train-fog-horn-long-wyomming.aiff +0 -0
  206. data/samples/sounds/46492__phreaksaccount__shields1.ogg +0 -0
  207. data/samples/sounds/61847__simon-rue__boink-v3.wav +0 -0
  208. data/samples/swt-raw.rb +0 -20
  209. data/samples/troll.rb +0 -22
  210. data/shoes.gemspec +0 -29
  211. data/snapshots/sample1.png +0 -0
  212. data/snapshots/sample10.png +0 -0
  213. data/snapshots/sample11.png +0 -0
  214. data/snapshots/sample12.png +0 -0
  215. data/snapshots/sample13.png +0 -0
  216. data/snapshots/sample14.png +0 -0
  217. data/snapshots/sample15.png +0 -0
  218. data/snapshots/sample16.png +0 -0
  219. data/snapshots/sample17.png +0 -0
  220. data/snapshots/sample18.png +0 -0
  221. data/snapshots/sample19.png +0 -0
  222. data/snapshots/sample2.png +0 -0
  223. data/snapshots/sample20.png +0 -0
  224. data/snapshots/sample21.png +0 -0
  225. data/snapshots/sample22.png +0 -0
  226. data/snapshots/sample23.png +0 -0
  227. data/snapshots/sample24.png +0 -0
  228. data/snapshots/sample27.png +0 -0
  229. data/snapshots/sample28.png +0 -0
  230. data/snapshots/sample29.png +0 -0
  231. data/snapshots/sample3.png +0 -0
  232. data/snapshots/sample30.png +0 -0
  233. data/snapshots/sample31.png +0 -0
  234. data/snapshots/sample34.png +0 -0
  235. data/snapshots/sample35.png +0 -0
  236. data/snapshots/sample36.png +0 -0
  237. data/snapshots/sample37.png +0 -0
  238. data/snapshots/sample4.png +0 -0
  239. data/snapshots/sample42.png +0 -0
  240. data/snapshots/sample44.png +0 -0
  241. data/snapshots/sample45.png +0 -0
  242. data/snapshots/sample46.png +0 -0
  243. data/snapshots/sample5.png +0 -0
  244. data/snapshots/sample56.png +0 -0
  245. data/snapshots/sample6.png +0 -0
  246. data/snapshots/sample7.png +0 -0
  247. data/snapshots/sample8.png +0 -0
  248. data/snapshots/sample9.png +0 -0
  249. data/snapshots/sample99.png +0 -0
  250. data/static/PKGBUILD +0 -47
  251. data/static/Shoes.icns +0 -0
  252. data/static/avatar.png +0 -0
  253. data/static/code_highlighter.js +0 -188
  254. data/static/code_highlighter_ruby.js +0 -26
  255. data/static/downloading.png +0 -0
  256. data/static/icon-debug.png +0 -0
  257. data/static/icon-error.png +0 -0
  258. data/static/icon-info.png +0 -0
  259. data/static/icon-warn.png +0 -0
  260. data/static/listbox_button1.png +0 -0
  261. data/static/listbox_button2.png +0 -0
  262. data/static/man-app.png +0 -0
  263. data/static/man-builds.png +0 -0
  264. data/static/man-builds1.png +0 -0
  265. data/static/man-editor-notepad.png +0 -0
  266. data/static/man-editor-osx.png +0 -0
  267. data/static/man-ele-background.png +0 -0
  268. data/static/man-ele-border.png +0 -0
  269. data/static/man-ele-button.png +0 -0
  270. data/static/man-ele-check.png +0 -0
  271. data/static/man-ele-editbox.png +0 -0
  272. data/static/man-ele-editline.png +0 -0
  273. data/static/man-ele-image.png +0 -0
  274. data/static/man-ele-listbox.png +0 -0
  275. data/static/man-ele-progress.png +0 -0
  276. data/static/man-ele-radio.png +0 -0
  277. data/static/man-ele-shape.png +0 -0
  278. data/static/man-ele-textblock.png +0 -0
  279. data/static/man-ele-video.png +0 -0
  280. data/static/man-intro-dmg.png +0 -0
  281. data/static/man-intro-exe.png +0 -0
  282. data/static/man-look-tiger.png +0 -0
  283. data/static/man-look-ubuntu.png +0 -0
  284. data/static/man-look-vista.png +0 -0
  285. data/static/man-run-osx.png +0 -0
  286. data/static/man-run-vista.png +0 -0
  287. data/static/man-run-xp.png +0 -0
  288. data/static/man-shot1.png +0 -0
  289. data/static/manual-en.txt +0 -3531
  290. data/static/manual-ja.txt +0 -2829
  291. data/static/manual.css +0 -184
  292. data/static/menu-corner1.png +0 -0
  293. data/static/menu-corner2.png +0 -0
  294. data/static/menu-gray.png +0 -0
  295. data/static/menu-left.png +0 -0
  296. data/static/menu-right.png +0 -0
  297. data/static/menu-top.png +0 -0
  298. data/static/shoes-dmg.jpg +0 -0
  299. data/static/shoes-icon-blue.png +0 -0
  300. data/static/shoes-icon-brown.png +0 -0
  301. data/static/shoes-icon.png +0 -0
  302. data/static/shoes-manual-apps.gif +0 -0
  303. data/static/shoes-manual-apps.png +0 -0
  304. data/static/shoes_main_window.png +0 -0
  305. data/static/stripe.png +0 -0
  306. data/static/tutor-back.png +0 -0
  307. data/tasks/changelog.rb +0 -92
  308. data/tasks/gem.rb +0 -38
  309. data/tasks/rspec.rb +0 -106
  310. data/tasks/sample.rb +0 -66
  311. data/tasks/yard.rb +0 -13
@@ -1,110 +0,0 @@
1
- require 'irb/ruby-lex'
2
- require 'stringio'
3
-
4
- class MimickIRB < RubyLex
5
- attr_accessor :started
6
-
7
- class Continue < StandardError; end
8
- class Empty < StandardError; end
9
-
10
- def initialize
11
- super
12
- set_input(StringIO.new)
13
- end
14
-
15
- def run(str)
16
- obj = nil
17
- @io << str
18
- @io.rewind
19
- unless l = lex
20
- raise Empty if @line == ''
21
- else
22
- case l.strip
23
- when "reset"
24
- @line = ""
25
- when "time"
26
- @line = "puts %{You started \#{IRBalike.started.since} ago.}"
27
- else
28
- @line << l << "\n"
29
- if @ltype or @continue or @indent > 0
30
- raise Continue
31
- end
32
- end
33
- end
34
- unless @line.empty?
35
- obj = eval @line, TOPLEVEL_BINDING, "(irb)", @line_no
36
- end
37
- @line_no += @line.scan(/\n/).length
38
- @line = ''
39
- @exp_line_no = @line_no
40
-
41
- @indent = 0
42
- @indent_stack = []
43
-
44
- $stdout.rewind
45
- output = $stdout.read
46
- $stdout.truncate(0)
47
- $stdout.rewind
48
- [output, obj]
49
- rescue Object => e
50
- case e when Empty, Continue
51
- else @line = ""
52
- end
53
- raise e
54
- ensure
55
- set_input(StringIO.new)
56
- end
57
-
58
- end
59
-
60
- CURSOR = ">>"
61
- IRBalike = MimickIRB.new
62
- $stdout = StringIO.new
63
-
64
- Shoes.app do
65
- @str, @cmd = [CURSOR + " "], ""
66
- background "#555"
67
- @scroll = stack do
68
- background "#555"
69
- stack width: 1.0, height: 50 do
70
- para "Interactive Ruby ready.", fill: white, stroke: red
71
- end
72
- @console = para *@str, font: "Lucida Console", stroke: "#dfa"
73
- @console.cursor = -1
74
- end
75
- keypress do |k|
76
- case k
77
- when "\n"
78
- begin
79
- out, obj = IRBalike.run(@cmd + ';')
80
- @str += ["#@cmd\n",
81
- fg("#{out}=> #{obj.inspect}\n", "#fda"),
82
- "#{CURSOR} "]
83
- @cmd = ""
84
- rescue MimickIRB::Empty
85
- rescue MimickIRB::Continue
86
- @str += ["#@cmd\n.. "]
87
- @cmd = ""
88
- rescue Object => e
89
- @str += ["#@cmd\n", fg("#{e.class}: #{e.message}\n", "#fcf"),
90
- "#{CURSOR} "]
91
- @cmd = ""
92
- end
93
- when String
94
- @cmd += k
95
- when :backspace
96
- @cmd.slice!(-1)
97
- when :tab
98
- @cmd += " "
99
- when :alt_q
100
- exit
101
- when :alt_c
102
- self.clipboard = @cmd
103
- when :alt_v
104
- @cmd += self.clipboard
105
- end
106
- @console.replace *(@str + [@cmd])
107
- tmp = @scroll.height - app.height
108
- @scroll.scroll_top = tmp > 0 ? tmp : 0
109
- end
110
- end
@@ -1,112 +0,0 @@
1
- require 'irb/ruby-lex'
2
- require 'stringio'
3
-
4
- class MimickIRB < RubyLex
5
- attr_accessor :started
6
-
7
- class Continue < StandardError; end
8
- class Empty < StandardError; end
9
-
10
- def initialize
11
- super
12
- set_input(StringIO.new)
13
- end
14
-
15
- def run(str)
16
- obj = nil
17
- @io << str
18
- @io.rewind
19
- unless l = lex
20
- raise Empty if @line == ''
21
- else
22
- case l.strip
23
- when "reset"
24
- @line = ""
25
- when "time"
26
- @line = "puts %{You started \#{IRBalike.started.since} ago.}"
27
- else
28
- @line << l << "\n"
29
- if @ltype or @continue or @indent > 0
30
- raise Continue
31
- end
32
- end
33
- end
34
- unless @line.empty?
35
- obj = eval @line, TOPLEVEL_BINDING, "(irb)", @line_no
36
- end
37
- @line_no += @line.scan(/\n/).length
38
- @line = ''
39
- @exp_line_no = @line_no
40
-
41
- @indent = 0
42
- @indent_stack = []
43
-
44
- $stdout.rewind
45
- output = $stdout.read
46
- $stdout.truncate(0)
47
- $stdout.rewind
48
- [output, obj]
49
- rescue Object => e
50
- case e when Empty, Continue
51
- else @line = ""
52
- end
53
- raise e
54
- ensure
55
- set_input(StringIO.new)
56
- end
57
-
58
- end
59
-
60
- CURSOR = ">>"
61
- IRBalike = MimickIRB.new
62
- $stdout = StringIO.new
63
-
64
- Shoes.app do
65
- @str, @cmd = [CURSOR + " "], ""
66
- stack width: 1.0, height: 1.0 do
67
- background "#555"
68
- stack width: 1.0, height: 50 do
69
- para "Interactive Ruby ready.", fill: white, stroke: red
70
- end
71
- @scroll =
72
- stack width: 1.0, height: -50, scroll: true do
73
- background "#555"
74
- @console = para @str, font: "Monospace 12px", stroke: "#dfa"
75
- @console.cursor = -1
76
- end
77
- end
78
- keypress do |k|
79
- case k
80
- when "\n"
81
- begin
82
- out, obj = IRBalike.run(@cmd + ';')
83
- @str += ["#@cmd\n",
84
- span("#{out}=> #{obj.inspect}\n", stroke: "#fda"),
85
- "#{CURSOR} "]
86
- @cmd = ""
87
- rescue MimickIRB::Empty
88
- rescue MimickIRB::Continue
89
- @str += ["#@cmd\n.. "]
90
- @cmd = ""
91
- rescue Object => e
92
- @str += ["#@cmd\n", span("#{e.class}: #{e.message}\n", stroke: "#fcf"),
93
- "#{CURSOR} "]
94
- @cmd = ""
95
- end
96
- when String
97
- @cmd += k
98
- when :backspace
99
- @cmd.slice!(-1)
100
- when :tab
101
- @cmd += " "
102
- when :alt_q
103
- quit
104
- when :alt_c
105
- self.clipboard = @cmd
106
- when :alt_v
107
- @cmd += self.clipboard
108
- end
109
- @console.replace *(@str + [@cmd])
110
- @scroll.scroll_top = @scroll.scroll_max
111
- end
112
- end
@@ -1,272 +0,0 @@
1
- #
2
- # Shoes Minesweeper by que/varyform
3
- #
4
- LEVELS = { beginner: [9, 9, 10], intermediate: [16, 16, 40], expert: [30, 16, 99] }
5
-
6
- class Field
7
- CELL_SIZE = 20
8
- COLORS = %w(#00A #0A0 #A00 #004 #040 #400 #000)
9
-
10
- class Cell
11
- attr_accessor :flag
12
- def initialize(aflag = false)
13
- @flag = aflag
14
- end
15
- end
16
-
17
- class Bomb < Cell
18
- attr_accessor :exploded
19
- def initialize(exploded = false)
20
- @exploded = exploded
21
- end
22
- end
23
-
24
- class OpenCell < Cell
25
- attr_accessor :number
26
- def initialize(bombs_around = 0)
27
- @number = bombs_around
28
- end
29
- end
30
-
31
- class EmptyCell < Cell; end
32
-
33
- attr_reader :cell_size, :offset
34
-
35
- def initialize(app, level = :beginner)
36
- @app = app
37
- @field = []
38
- @w, @h, @bombs = LEVELS[level][0], LEVELS[level][1], LEVELS[level][2]
39
- @h.times { @field << Array.new(@w) { EmptyCell.new } }
40
- @game_over = false
41
- @width, @height, @cell_size = @w * CELL_SIZE, @h * CELL_SIZE, CELL_SIZE
42
- @offset = [(@app.width - @width.to_i) / 2, (@app.height - @height.to_i) / 2]
43
- plant_bombs
44
- @start_time = Time.now
45
- end
46
-
47
- def total_time
48
- @latest_time = Time.now - @start_time unless game_over? || all_found?
49
- @latest_time
50
- end
51
-
52
- def click!(x, y)
53
- return unless cell_exists?(x, y)
54
- return if has_flag?(x, y)
55
- return die!(x, y) if bomb?(x, y)
56
- open(x, y)
57
- discover(x, y) if bombs_around(x, y) == 0
58
- end
59
-
60
- def flag!(x, y)
61
- return unless cell_exists?(x, y)
62
- self[x, y].flag = !self[x, y].flag unless self[x, y].is_a?(OpenCell)
63
- end
64
-
65
- def game_over?
66
- @game_over
67
- end
68
-
69
- def render_cell(x, y, color = "#AAA", stroke = true)
70
- @app.stroke "#666" if stroke
71
- @app.fill color
72
- @app.rect $x+x*cell_size, $y+y*cell_size, cell_size-1, cell_size-1
73
- @app.stroke "#BBB" if stroke
74
- @app.line $x+x*cell_size+1, $y+y*cell_size+1, $x+x*cell_size+cell_size-1, $y+y*cell_size
75
- @app.line $x+x*cell_size+1, $y+y*cell_size+1, $x+x*cell_size, $y+y*cell_size+cell_size-1
76
- end
77
-
78
- def render_flag(x, y)
79
- @app.stroke "#000"
80
- @app.line($x+x*cell_size+cell_size / 4 + 1, $y+y*cell_size + cell_size / 5, $x+x*cell_size+cell_size / 4 + 1, $y+y*cell_size+cell_size / 5 * 4)
81
- @app.fill "#A00"
82
- @app.rect($x+x*cell_size+cell_size / 4+2, $y+y*cell_size + cell_size / 5,
83
- cell_size / 3, cell_size / 4)
84
- end
85
-
86
- def render_bomb(x, y)
87
- render_cell(x, y)
88
- if (game_over? or all_found?) then # draw bomb
89
- if self[x, y].exploded then
90
- render_cell(x, y, @app.rgb(0xFF, 0, 0, 0.5))
91
- end
92
- @app.nostroke
93
- @app.fill @app.rgb(0, 0, 0, 0.8)
94
- @app.oval($x+x*cell_size+3, $y+y*cell_size+3, 13)
95
- @app.fill "#333"
96
- @app.oval($x+x*cell_size+5, $y+y*cell_size+5, 7)
97
- @app.fill "#AAA"
98
- @app.oval($x+x*cell_size+6, $y+y*cell_size+6, 3)
99
- @app.fill @app.rgb(0, 0, 0, 0.8)
100
- @app.stroke "#222"
101
- @app.strokewidth 2
102
- @app.oval($x+x*cell_size + cell_size / 2 + 2, $y+y*cell_size + cell_size / 4 - 2, 2)
103
- @app.oval($x+x*cell_size + cell_size / 2 + 4, $y+y*cell_size + cell_size / 4 - 2, 1)
104
- @app.strokewidth 1
105
- end
106
- end
107
-
108
- def render_number(x, y)
109
- render_cell(x, y, "#999", false)
110
- if self[x, y].number != 0 then
111
- @app.nostroke
112
- @app.nofill
113
- @app.oval($x+x*cell_size + 3, $y+y*cell_size - 2, 10)
114
- @app.para self[x, y].number.to_s, left: $x+x*cell_size + 3, top: $y+y*cell_size - 2,
115
- size: 13, stroke: COLORS[self[x, y].number - 1]
116
- end
117
- end
118
-
119
- def paint
120
- 0.upto @h-1 do |y|
121
- 0.upto @w-1 do |x|
122
- @app.nostroke
123
- case self[x, y]
124
- when EmptyCell then render_cell(x, y)
125
- when Bomb then render_bomb(x, y)
126
- when OpenCell then render_number(x, y)
127
- end
128
- render_flag(x, y) if has_flag?(x, y) && !(game_over? && bomb?(x, y))
129
- end
130
- end
131
- end
132
-
133
- def bombs_left
134
- @bombs - @field.flatten.compact.reject {|e| !e.flag }.size
135
- end
136
-
137
- def all_found?
138
- @field.flatten.compact.reject {|e| !e.is_a?(OpenCell) }.size + @bombs == @w*@h
139
- end
140
-
141
- def reveal!(x, y)
142
- return unless cell_exists?(x, y)
143
- return unless self[x, y].is_a?(Field::OpenCell)
144
- if flags_around(x, y) >= self[x, y].number then
145
- (-1..1).each do |v|
146
- (-1..1).each { |h| click!(x+h, y+v) unless (v==0 && h==0) or has_flag?(x+h, y+v) }
147
- end
148
- end
149
- end
150
-
151
- private
152
-
153
- def cell_exists?(x, y)
154
- ((0...@w).include? x) && ((0...@h).include? y)
155
- end
156
-
157
- def has_flag?(x, y)
158
- return false unless cell_exists?(x, y)
159
- return self[x, y].flag
160
- end
161
-
162
- def bomb?(x, y)
163
- cell_exists?(x, y) && (self[x, y].is_a? Bomb)
164
- end
165
-
166
- def can_be_discovered?(x, y)
167
- return false unless cell_exists?(x, y)
168
- return false if self[x, y].flag
169
- cell_exists?(x, y) && (self[x, y].is_a? EmptyCell) && !bomb?(x, y) && (bombs_around(x, y) == 0)
170
- end
171
-
172
- def open(x, y)
173
- self[x, y] = OpenCell.new(bombs_around(x, y)) unless (self[x, y].is_a? OpenCell) or has_flag?(x, y)
174
- end
175
-
176
- def neighbors
177
- (-1..1).each do |col|
178
- (-1..1).each { |row| yield row, col unless col==0 && row == 0 }
179
- end
180
- end
181
-
182
- def discover(x, y)
183
- open(x, y)
184
- neighbors do |col, row|
185
- cx, cy = x+row, y+col
186
- next unless cell_exists?(cx, cy)
187
- discover(cx, cy) if can_be_discovered?(cx, cy)
188
- open(cx, cy)
189
- end
190
- end
191
-
192
- def count_neighbors
193
- return 0 unless block_given?
194
- count = 0
195
- neighbors { |h, v| count += 1 if yield(h, v) }
196
- count
197
- end
198
-
199
- def bombs_around(x, y)
200
- count_neighbors { |v, h| bomb?(x+h, y+v) }
201
- end
202
-
203
- def flags_around(x, y)
204
- count_neighbors { |v, h| has_flag?(x+h, y+v) }
205
- end
206
-
207
- def die!(x, y)
208
- self[x, y].exploded = true
209
- @game_over = true
210
- end
211
-
212
- def plant_bomb(x, y)
213
- self[x, y].is_a?(EmptyCell) ? self[x, y] = Bomb.new : false
214
- end
215
-
216
- def plant_bombs
217
- @bombs.times { redo unless plant_bomb(rand(@w), rand(@h)) }
218
- end
219
-
220
- def [](*args)
221
- x, y = args
222
- raise "Cell #{x}:#{y} does not exists!" unless cell_exists?(x, y)
223
- @field[y][x]
224
- end
225
-
226
- def []=(*args)
227
- x, y, v = args
228
- cell_exists?(x, y) ? @field[y][x] = v : false
229
- end
230
- end
231
-
232
- Shoes.app width: 730, height: 450, title: 'Minesweeper' do
233
- def render_field
234
- clear do
235
- background rgb(50, 50, 90, 0.7)
236
- flow margin: 4 do
237
- flow do
238
- button("Beginner") { new_game :beginner }
239
- button("Intermediate") { new_game :intermediate }
240
- button("Expert") { new_game :expert }
241
- end
242
- end
243
- stack do @status = para stroke: white end
244
- @field.paint
245
- para "Left click - open cell, right click - put flag, middle click - reveal empty cells", top: 420, left: 0, stroke: white, size: 11
246
- end
247
- end
248
-
249
- def new_game level
250
- @field = Field.new self, level
251
- #translate -@old_offset.first, -@old_offset.last unless @old_offset.nil?
252
- #translate @field.offset.first, @field.offset.last
253
- #@old_offset = @field.offset
254
- $x, $y = @field.offset.first, @field.offset.last
255
- render_field
256
- end
257
-
258
- new_game :beginner
259
- every { @status.replace "Time: #{@field.total_time.to_i} Bombs left: #{@field.bombs_left}" }
260
-
261
- click do |button, x, y|
262
- next if @field.game_over? || @field.all_found?
263
- fx, fy = ((x-@field.offset.first) / @field.cell_size).to_i, ((y-@field.offset.last) / @field.cell_size).to_i
264
- @field.click!(fx, fy) if button == 1
265
- @field.reveal!(fx, fy) if button == 2
266
- @field.flag!(fx, fy) if button == 3
267
-
268
- render_field
269
- alert("Winner!\nTotal time: #{@field.total_time}") if @field.all_found?
270
- alert("Bang!\nYou loose.") if @field.game_over?
271
- end
272
- end