shoes 3.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.
- data/.gitignore +12 -0
- data/CHANGELOG +29 -0
- data/COPYING +30 -0
- data/README.md +76 -0
- data/README.old +117 -0
- data/Rakefile +130 -0
- data/Rakefile.bk +651 -0
- data/app.yaml +7 -0
- data/bin/main.skel +104 -0
- data/bugs/issue-012e9468ddc7b0cb7e1503413a8a11c4f8707b67.yaml +21 -0
- data/bugs/issue-0711ff8b67baa63586f11d0096fee9dd4436bf58.yaml +23 -0
- data/bugs/issue-07f87998d93eb401e22395c11085676389b935c4.yaml +22 -0
- data/bugs/issue-0bff2d80008803cbc7efbcdacdc60ef2163664d2.yaml +22 -0
- data/bugs/issue-0c66f223d19efbca7b692f3b91961f407ad7abec.yaml +24 -0
- data/bugs/issue-183bc3c7a8f575aff2b24e0bf22aa0dfcc8e4fc2.yaml +29 -0
- data/bugs/issue-1bad1e60a04cb3adb6a8f3ded128af2e16b56ffe.yaml +18 -0
- data/bugs/issue-1f1d43f76bf4de79d7f94adbae6dd506a9d81633.yaml +41 -0
- data/bugs/issue-320924117cadb045cc91f2a6fca922b4d81d4bb5.yaml +20 -0
- data/bugs/issue-33e5c8355fbf65252ea9e939714651df8bd8cb3b.yaml +25 -0
- data/bugs/issue-36f7c8262a72bcd5e28cfa4ed29328b8237ea79b.yaml +20 -0
- data/bugs/issue-39bf04ee50c3bef67b89b8e9beb28657805587ce.yaml +18 -0
- data/bugs/issue-3e28ba7754f73d02ef416eef989af707a8c00f01.yaml +23 -0
- data/bugs/issue-3f638cc03f41f9c3fdf217355321f1563f8fee45.yaml +22 -0
- data/bugs/issue-41e48e14f1ef4f6deb69be68165d7dd3ffd99156.yaml +22 -0
- data/bugs/issue-4c9408166a2aa5dd333bbb05520deebf4ded08e0.yaml +22 -0
- data/bugs/issue-55c687e108ecd5aeb8e0d0aeb4294984f84acd3e.yaml +18 -0
- data/bugs/issue-5811d34692cc292717a58ec1df1f8948cf30d826.yaml +28 -0
- data/bugs/issue-5a7c1f59a0526f9cea7fb366867cf1e6ed8ef69d.yaml +22 -0
- data/bugs/issue-688a2c2566bef6a03efa57a4ae1f7cfa8fc74444.yaml +21 -0
- data/bugs/issue-78b16c7988ade2ef96e716fa8cb9a004bd4ced65.yaml +33 -0
- data/bugs/issue-804ee49f9800154eddf0650690c7a9bb5626253f.yaml +27 -0
- data/bugs/issue-807dd1c610b2e941a5d454e26b2eac27e89a0ab4.yaml +22 -0
- data/bugs/issue-822ee33ec11ebd25f90ea86e8438de7891e63aee.yaml +18 -0
- data/bugs/issue-82ff7152cebb8a1cb065b864cb4fe22de2328146.yaml +29 -0
- data/bugs/issue-856afbdcdd4970ad54b8ce4a6c017fbaab45f49d.yaml +31 -0
- data/bugs/issue-8d49e32fb21522651c67490adb4d80076dbb14e1.yaml +24 -0
- data/bugs/issue-91583359653a9d530c1e32be72d874d847a306e7.yaml +21 -0
- data/bugs/issue-af41a5229613172764e7d3c98431172db337053d.yaml +20 -0
- data/bugs/issue-bd9856b3788dd429c998a5af1b2aae8221cb80b7.yaml +28 -0
- data/bugs/issue-be22aef5c564fb7b5e9938343136a9cd6a2edb7b.yaml +22 -0
- data/bugs/issue-bf8697523c77c326e7e35fc82cf3dd739ae92310.yaml +27 -0
- data/bugs/issue-cdd4b4795f34d6ff46e56ece10f8216a4a5456b2.yaml +25 -0
- data/bugs/issue-d9bfb5581d745ef9deb3b9b2e08ef74d1cd43082.yaml +20 -0
- data/bugs/issue-e0ce2f687cc096f35715d28b0af88589f4ab6cc6.yaml +18 -0
- data/bugs/issue-e4b0aca4a10a574b333aeaecaaf221dbc5ed22c6.yaml +38 -0
- data/bugs/issue-f263746594b95ba778455730478ee8df60ee639d.yaml +22 -0
- data/bugs/project.yaml +72 -0
- data/builddeps.sh +102 -0
- data/fonts/Coolvetica.ttf +0 -0
- data/fonts/Lacuna.ttf +0 -0
- data/gemlib/shoes.rb +1 -0
- data/lib/shoes.rb +548 -0
- data/lib/shoes/cache.rb +54 -0
- data/lib/shoes/chipmunk.rb +35 -0
- data/lib/shoes/data.rb +39 -0
- data/lib/shoes/help.rb +468 -0
- data/lib/shoes/image.rb +25 -0
- data/lib/shoes/inspect.rb +128 -0
- data/lib/shoes/log.rb +48 -0
- data/lib/shoes/minitar.rb +986 -0
- data/lib/shoes/override.rb +38 -0
- data/lib/shoes/pack.rb +543 -0
- data/lib/shoes/search.rb +46 -0
- data/lib/shoes/setup.rb +329 -0
- data/lib/shoes/shy.rb +131 -0
- data/lib/shoes/shybuilder.rb +44 -0
- data/lib/shoes/version.rb +3 -0
- data/make/darwin/deps.vlc +12 -0
- data/make/darwin/dylibs.shoes +22 -0
- data/make/darwin/dylibs.video +11 -0
- data/make/darwin/env.rb +81 -0
- data/make/darwin/tasks.rb +105 -0
- data/make/linux/env.rb +65 -0
- data/make/linux/tasks.rb +61 -0
- data/make/make.rb +85 -0
- data/make/mingw/dlls +19 -0
- data/make/mingw/env.rb +69 -0
- data/make/mingw/tasks.rb +70 -0
- data/make/rakefile_common.rb +8 -0
- data/manual-snapshots/class-book.png +0 -0
- data/manual-snapshots/expert-definr.png +0 -0
- data/manual-snapshots/expert-funnies.png +0 -0
- data/manual-snapshots/expert-irb.png +0 -0
- data/manual-snapshots/expert-minesweeper.png +0 -0
- data/manual-snapshots/expert-othello.png +0 -0
- data/manual-snapshots/expert-pong.png +0 -0
- data/manual-snapshots/expert-tankspank.png +0 -0
- data/manual-snapshots/good-arc.png +0 -0
- data/manual-snapshots/good-clock.png +0 -0
- data/manual-snapshots/good-follow.png +0 -0
- data/manual-snapshots/good-reminder.png +0 -0
- data/manual-snapshots/good-vjot.png +0 -0
- data/manual-snapshots/simple-accordion.png +0 -0
- data/manual-snapshots/simple-anim-shapes.png +0 -0
- data/manual-snapshots/simple-anim-text.png +0 -0
- data/manual-snapshots/simple-arc.png +0 -0
- data/manual-snapshots/simple-bounce.png +0 -0
- data/manual-snapshots/simple-calc.png +0 -0
- data/manual-snapshots/simple-chipmunk.png +0 -0
- data/manual-snapshots/simple-control-sizes.png +0 -0
- data/manual-snapshots/simple-curve.png +0 -0
- data/manual-snapshots/simple-dialogs.png +0 -0
- data/manual-snapshots/simple-downloader.png +0 -0
- data/manual-snapshots/simple-draw.png +0 -0
- data/manual-snapshots/simple-editor.png +0 -0
- data/manual-snapshots/simple-form.png +0 -0
- data/manual-snapshots/simple-mask.png +0 -0
- data/manual-snapshots/simple-menu.png +0 -0
- data/manual-snapshots/simple-menu1.png +0 -0
- data/manual-snapshots/simple-rubygems.png +0 -0
- data/manual-snapshots/simple-slide.png +0 -0
- data/manual-snapshots/simple-sphere.png +0 -0
- data/manual-snapshots/simple-sqlite3.png +0 -0
- data/manual-snapshots/simple-timer.png +0 -0
- data/manual-snapshots/simple-video.png +0 -0
- data/platform/mac/Info.plist +55 -0
- data/platform/mac/build-deps.sh +658 -0
- data/platform/mac/command-manual.rb +1 -0
- data/platform/mac/deps-osx.patch +159 -0
- data/platform/mac/dmg_ds_store +0 -0
- data/platform/mac/pangorc +2 -0
- data/platform/mac/pkg-dmg +1447 -0
- data/platform/mac/shoes +31 -0
- data/platform/mac/shoes-launch +7 -0
- data/platform/mac/stub.m +178 -0
- data/platform/mac/version.plist +14 -0
- data/platform/msw/base.nsi +644 -0
- data/platform/msw/installer-1.bmp +0 -0
- data/platform/msw/installer-2.bmp +0 -0
- data/platform/msw/shoes.exe.manifest +17 -0
- data/platform/msw/shoes.ico +0 -0
- data/platform/msw/stub-inject.c +59 -0
- data/platform/msw/stub.c +271 -0
- data/platform/msw/stub32.h +14 -0
- data/platform/msw/stub32.rc +16 -0
- data/platform/nix/INSTALL +56 -0
- data/platform/nix/Makefile +144 -0
- data/platform/nix/shoes.launch +20 -0
- data/platform/skel.rb +27 -0
- data/rakefile_darwin.rb +7 -0
- data/rakefile_linux.rb +3 -0
- data/rakefile_mingw.rb +7 -0
- data/samples/class-book.rb +43 -0
- data/samples/class-book.yaml +387 -0
- data/samples/expert-definr.rb +23 -0
- data/samples/expert-funnies.rb +51 -0
- data/samples/expert-irb.rb +112 -0
- data/samples/expert-minesweeper.rb +267 -0
- data/samples/expert-othello.rb +319 -0
- data/samples/expert-pong.rb +62 -0
- data/samples/expert-tankspank.rb +385 -0
- data/samples/good-arc.rb +37 -0
- data/samples/good-clock.rb +51 -0
- data/samples/good-follow.rb +26 -0
- data/samples/good-reminder.rb +174 -0
- data/samples/good-vjot.rb +56 -0
- data/samples/simple-accordion.rb +75 -0
- data/samples/simple-anim-shapes.rb +17 -0
- data/samples/simple-anim-text.rb +13 -0
- data/samples/simple-arc.rb +23 -0
- data/samples/simple-bounce.rb +24 -0
- data/samples/simple-calc.rb +70 -0
- data/samples/simple-chipmunk.rb +26 -0
- data/samples/simple-control-sizes.rb +24 -0
- data/samples/simple-curve.rb +26 -0
- data/samples/simple-dialogs.rb +29 -0
- data/samples/simple-downloader.rb +27 -0
- data/samples/simple-draw.rb +13 -0
- data/samples/simple-editor.rb +28 -0
- data/samples/simple-form.rb +28 -0
- data/samples/simple-form.shy +0 -0
- data/samples/simple-mask.rb +21 -0
- data/samples/simple-menu.rb +31 -0
- data/samples/simple-menu1.rb +35 -0
- data/samples/simple-rubygems.rb +29 -0
- data/samples/simple-slide.rb +45 -0
- data/samples/simple-sphere.rb +28 -0
- data/samples/simple-sqlite3.rb +13 -0
- data/samples/simple-timer.rb +13 -0
- data/samples/simple-video.rb +13 -0
- data/shoes.gemspec +21 -0
- data/shoes/app.c +591 -0
- data/shoes/app.h +110 -0
- data/shoes/appwin32.h +13 -0
- data/shoes/appwin32.rc +28 -0
- data/shoes/canvas.c +2202 -0
- data/shoes/canvas.h +682 -0
- data/shoes/code.h +14 -0
- data/shoes/config.h +232 -0
- data/shoes/effects.c +243 -0
- data/shoes/effects.h +7 -0
- data/shoes/http.h +44 -0
- data/shoes/http/common.h +86 -0
- data/shoes/http/curl.c +259 -0
- data/shoes/http/nsurl.m +274 -0
- data/shoes/http/windownload.c +114 -0
- data/shoes/http/winhttp.c +216 -0
- data/shoes/http/winhttp.h +19 -0
- data/shoes/image.c +1020 -0
- data/shoes/internal.c +46 -0
- data/shoes/internal.h +63 -0
- data/shoes/native.h +110 -0
- data/shoes/native/cocoa.h +105 -0
- data/shoes/native/cocoa.m +1557 -0
- data/shoes/native/gtk.c +1257 -0
- data/shoes/native/windows.c +2392 -0
- data/shoes/ruby.c +5221 -0
- data/shoes/ruby.h +299 -0
- data/shoes/world.c +243 -0
- data/shoes/world.h +63 -0
- data/static/Shoes.icns +0 -0
- data/static/avatar.png +0 -0
- data/static/code_highlighter.js +188 -0
- data/static/code_highlighter_ruby.js +26 -0
- data/static/icon-debug.png +0 -0
- data/static/icon-error.png +0 -0
- data/static/icon-info.png +0 -0
- data/static/icon-warn.png +0 -0
- data/static/listbox_button1.png +0 -0
- data/static/listbox_button2.png +0 -0
- data/static/man-app.png +0 -0
- data/static/man-builds.png +0 -0
- data/static/man-builds1.png +0 -0
- data/static/man-editor-notepad.png +0 -0
- data/static/man-editor-osx.png +0 -0
- data/static/man-ele-background.png +0 -0
- data/static/man-ele-border.png +0 -0
- data/static/man-ele-button.png +0 -0
- data/static/man-ele-check.png +0 -0
- data/static/man-ele-editbox.png +0 -0
- data/static/man-ele-editline.png +0 -0
- data/static/man-ele-image.png +0 -0
- data/static/man-ele-listbox.png +0 -0
- data/static/man-ele-progress.png +0 -0
- data/static/man-ele-radio.png +0 -0
- data/static/man-ele-shape.png +0 -0
- data/static/man-ele-textblock.png +0 -0
- data/static/man-ele-video.png +0 -0
- data/static/man-intro-dmg.png +0 -0
- data/static/man-intro-exe.png +0 -0
- data/static/man-look-tiger.png +0 -0
- data/static/man-look-ubuntu.png +0 -0
- data/static/man-look-vista.png +0 -0
- data/static/man-run-osx.png +0 -0
- data/static/man-run-vista.png +0 -0
- data/static/man-run-xp.png +0 -0
- data/static/man-shot1.png +0 -0
- data/static/manual-en.txt +3531 -0
- data/static/manual-ja.txt +2825 -0
- data/static/manual.css +167 -0
- data/static/menu-corner1.png +0 -0
- data/static/menu-corner2.png +0 -0
- data/static/menu-gray.png +0 -0
- data/static/menu-left.png +0 -0
- data/static/menu-right.png +0 -0
- data/static/menu-top.png +0 -0
- data/static/shoes-dmg.jpg +0 -0
- data/static/shoes-icon-blue.png +0 -0
- data/static/shoes-icon.png +0 -0
- data/static/shoes-manual-apps.gif +0 -0
- data/static/shoes_main_window.png +0 -0
- data/static/stripe.png +0 -0
- data/static/stubs/blank.exe +0 -0
- data/static/stubs/blank.hfz +0 -0
- data/static/stubs/blank.run +375 -0
- data/static/stubs/cocoa-install +0 -0
- data/static/stubs/sh-install +49 -0
- data/static/stubs/shoes-stub-inject.exe +0 -0
- data/static/stubs/shoes-stub.exe +0 -0
- data/static/tutor-back.png +0 -0
- data/test/shoes_test.rb +8 -0
- data/test/test_helper.rb +25 -0
- data/use-deps +12 -0
- data/use-tmp-dep +8 -0
- metadata +509 -0
@@ -0,0 +1,319 @@
|
|
1
|
+
# Othello
|
2
|
+
# by tieg
|
3
|
+
# 1/13/08
|
4
|
+
# with help: DeeJay, Ryan M. from mailing list
|
5
|
+
#
|
6
|
+
# FIXME bug if it memorizes it but it's not a valid move
|
7
|
+
#
|
8
|
+
module Othello
|
9
|
+
|
10
|
+
PIECE_WIDTH = 62
|
11
|
+
PIECE_HEIGHT = 62
|
12
|
+
TOP_OFFSET = 47
|
13
|
+
LEFT_OFFSET = 12
|
14
|
+
|
15
|
+
class Game
|
16
|
+
BOARD_SIZE = [8,8]
|
17
|
+
|
18
|
+
attr_accessor :p1, :p2, :board, :board_history
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@board_history = []
|
22
|
+
@p1 = Player.new(:black, pieces_per_player)
|
23
|
+
@p2 = Player.new(:white, pieces_per_player)
|
24
|
+
@board = new_board
|
25
|
+
lay_initial_pieces
|
26
|
+
end
|
27
|
+
|
28
|
+
def next_turn(check_available_moves=true)
|
29
|
+
@current_player = next_player
|
30
|
+
if check_available_moves && skip_turn?
|
31
|
+
# FIXME Possible infinite loop if neither player has a good move?
|
32
|
+
next_turn
|
33
|
+
raise "Player #{@current_player.piece} (#{@current_player.color}) has no available moves. Player #{next_player.piece}'s (#{next_player.color}) turn."
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def current_player
|
38
|
+
@current_player ||= @p1
|
39
|
+
end
|
40
|
+
|
41
|
+
def next_player
|
42
|
+
current_player == @p1 ? @p2 : @p1
|
43
|
+
end
|
44
|
+
|
45
|
+
# Build the array for the board, with zero-based arrays.
|
46
|
+
def new_board
|
47
|
+
Array.new(BOARD_SIZE[0]) do # build each cols L to R
|
48
|
+
Array.new(BOARD_SIZE[1]) do # insert cells in each col
|
49
|
+
0
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Lay the initial 4 pieces in the middle
|
55
|
+
def lay_initial_pieces
|
56
|
+
lay_piece([4, 3], false)
|
57
|
+
next_turn(false)
|
58
|
+
lay_piece([3, 3], false)
|
59
|
+
next_turn(false)
|
60
|
+
lay_piece([3, 4], false)
|
61
|
+
next_turn(false)
|
62
|
+
lay_piece([4, 4], false)
|
63
|
+
next_turn(false)
|
64
|
+
end
|
65
|
+
|
66
|
+
def lay_piece(c=[0,0], check_adjacent_pieces=true)
|
67
|
+
memorize_board
|
68
|
+
piece = current_player.piece
|
69
|
+
opp_piece = current_player.opp_piece
|
70
|
+
raise "Spot already taken." if board_at(c) != 0
|
71
|
+
if check_adjacent_pieces
|
72
|
+
pieces_to_change = []
|
73
|
+
pieces_to_change << check_direction(c, [ 0, 1], piece, opp_piece) # N
|
74
|
+
pieces_to_change << check_direction(c, [ 1, 1], piece, opp_piece) # NE
|
75
|
+
pieces_to_change << check_direction(c, [ 1, 0], piece, opp_piece) # E
|
76
|
+
pieces_to_change << check_direction(c, [ 1,-1], piece, opp_piece) # SE
|
77
|
+
pieces_to_change << check_direction(c, [ 0,-1], piece, opp_piece) # S
|
78
|
+
pieces_to_change << check_direction(c, [-1,-1], piece, opp_piece) # SW
|
79
|
+
pieces_to_change << check_direction(c, [-1, 0], piece, opp_piece) # W
|
80
|
+
pieces_to_change << check_direction(c, [-1, 1], piece, opp_piece) # NW
|
81
|
+
raise "You must move to a spot that will turn your opponent's piece." if pieces_to_change.compact.all? { |a| a.empty? }
|
82
|
+
pieces_to_change.compact.each { |direction| direction.each { |i| @board[i[0]][i[1]] = piece } }
|
83
|
+
end
|
84
|
+
current_player.pieces -= 1
|
85
|
+
@board[c[0]][c[1]] = piece
|
86
|
+
current_winner = calculate_current_winner
|
87
|
+
raise "Game over. Player #{current_winner.piece} wins with #{current_winner.pieces_on_board} pieces!" if @p1.pieces + @p2.pieces == 0
|
88
|
+
end
|
89
|
+
|
90
|
+
def skip_turn?
|
91
|
+
possibles = []
|
92
|
+
@board.each_with_index { |col,col_index|
|
93
|
+
col.each_with_index { |cell,row_index|
|
94
|
+
return false if possible_move?([col_index,row_index])
|
95
|
+
}
|
96
|
+
}
|
97
|
+
true
|
98
|
+
end
|
99
|
+
|
100
|
+
def possible_move?(c=[0,0])
|
101
|
+
return nil if board_at(c) != 0
|
102
|
+
possible_moves = []
|
103
|
+
piece = current_player.piece
|
104
|
+
opp_piece = current_player.opp_piece
|
105
|
+
pieces_to_change = []
|
106
|
+
pieces_to_change << check_direction(c, [ 0, 1], piece, opp_piece) # N
|
107
|
+
pieces_to_change << check_direction(c, [ 1, 1], piece, opp_piece) # NE
|
108
|
+
pieces_to_change << check_direction(c, [ 1, 0], piece, opp_piece) # E
|
109
|
+
pieces_to_change << check_direction(c, [ 1,-1], piece, opp_piece) # SE
|
110
|
+
pieces_to_change << check_direction(c, [ 0,-1], piece, opp_piece) # S
|
111
|
+
pieces_to_change << check_direction(c, [-1,-1], piece, opp_piece) # SW
|
112
|
+
pieces_to_change << check_direction(c, [-1, 0], piece, opp_piece) # W
|
113
|
+
pieces_to_change << check_direction(c, [-1, 1], piece, opp_piece) # NW
|
114
|
+
return nil if pieces_to_change.compact.all? { |a| a.empty? }
|
115
|
+
true
|
116
|
+
end
|
117
|
+
|
118
|
+
def memorize_board
|
119
|
+
dup_board = new_board
|
120
|
+
dup_board = []
|
121
|
+
@board.each do |col|
|
122
|
+
dup_board << col.dup
|
123
|
+
end
|
124
|
+
@board_history << { :player => current_player, :board => dup_board }
|
125
|
+
end
|
126
|
+
|
127
|
+
def undo!
|
128
|
+
last_move = @board_history.pop
|
129
|
+
@board = last_move[:board]
|
130
|
+
@current_player = last_move[:player]
|
131
|
+
@current_player.pieces += 1
|
132
|
+
end
|
133
|
+
|
134
|
+
def calculate_current_winner
|
135
|
+
@p1.pieces_on_board, @p2.pieces_on_board = 0, 0
|
136
|
+
@board.each { |row|
|
137
|
+
row.each { |cell|
|
138
|
+
if cell == 1
|
139
|
+
@p1.pieces_on_board += 1
|
140
|
+
else
|
141
|
+
@p2.pieces_on_board += 1
|
142
|
+
end
|
143
|
+
}
|
144
|
+
}
|
145
|
+
@p1.pieces_on_board > @p2.pieces_on_board ? @p1 : @p2
|
146
|
+
end
|
147
|
+
|
148
|
+
def check_direction(c, dir, piece, opp_piece)
|
149
|
+
c_adjacent = next_in_direction(c.dup, dir)
|
150
|
+
c_last = nil
|
151
|
+
pieces_in_between = []
|
152
|
+
# Find the last piece if there is one.
|
153
|
+
while(valid_location?(c_adjacent))
|
154
|
+
if board_at(c_adjacent) == opp_piece
|
155
|
+
pieces_in_between << c_adjacent.dup
|
156
|
+
elsif board_at(c_adjacent) == piece && pieces_in_between.size > 0
|
157
|
+
c_last = c_adjacent
|
158
|
+
break
|
159
|
+
else
|
160
|
+
break
|
161
|
+
end
|
162
|
+
c_adjacent = next_in_direction(c_adjacent, dir)
|
163
|
+
end
|
164
|
+
|
165
|
+
pieces_in_between.empty? || c_last.nil? ? nil : pieces_in_between
|
166
|
+
end
|
167
|
+
|
168
|
+
# Find the value of the board at the given coordinate.
|
169
|
+
def board_at(c)
|
170
|
+
@board[c[0]][c[1]]
|
171
|
+
end
|
172
|
+
|
173
|
+
# Is this a valid location on board?
|
174
|
+
def valid_location?(c=[1,1])
|
175
|
+
c[0] >= 0 && c[1] >= 0 && c[0] < BOARD_SIZE[0] && c[1] < BOARD_SIZE[1]
|
176
|
+
end
|
177
|
+
|
178
|
+
# Perform the operations to get the next spot in the appropriate direction
|
179
|
+
def next_in_direction(c, dir)
|
180
|
+
c[0] += dir[0]
|
181
|
+
c[1] += dir[1]
|
182
|
+
c
|
183
|
+
end
|
184
|
+
|
185
|
+
private
|
186
|
+
def pieces_per_player
|
187
|
+
total_squares / 2
|
188
|
+
end
|
189
|
+
|
190
|
+
# The total number of squares
|
191
|
+
def total_squares
|
192
|
+
BOARD_SIZE[0] * BOARD_SIZE[1]
|
193
|
+
end
|
194
|
+
|
195
|
+
class Player
|
196
|
+
attr_accessor :pieces, :color, :pieces_on_board
|
197
|
+
|
198
|
+
def initialize(color=:black,pieces=0)
|
199
|
+
@pieces = pieces
|
200
|
+
@pieces_on_board = 0 # used only in calculating winner
|
201
|
+
@color = color
|
202
|
+
end
|
203
|
+
|
204
|
+
def piece
|
205
|
+
color == :black ? 1 : 2
|
206
|
+
end
|
207
|
+
|
208
|
+
def opp_piece
|
209
|
+
color == :black ? 2 : 1
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def draw_player_1(first_turn=false)
|
215
|
+
stack :margin => 10 do
|
216
|
+
if GAME.current_player==GAME.p1
|
217
|
+
background yellow
|
218
|
+
para span("Player 1 (#{GAME.current_player.color}) turn", :stroke => black, :font => "Trebuchet 20px bold"), :margin => 4
|
219
|
+
else
|
220
|
+
background white
|
221
|
+
para span("Player 1", :stroke => black, :font => "Trebuchet 10px bold"), :margin => 4
|
222
|
+
|
223
|
+
button("Undo last move", :top => 0, :left => -150) { GAME.undo!; draw_board } unless GAME.board_history.empty?
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def draw_player_2(first_turn=false)
|
229
|
+
stack :top => 550, :left => 0, :margin => 10 do
|
230
|
+
if GAME.current_player==GAME.p2
|
231
|
+
background yellow
|
232
|
+
para span("Player 2's (#{GAME.current_player.color}) turn", :stroke => black, :font => "Trebuchet 20px bold"), :margin => 4
|
233
|
+
else
|
234
|
+
background white
|
235
|
+
para span("Player 2", :stroke => black, :font => "Trebuchet 10px bold"), :margin => 4
|
236
|
+
|
237
|
+
button("Undo last move", :top => 0, :left => -150) { GAME.undo!; draw_board } unless GAME.board_history.empty?
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
|
243
|
+
def draw_board
|
244
|
+
clear do
|
245
|
+
background black
|
246
|
+
draw_player_1
|
247
|
+
stack :margin => 10 do
|
248
|
+
fill rgb(0, 190, 0)
|
249
|
+
rect :left => 0, :top => 0, :width => 495, :height => 495
|
250
|
+
|
251
|
+
GAME.board.each_with_index do |col, col_index|
|
252
|
+
col.each_with_index do |cell, row_index|
|
253
|
+
left, top = left_top_corner_of_piece(col_index, row_index)
|
254
|
+
left = left - LEFT_OFFSET
|
255
|
+
top = top - TOP_OFFSET
|
256
|
+
fill rgb(0, 440, 0, 90)
|
257
|
+
strokewidth 1
|
258
|
+
stroke rgb(0, 100, 0)
|
259
|
+
rect :left => left, :top => top, :width => PIECE_WIDTH, :height => PIECE_HEIGHT
|
260
|
+
|
261
|
+
if cell != 0
|
262
|
+
strokewidth 0
|
263
|
+
fill (cell == 1 ? rgb(100,100,100) : rgb(155,155,155))
|
264
|
+
oval(left+3, top+4, PIECE_WIDTH-10, PIECE_HEIGHT-10)
|
265
|
+
|
266
|
+
fill (cell == 1 ? black : white)
|
267
|
+
oval(left+5, top+5, PIECE_WIDTH-10, PIECE_HEIGHT-10)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
draw_player_2
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def left_top_corner_of_piece(a,b)
|
277
|
+
[(a*PIECE_WIDTH+LEFT_OFFSET), (b*PIECE_HEIGHT+TOP_OFFSET)]
|
278
|
+
end
|
279
|
+
|
280
|
+
def right_bottom_corner_of_piece(a,b)
|
281
|
+
left_top_corner_of_piece(a,b).map { |coord| coord + PIECE_WIDTH }
|
282
|
+
end
|
283
|
+
|
284
|
+
def find_piece(x,y)
|
285
|
+
GAME.board.each_with_index { |row_array, row|
|
286
|
+
row_array.each_with_index { |col_array, col|
|
287
|
+
left, top = left_top_corner_of_piece(col, row).map { |i| i - 5}
|
288
|
+
right, bottom = right_bottom_corner_of_piece(col, row).map { |i| i -5 }
|
289
|
+
return [col, row] if x >= left && x <= right && y >= top && y <= bottom
|
290
|
+
}
|
291
|
+
}
|
292
|
+
return false
|
293
|
+
end
|
294
|
+
|
295
|
+
GAME = Othello::Game.new
|
296
|
+
end
|
297
|
+
|
298
|
+
|
299
|
+
Shoes.app :width => 520, :height => 600 do
|
300
|
+
extend Othello
|
301
|
+
|
302
|
+
draw_board
|
303
|
+
|
304
|
+
click { |button, x, y|
|
305
|
+
if coords = find_piece(x,y)
|
306
|
+
begin
|
307
|
+
GAME.lay_piece(coords)
|
308
|
+
GAME.next_turn
|
309
|
+
draw_board
|
310
|
+
rescue => e
|
311
|
+
draw_board
|
312
|
+
alert(e.message)
|
313
|
+
end
|
314
|
+
else
|
315
|
+
# alert("Not a piece.")
|
316
|
+
end
|
317
|
+
}
|
318
|
+
end
|
319
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
#
|
2
|
+
# Pong in Shoes
|
3
|
+
# a clone of http://billmill.org/pong.html
|
4
|
+
# and shoes is at http://shoooes.net
|
5
|
+
#
|
6
|
+
# This is just for kicks -- I'm very fond of NodeBox as well.
|
7
|
+
#
|
8
|
+
# There's a slightly different approach in Shoes: rather than
|
9
|
+
# redrawing the shapes, you can move the shapes around as objects.
|
10
|
+
# Yeah, see, notice how @you, @comp and @ball are used.
|
11
|
+
#
|
12
|
+
Shoes.app :width => 400, :height => 400, :resizable => false do
|
13
|
+
paddle_size = 75
|
14
|
+
ball_diameter = 20
|
15
|
+
vx, vy = [3, 4]
|
16
|
+
compuspeed = 10
|
17
|
+
bounce = 1.2
|
18
|
+
|
19
|
+
# set up the playing board
|
20
|
+
nostroke and background white
|
21
|
+
@ball = oval 0, 0, ball_diameter, :fill => "#9B7"
|
22
|
+
@you, @comp = [app.height-4, 0].map {|y| rect 0, y, paddle_size, 4, :curve => 2}
|
23
|
+
|
24
|
+
# animates at 40 frames per second
|
25
|
+
@anim = animate 40 do
|
26
|
+
|
27
|
+
# check for game over
|
28
|
+
if @ball.top + ball_diameter < 0 or @ball.top > app.height
|
29
|
+
para strong("GAME OVER", :size => 32), "\n",
|
30
|
+
@ball.top < 0 ? "You win!" : "Computer wins", :top => 140, :align => 'center'
|
31
|
+
@ball.hide and @anim.stop
|
32
|
+
end
|
33
|
+
|
34
|
+
# move the @you paddle, following the mouse
|
35
|
+
@you.left = mouse[1] - (paddle_size / 2)
|
36
|
+
nx, ny = (@ball.left + vx).to_i, (@ball.top + vy).to_i
|
37
|
+
|
38
|
+
# move the @comp paddle, speed based on `compuspeed` variable
|
39
|
+
@comp.left +=
|
40
|
+
if nx + (ball_diameter / 2) > @comp.left + paddle_size; compuspeed
|
41
|
+
elsif nx < @comp.left; -compuspeed
|
42
|
+
else 0 end
|
43
|
+
|
44
|
+
# if the @you paddle hits the ball
|
45
|
+
if ny + ball_diameter > app.height and vy > 0 and
|
46
|
+
(0..paddle_size).include? nx + (ball_diameter / 2) - @you.left
|
47
|
+
vx, vy = (nx - @you.left - (paddle_size / 2)) * 0.25, -vy * bounce
|
48
|
+
ny = app.height - ball_diameter
|
49
|
+
end
|
50
|
+
|
51
|
+
# if the @comp paddle hits the ball
|
52
|
+
if ny < 0 and vy < 0 and
|
53
|
+
(0..paddle_size).include? nx + (ball_diameter / 2) - @comp.left
|
54
|
+
vx, vy = (nx - @comp.left - (paddle_size / 2)) * 0.25, -vy * bounce
|
55
|
+
ny = 0
|
56
|
+
elsif nx + ball_diameter > app.width or nx < 0
|
57
|
+
vx = -vx
|
58
|
+
end
|
59
|
+
|
60
|
+
@ball.move nx, ny
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,385 @@
|
|
1
|
+
# Tankspank
|
2
|
+
# kevin conner
|
3
|
+
# connerk@gmail.com
|
4
|
+
# version 3, 13 March 2008
|
5
|
+
# this code is free, do what you like with it!
|
6
|
+
|
7
|
+
$width, $height = 700, 500
|
8
|
+
$camera_tightness = 0.1
|
9
|
+
|
10
|
+
module Collisions
|
11
|
+
def contains? x, y
|
12
|
+
not (x < west or x > east or y < north or y > south)
|
13
|
+
end
|
14
|
+
|
15
|
+
def intersects? other
|
16
|
+
not (other.east < west or other.west > east or
|
17
|
+
other.south < north or other.north > south)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Building
|
22
|
+
include Collisions
|
23
|
+
|
24
|
+
attr_reader :west, :east, :north, :south
|
25
|
+
|
26
|
+
def initialize(west, east, north, south)
|
27
|
+
@west, @east, @north, @south = west, east, north, south
|
28
|
+
@top, @bottom = 1.1 + rand(3) * 0.15, 1.0
|
29
|
+
|
30
|
+
color = (1..3).collect { 0.2 + 0.4 * rand }
|
31
|
+
color << 0.9
|
32
|
+
@stroke = $app.rgb *color
|
33
|
+
color[-1] = 0.3
|
34
|
+
@fill = $app.rgb *color
|
35
|
+
end
|
36
|
+
|
37
|
+
def draw
|
38
|
+
$app.stroke @stroke
|
39
|
+
$app.fill @fill
|
40
|
+
Opp.draw_opp_box(@west, @east, @north, @south, @top, @bottom)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
module Guidance
|
45
|
+
def guidance_system x, y, dest_x, dest_y, angle
|
46
|
+
vx, vy = dest_x - x, dest_y - y
|
47
|
+
if vx.abs < 0.1 and vy.abs <= 0.1
|
48
|
+
yield 0, 0
|
49
|
+
else
|
50
|
+
length = Math.sqrt(vx * vx + vy * vy)
|
51
|
+
vx /= length
|
52
|
+
vy /= length
|
53
|
+
ax, ay = Math.cos(angle), Math.sin(angle)
|
54
|
+
cos_between = vx * ax + vy * ay
|
55
|
+
sin_between = vx * -ay + vy * ax
|
56
|
+
yield sin_between, cos_between
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
module Life
|
62
|
+
attr_reader :health
|
63
|
+
def dead?
|
64
|
+
@health == 0
|
65
|
+
end
|
66
|
+
def hurt damage
|
67
|
+
@health = [@health - damage, 0].max
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class Tank
|
72
|
+
include Collisions
|
73
|
+
include Guidance
|
74
|
+
include Life
|
75
|
+
# ^ sounds like insurance
|
76
|
+
|
77
|
+
@@collide_size = 15
|
78
|
+
def west; @x - @@collide_size; end
|
79
|
+
def east; @x + @@collide_size; end
|
80
|
+
def north; @y - @@collide_size; end
|
81
|
+
def south; @y + @@collide_size; end
|
82
|
+
|
83
|
+
attr_reader :x, :y
|
84
|
+
|
85
|
+
def initialize
|
86
|
+
@x, @y = 0, -125
|
87
|
+
@last_x, @last_y = @x, @y
|
88
|
+
@tank_angle = 0.0
|
89
|
+
@dest_x, @dest_y = 0, 0
|
90
|
+
@acceleration = 0.0
|
91
|
+
@speed = 0.0
|
92
|
+
@moving = false
|
93
|
+
|
94
|
+
@aim_angle = 0.0
|
95
|
+
@target_x, @target_y = 0, 0
|
96
|
+
@aimed = false
|
97
|
+
|
98
|
+
@health = 100
|
99
|
+
end
|
100
|
+
|
101
|
+
def set_destination
|
102
|
+
@dest_x, @dest_y = @target_x, @target_y
|
103
|
+
@moving = true
|
104
|
+
end
|
105
|
+
|
106
|
+
def fire
|
107
|
+
Opp.add_shell Shell.new(@x + 30 * Math.cos(@aim_angle),
|
108
|
+
@y + 30 * Math.sin(@aim_angle), @aim_angle)
|
109
|
+
end
|
110
|
+
|
111
|
+
def update button, mouse_x, mouse_y
|
112
|
+
@target_x, @target_y = mouse_x, mouse_y
|
113
|
+
|
114
|
+
if @moving
|
115
|
+
guidance_system @x, @y, @dest_x, @dest_y, @tank_angle do |direction, on_target|
|
116
|
+
turn direction
|
117
|
+
@acceleration = on_target * 0.25
|
118
|
+
end
|
119
|
+
|
120
|
+
distance = Math.sqrt((@dest_x - @x) ** 2 + (@dest_y - @y) ** 2)
|
121
|
+
@moving = false if distance < 50
|
122
|
+
else
|
123
|
+
@acceleration = 0.0
|
124
|
+
end
|
125
|
+
|
126
|
+
guidance_system @x, @y, @target_x, @target_y, @aim_angle do |direction, on_target|
|
127
|
+
aim direction
|
128
|
+
@aimed = on_target > 0.98
|
129
|
+
end
|
130
|
+
|
131
|
+
integrity = @health / 100.0 # the more hurt you are, the slower you go
|
132
|
+
@speed = [[@speed + @acceleration, 5.0 * integrity].min, -3.0 * integrity].max
|
133
|
+
@speed *= 0.9 if !@moving
|
134
|
+
|
135
|
+
@last_x, @last_y = @x, @y
|
136
|
+
@x += @speed * Math.cos(@tank_angle)
|
137
|
+
@y += @speed * Math.sin(@tank_angle)
|
138
|
+
end
|
139
|
+
|
140
|
+
def collide_and_stop
|
141
|
+
@x, @y = @last_x, @last_y
|
142
|
+
hurt @speed.abs * 3 + 5
|
143
|
+
@speed = 0
|
144
|
+
@moving = false
|
145
|
+
end
|
146
|
+
|
147
|
+
def turn direction
|
148
|
+
@tank_angle += [[-0.03, direction].max, 0.03].min
|
149
|
+
end
|
150
|
+
|
151
|
+
def aim direction
|
152
|
+
@aim_angle += [[-0.1, direction].max, 0.1].min
|
153
|
+
end
|
154
|
+
|
155
|
+
def draw
|
156
|
+
$app.stroke $app.blue
|
157
|
+
$app.fill $app.blue(0.4)
|
158
|
+
Opp.draw_opp_rect @x - 20, @x + 20, @y - 15, @y + 15, 1.05, @tank_angle
|
159
|
+
#Opp.draw_opp_box @x - 20, @x + 20, @y - 20, @y + 20, 1.03, 1.0
|
160
|
+
Opp.draw_opp_rect @x - 10, @x + 10, @y - 7, @y + 7, 1.05, @aim_angle
|
161
|
+
x, unused1, y, unused2 = Opp.project(@x, 0, @y, 0, 1.05)
|
162
|
+
$app.line x, y, x + 25 * Math.cos(@aim_angle), y + 25 * Math.sin(@aim_angle)
|
163
|
+
|
164
|
+
$app.stroke $app.red
|
165
|
+
$app.fill $app.red(@aimed ? 0.4 : 0.1)
|
166
|
+
Opp.draw_opp_oval @target_x - 10, @target_x + 10, @target_y - 10, @target_y + 10, 1.00
|
167
|
+
|
168
|
+
if @moving
|
169
|
+
$app.stroke $app.green
|
170
|
+
$app.fill $app.green(0.2)
|
171
|
+
Opp.draw_opp_oval @dest_x - 20, @dest_x + 20, @dest_y - 20, @dest_y + 20, 1.00
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
class Shell
|
177
|
+
attr_reader :x, :y
|
178
|
+
|
179
|
+
def initialize x, y, angle
|
180
|
+
@x, @y, @angle = x, y, angle
|
181
|
+
@speed = 10.0
|
182
|
+
end
|
183
|
+
|
184
|
+
def update
|
185
|
+
@x += @speed * Math.cos(@angle)
|
186
|
+
@y += @speed * Math.sin(@angle)
|
187
|
+
end
|
188
|
+
|
189
|
+
def draw
|
190
|
+
$app.stroke $app.red
|
191
|
+
$app.fill $app.red(0.1)
|
192
|
+
Opp.draw_opp_box @x - 2, @x + 2, @y - 2, @y + 2, 1.05, 1.04
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
class Opp
|
197
|
+
def self.new_game
|
198
|
+
@offset_x, @offset_y = 0, 0
|
199
|
+
@buildings = [
|
200
|
+
[-1000, -750, -750, -250],
|
201
|
+
[-500, 250, -750, -250],
|
202
|
+
[500, 1000, -750, -500],
|
203
|
+
[750, 1250, -250, 0],
|
204
|
+
[750, 1250, 250, 750],
|
205
|
+
[250, 500, 0, 750],
|
206
|
+
[-250, 0, 0, 500],
|
207
|
+
[-500, 0, 750, 1000],
|
208
|
+
[-1000, -500, 0, 500],
|
209
|
+
[400, 600, -350, -150]
|
210
|
+
].collect { |p| Building.new *p }
|
211
|
+
@shells = []
|
212
|
+
@boundary = [-1250, 1500, -1250, 1250]
|
213
|
+
@tank = Tank.new
|
214
|
+
@center_x, @center_y = $app.width / 2, $app.height / 2
|
215
|
+
end
|
216
|
+
|
217
|
+
def self.tank
|
218
|
+
@tank
|
219
|
+
end
|
220
|
+
|
221
|
+
def self.read_input
|
222
|
+
@input = $app.mouse
|
223
|
+
end
|
224
|
+
|
225
|
+
def self.update_scene
|
226
|
+
button, x, y = @input
|
227
|
+
x += @offset_x - @center_x
|
228
|
+
y += @offset_y - @center_y
|
229
|
+
|
230
|
+
@tank.update(button, x, y) if !@tank.dead?
|
231
|
+
@buildings.each do |b|
|
232
|
+
@tank.collide_and_stop if b.intersects? @tank
|
233
|
+
end
|
234
|
+
|
235
|
+
@shells.each { |s| s.update }
|
236
|
+
@buildings.each do |b|
|
237
|
+
@shells.reject! do |s|
|
238
|
+
b.contains?(s.x, s.y)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
#collide shells with tanks -- don't need this until there are enemy tanks
|
242
|
+
#@shells.reject! do |s|
|
243
|
+
# @tank.contains?(s.x, s.y)
|
244
|
+
#end
|
245
|
+
|
246
|
+
$app.clear do
|
247
|
+
@offset_x += $camera_tightness * (@tank.x - @offset_x)
|
248
|
+
@offset_y += $camera_tightness * (@tank.y - @offset_y)
|
249
|
+
|
250
|
+
$app.background $app.black
|
251
|
+
@center_x, @center_y = $app.width / 2, $app.height / 2
|
252
|
+
|
253
|
+
$app.stroke $app.red(0.9)
|
254
|
+
$app.nofill
|
255
|
+
draw_opp_box *(@boundary + [1.1, 1.0, false])
|
256
|
+
|
257
|
+
@tank.draw
|
258
|
+
@shells.each { |s| s.draw }
|
259
|
+
@buildings.each { |b| b.draw }
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def self.add_shell shell
|
264
|
+
@shells << shell
|
265
|
+
@shells.shift if @shells.size > 10
|
266
|
+
end
|
267
|
+
|
268
|
+
def self.project left, right, top, bottom, depth
|
269
|
+
[left, right].collect { |x| @center_x + depth * (x - @offset_x) } +
|
270
|
+
[top, bottom].collect { |y| @center_y + depth * (y - @offset_y) }
|
271
|
+
end
|
272
|
+
|
273
|
+
# here "front" and "back" push the rect into and out of the window.
|
274
|
+
# 1.0 means your x and y units are pixels on the surface.
|
275
|
+
# greater than that brings the box closer. less pushes it back. 0.0 => infinity.
|
276
|
+
# the front will be filled but the rest is wireframe only.
|
277
|
+
def self.draw_opp_box left, right, top, bottom, front, back, occlude = true
|
278
|
+
near_left, near_right, near_top, near_bottom = project(left, right, top, bottom, front)
|
279
|
+
far_left, far_right, far_top, far_bottom = project(left, right, top, bottom, back)
|
280
|
+
|
281
|
+
# determine which sides of the box are visible
|
282
|
+
if occlude
|
283
|
+
draw_left = @center_x < near_left
|
284
|
+
draw_right = near_right < @center_x
|
285
|
+
draw_top = @center_y < near_top
|
286
|
+
draw_bottom = near_bottom < @center_y
|
287
|
+
else
|
288
|
+
draw_left, draw_right, draw_top, draw_bottom = [true] * 4
|
289
|
+
end
|
290
|
+
|
291
|
+
# draw lines for the back edges
|
292
|
+
$app.line far_left, far_top, far_right, far_top if draw_top
|
293
|
+
$app.line far_left, far_bottom, far_right, far_bottom if draw_bottom
|
294
|
+
$app.line far_left, far_top, far_left, far_bottom if draw_left
|
295
|
+
$app.line far_right, far_top, far_right, far_bottom if draw_right
|
296
|
+
|
297
|
+
# draw lines to connect the front and back
|
298
|
+
$app.line near_left, near_top, far_left, far_top if draw_left or draw_top
|
299
|
+
$app.line near_right, near_top, far_right, far_top if draw_right or draw_top
|
300
|
+
$app.line near_left, near_bottom, far_left, far_bottom if draw_left or draw_bottom
|
301
|
+
$app.line near_right, near_bottom, far_right, far_bottom if draw_right or draw_bottom
|
302
|
+
|
303
|
+
# draw the front, filled
|
304
|
+
$app.rect near_left, near_top, near_right - near_left, near_bottom - near_top
|
305
|
+
end
|
306
|
+
|
307
|
+
def self.draw_opp_rect left, right, top, bottom, depth, angle, with_x = false
|
308
|
+
pl, pr, pt, pb = project(left, right, top, bottom, depth)
|
309
|
+
cos = Math.cos(angle)
|
310
|
+
sin = Math.sin(angle)
|
311
|
+
cx, cy = (pr + pl) / 2.0, (pb + pt) / 2.0
|
312
|
+
points = [[pl, pt], [pr, pt], [pr, pb], [pl, pb]].collect do |x, y|
|
313
|
+
[cx + (x - cx) * cos - (y - cy) * sin,
|
314
|
+
cy + (x - cx) * sin + (y - cy) * cos]
|
315
|
+
end
|
316
|
+
|
317
|
+
$app.line *(points[0] + points[1])
|
318
|
+
$app.line *(points[1] + points[2])
|
319
|
+
$app.line *(points[2] + points[3])
|
320
|
+
$app.line *(points[3] + points[0])
|
321
|
+
end
|
322
|
+
|
323
|
+
def self.draw_opp_oval left, right, top, bottom, depth
|
324
|
+
pl, pr, pt, pb = project(left, right, top, bottom, depth)
|
325
|
+
$app.oval(pl, pt, pr - pl, pb - pt)
|
326
|
+
end
|
327
|
+
|
328
|
+
def self.draw_opp_plane x1, y1, x2, y2, front, back, stroke_color
|
329
|
+
near_x1, near_x2, near_y1, near_y2 = project(x1, x2, y1, y2, front)
|
330
|
+
far_x1, far_x2, far_y1, far_y2 = project(x1, x2, y1, y2, back)
|
331
|
+
|
332
|
+
$app.stroke stroke_color
|
333
|
+
|
334
|
+
$app.line far_x1, far_y1, far_x2, far_y2
|
335
|
+
$app.line far_x1, far_y1, near_x1, near_y1
|
336
|
+
$app.line far_x2, far_y2, near_x2, near_y2
|
337
|
+
$app.line near_x1, near_y1, near_x2, near_y2
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
Shoes.app :width => $width, :height => $height do
|
342
|
+
$app = self
|
343
|
+
|
344
|
+
Opp.new_game
|
345
|
+
@playing = true
|
346
|
+
|
347
|
+
keypress do |key|
|
348
|
+
if @playing
|
349
|
+
if key == "1" or key == "z"
|
350
|
+
Opp.tank.set_destination
|
351
|
+
elsif key == "2" or key == "x" or key == " "
|
352
|
+
Opp.tank.fire
|
353
|
+
end
|
354
|
+
else
|
355
|
+
if key == "n"
|
356
|
+
Opp.new_game
|
357
|
+
@playing = true
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
click do |button, x, y|
|
363
|
+
if @playing
|
364
|
+
if button == 1
|
365
|
+
Opp.tank.set_destination
|
366
|
+
else
|
367
|
+
Opp.tank.fire
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
game_over_count = -1
|
373
|
+
animate(60) do
|
374
|
+
Opp.read_input if @playing
|
375
|
+
Opp.update_scene
|
376
|
+
|
377
|
+
@playing = false if Opp.tank.dead?
|
378
|
+
if !@playing
|
379
|
+
stack do
|
380
|
+
banner "Game Over", :stroke => white, :margin => 10
|
381
|
+
caption "learn to drive!", :stroke => white, :margin => 20
|
382
|
+
end
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|