snek 0.1.0
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 +7 -0
- data/.gitignore +3 -0
- data/Gemfile +3 -0
- data/README.markdown +17 -0
- data/Rakefile +6 -0
- data/assets/sounds/explosion.wav +0 -0
- data/assets/sounds/pickup.wav +0 -0
- data/assets/sounds/startup.wav +0 -0
- data/bin/snek +20 -0
- data/lib/game.rb +277 -0
- data/lib/game_engine/engine.rb +22 -0
- data/lib/game_engine/frame.rb +84 -0
- data/lib/game_engine/input.rb +13 -0
- data/lib/game_engine/network.rb +52 -0
- data/lib/game_engine/sound.rb +12 -0
- data/lib/game_engine/window.rb +11 -0
- data/lib/snek.rb +32 -0
- data/lib/snek/version.rb +3 -0
- data/snek.gemspec +24 -0
- metadata +119 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e9b064541769fc02d79b90d8394c226c70d34199
|
4
|
+
data.tar.gz: 9271b210952c5ab66e427c656bf2b8fea88aade2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 54624bbbd428c6bf48039183ddab94c0df99988a7b26053a78ae3644cd286dfc68efca675f44bf58cf1a7381187c766096b8255cf909deb477e2049ff6addd75
|
7
|
+
data.tar.gz: 91a641b05a9bb3f8d3acbff651e6703b235675dfc17e7436ed9bb5e8a35fc7efa895324a7d51a9405f4218fad2ca8903d360608f84b8798cdc52c2cb195b8785
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# SNEK
|
2
|
+
|
3
|
+
Terminal multiplayer snek game made at Railscamp 19, Adelaide.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
```
|
8
|
+
gem install snek
|
9
|
+
```
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
```
|
14
|
+
snek --head=⛵️
|
15
|
+
```
|
16
|
+
|
17
|
+
Controls are <kbd>w</kbd>, <kbd>a</kbd>, <kbd>s</kbd>, <kbd>d</kbd>.
|
data/Rakefile
ADDED
Binary file
|
Binary file
|
Binary file
|
data/bin/snek
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH << './lib'
|
4
|
+
|
5
|
+
require 'game'
|
6
|
+
|
7
|
+
options = {}
|
8
|
+
|
9
|
+
ARGV.each do |arg|
|
10
|
+
option, value = arg.split('=')
|
11
|
+
options[option] = value
|
12
|
+
end
|
13
|
+
|
14
|
+
head = options['--head'] || options['-h']
|
15
|
+
|
16
|
+
if !options.empty? && head.nil?
|
17
|
+
$stderr.puts "#{$0}: usage: [-h=[char]|--head=[char]]"
|
18
|
+
else
|
19
|
+
Snek::Game.new(head: head).start
|
20
|
+
end
|
data/lib/game.rb
ADDED
@@ -0,0 +1,277 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'io/console'
|
3
|
+
|
4
|
+
Dir[File.dirname(__FILE__) + "/**/*.rb"].each { |f| require f }
|
5
|
+
|
6
|
+
module Snek
|
7
|
+
class Game
|
8
|
+
def initialize(head:)
|
9
|
+
@food = @local_food_position = random_position
|
10
|
+
@random_number = rand
|
11
|
+
@messages = {}
|
12
|
+
@other_sneks = {}
|
13
|
+
@food_positions = {}
|
14
|
+
@food_eaten_counts = {}
|
15
|
+
@food_eaten_count = 0
|
16
|
+
@head = head
|
17
|
+
end
|
18
|
+
|
19
|
+
def start
|
20
|
+
GameEngine::Sound.play 'startup.wav'
|
21
|
+
|
22
|
+
@network = GameEngine::Network.new logger: logger
|
23
|
+
@network.open_socket
|
24
|
+
|
25
|
+
reset_snek
|
26
|
+
|
27
|
+
GameEngine::Frame.setup
|
28
|
+
|
29
|
+
GameEngine::Engine.tick do |tick|
|
30
|
+
@tick = tick
|
31
|
+
|
32
|
+
render
|
33
|
+
update_network
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_reader :frame
|
40
|
+
|
41
|
+
def update_network
|
42
|
+
@network.receive_updates do |data|
|
43
|
+
hostname = data[:hostname]
|
44
|
+
unless hostname == @network.hostname
|
45
|
+
@other_sneks[hostname] = {
|
46
|
+
snek: unpack_snek(data[:snek]),
|
47
|
+
head: data[:head],
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
update_food_positions(data[:random_number], data[:food_position], data[:food_eaten_count])
|
52
|
+
end
|
53
|
+
@network.send_update(
|
54
|
+
snek: pack_snek(@snek),
|
55
|
+
random_number: @random_number,
|
56
|
+
food_position: @local_food_position,
|
57
|
+
food_eaten_count: @food_eaten_count,
|
58
|
+
head: @head,
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
def update_food_positions(id, value, food_eaten_count)
|
63
|
+
cached_food_eaten_count = @food_eaten_counts[id]
|
64
|
+
|
65
|
+
if cached_food_eaten_count != food_eaten_count
|
66
|
+
if id != @random_number
|
67
|
+
@local_food_position = random_position
|
68
|
+
end
|
69
|
+
@food_eaten_counts[id] = food_eaten_count
|
70
|
+
end
|
71
|
+
|
72
|
+
@food_positions[id] = value
|
73
|
+
@food = max_remote_food_position
|
74
|
+
end
|
75
|
+
|
76
|
+
def pack_snek(snek)
|
77
|
+
snek.flatten.join(',')
|
78
|
+
end
|
79
|
+
|
80
|
+
def unpack_snek(snek)
|
81
|
+
snek.split(',').map(&:to_i).each_slice(2).to_a
|
82
|
+
end
|
83
|
+
|
84
|
+
def rows
|
85
|
+
GameEngine::Window.rows
|
86
|
+
25
|
87
|
+
end
|
88
|
+
|
89
|
+
def columns
|
90
|
+
GameEngine::Window.columns
|
91
|
+
80
|
92
|
+
end
|
93
|
+
|
94
|
+
def render
|
95
|
+
@frame = GameEngine::Frame.new columns, rows + 10
|
96
|
+
|
97
|
+
if @tick % 2 == 0 || %w[e w].include?(@snek.direction)
|
98
|
+
new_position = move_snek
|
99
|
+
|
100
|
+
border = draw_border
|
101
|
+
draw_messages
|
102
|
+
draw_sneks
|
103
|
+
draw_food
|
104
|
+
draw_scores
|
105
|
+
|
106
|
+
check_border_collision(border, new_position)
|
107
|
+
check_food_collision(new_position)
|
108
|
+
|
109
|
+
GameEngine::Input.call do |key|
|
110
|
+
if key
|
111
|
+
return if @tick == @input_in_tick
|
112
|
+
@input_in_tick = @tick
|
113
|
+
end
|
114
|
+
|
115
|
+
head = @snek.last
|
116
|
+
|
117
|
+
case key
|
118
|
+
when 'q'.ord, 27, 3 # escape, ctrl-c
|
119
|
+
exit
|
120
|
+
when 119 # W up
|
121
|
+
@snek.direction = 'n' if @snek.direction != 's'
|
122
|
+
when 115 # S down
|
123
|
+
@snek.direction = 's' if @snek.direction != 'n'
|
124
|
+
when 100 # D right
|
125
|
+
@snek.direction = 'e' if @snek.direction != 'w'
|
126
|
+
when 97 # A left
|
127
|
+
@snek.direction = 'w' if @snek.direction != 'e'
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
frame.render
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def check_border_collision(border, new_position)
|
136
|
+
if border.include?(new_position)
|
137
|
+
crash_snek
|
138
|
+
add_message 'you crashed into a wall'
|
139
|
+
return
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def check_food_collision(new_position)
|
144
|
+
if @food == new_position
|
145
|
+
GameEngine::Sound.play 'pickup.wav'
|
146
|
+
@snek.snek_length += 1
|
147
|
+
@local_food_position = random_position
|
148
|
+
@food_eaten_count += 1
|
149
|
+
|
150
|
+
update_food_positions(@random_number, @local_food_position, @food_eaten_count)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def max_remote_food_position
|
155
|
+
@food_positions.max_by { |k, v| k }.last
|
156
|
+
end
|
157
|
+
|
158
|
+
# TODO: non-conflicting
|
159
|
+
def random_position
|
160
|
+
x = (1..columns-2).to_a.sample
|
161
|
+
y = (1..rows-2).to_a.sample
|
162
|
+
|
163
|
+
[x,y]
|
164
|
+
end
|
165
|
+
|
166
|
+
def draw_border
|
167
|
+
frame.draw 0, 0, "+#{'-' * (columns-2)}+"
|
168
|
+
(1..rows-2).each do |y|
|
169
|
+
frame.draw 0, y, '|'
|
170
|
+
frame.draw columns-1, y, '|'
|
171
|
+
end
|
172
|
+
frame.draw 0, rows-1, "+#{'-' * (columns-2)}+"
|
173
|
+
|
174
|
+
border = []
|
175
|
+
border << (0..columns-1).map { |x| [x, 0] }
|
176
|
+
border << (0..rows-1).map { |y| [0, y] }
|
177
|
+
border << (0..rows-1).map { |y| [columns-1, y] }
|
178
|
+
border << (0..columns-1).map { |x| [x, rows-1] }
|
179
|
+
border.flatten(1)
|
180
|
+
end
|
181
|
+
|
182
|
+
def draw_sneks
|
183
|
+
draw_snek @snek, head: (@head || '@')
|
184
|
+
|
185
|
+
@other_sneks.values.each do |snek|
|
186
|
+
draw_snek snek[:snek], head: (snek[:head] || '&')
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def draw_snek(snek, head:)
|
191
|
+
head = head[0]
|
192
|
+
snek.each_with_index do |segment, index|
|
193
|
+
char = index == snek.count-1 ? head : '*'
|
194
|
+
frame.draw *segment, char
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def draw_food
|
199
|
+
frame.draw *@food, '$'
|
200
|
+
end
|
201
|
+
|
202
|
+
def draw_scores
|
203
|
+
draw_score (@head || '@'), @network.hostname, @snek.length, rows
|
204
|
+
|
205
|
+
@other_sneks.each_with_index do |data, i|
|
206
|
+
hostname, snek = data
|
207
|
+
head = snek[:head] || '&'
|
208
|
+
draw_score(head, hostname, snek[:snek].length, rows + i + 1)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def draw_score(head, name, score, position)
|
213
|
+
frame.draw 0, position, "#{head[0]} #{score} #{name}"
|
214
|
+
end
|
215
|
+
|
216
|
+
def move_snek
|
217
|
+
x, y = @snek.last
|
218
|
+
|
219
|
+
new_position = case @snek.direction
|
220
|
+
when 'n'
|
221
|
+
[x, y - 1]
|
222
|
+
when 's'
|
223
|
+
[x, y + 1]
|
224
|
+
when 'e'
|
225
|
+
[x + 1, y]
|
226
|
+
when 'w'
|
227
|
+
[x - 1, y]
|
228
|
+
end
|
229
|
+
|
230
|
+
if @snek.include?(new_position)
|
231
|
+
crash_snek
|
232
|
+
add_message 'you crashed into yourself'
|
233
|
+
return
|
234
|
+
end
|
235
|
+
|
236
|
+
@other_sneks.each do |hostname, snek|
|
237
|
+
if snek[:snek].include?(new_position)
|
238
|
+
crash_snek
|
239
|
+
add_message "you crashed into #{hostname}"
|
240
|
+
return
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
@snek << new_position
|
245
|
+
new_position
|
246
|
+
end
|
247
|
+
|
248
|
+
def logger
|
249
|
+
@logger ||= Logger.new('snek.log').tap do |logger|
|
250
|
+
logger.formatter = lambda do |severity, datetime, progname, msg|
|
251
|
+
"[#{severity}] #{datetime.strftime('%M:%S')}: #{msg}\n"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def reset_snek
|
257
|
+
@snek = Snek.new([random_position])
|
258
|
+
end
|
259
|
+
|
260
|
+
def add_message(message)
|
261
|
+
@messages[message] = @tick + 10
|
262
|
+
end
|
263
|
+
|
264
|
+
def draw_messages
|
265
|
+
@messages.each do |message, end_tick|
|
266
|
+
if @tick < end_tick
|
267
|
+
frame.draw_center rows/2, message
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def crash_snek
|
273
|
+
GameEngine::Sound.play 'explosion.wav'
|
274
|
+
reset_snek
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module GameEngine
|
2
|
+
class Engine
|
3
|
+
attr_accessor :tick
|
4
|
+
|
5
|
+
def self.tick(&block)
|
6
|
+
self.new(&block).tap(&:call)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(&block)
|
10
|
+
@tick = 0
|
11
|
+
@block = block
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
loop do
|
16
|
+
@block.call @tick
|
17
|
+
@tick += 1
|
18
|
+
sleep 0.1
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module GameEngine
|
2
|
+
class Frame
|
3
|
+
attr_reader :rows
|
4
|
+
|
5
|
+
def initialize(width, height)
|
6
|
+
@rows = height.times.map { ' ' * width }
|
7
|
+
end
|
8
|
+
|
9
|
+
def width
|
10
|
+
@rows.first.size
|
11
|
+
end
|
12
|
+
|
13
|
+
def height
|
14
|
+
@rows.size
|
15
|
+
end
|
16
|
+
|
17
|
+
def draw(x, y, sprite)
|
18
|
+
lines = sprite.split("\n")
|
19
|
+
|
20
|
+
lines.each_with_index do |line, i|
|
21
|
+
if line.size > 0 && y+lines.size <= self.height && y+i >= 0
|
22
|
+
# crop when drawing off left
|
23
|
+
if x < 0
|
24
|
+
line = line[x.abs..-1]
|
25
|
+
x = 0
|
26
|
+
end
|
27
|
+
|
28
|
+
# crop when drawing off right
|
29
|
+
if x+line.size-1 >= self.width
|
30
|
+
line = line[0..(self.width-1)-(x+line.size)]
|
31
|
+
end
|
32
|
+
|
33
|
+
@rows[y+i][x..x+line.size-1] = line
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def draw_center(y, sprite)
|
39
|
+
sprite_width = sprite.split("\n").first.size
|
40
|
+
x = self.width / 2 - sprite_width / 2
|
41
|
+
draw x, y, sprite
|
42
|
+
end
|
43
|
+
|
44
|
+
def render
|
45
|
+
@rows.each_with_index do |row, i|
|
46
|
+
Frame.move_cursor 0, i
|
47
|
+
print row
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.move_cursor(x, y)
|
52
|
+
print "\033[#{y+1};#{x+1}H"
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.clear_screen
|
56
|
+
print "\033[2J"
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.disable_cursor
|
60
|
+
print "\x1B[?25l"
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.enable_cursor
|
64
|
+
print "\x1B[?25h"
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.setup
|
68
|
+
clear_screen
|
69
|
+
disable_cursor
|
70
|
+
|
71
|
+
$stdin.raw!
|
72
|
+
at_exit do
|
73
|
+
puts "\r"
|
74
|
+
enable_cursor
|
75
|
+
$stdin.cooked!
|
76
|
+
system 'stty sane'
|
77
|
+
end
|
78
|
+
|
79
|
+
trap 'WINCH' do
|
80
|
+
clear_screen
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'socket'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module GameEngine
|
6
|
+
class Network
|
7
|
+
PORT = 47357
|
8
|
+
|
9
|
+
attr_reader :logger
|
10
|
+
|
11
|
+
def initialize(logger: Logger.new('/dev/null'))
|
12
|
+
@logger = logger
|
13
|
+
end
|
14
|
+
|
15
|
+
def open_socket
|
16
|
+
@socket = UDPSocket.new
|
17
|
+
@socket.bind '0.0.0.0', PORT
|
18
|
+
@socket.setsockopt Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true
|
19
|
+
@socket.setsockopt Socket::SOL_SOCKET, Socket::SO_BROADCAST, true
|
20
|
+
rescue Errno::EADDRINUSE
|
21
|
+
$stderr.puts "Game is already running."
|
22
|
+
exit 1
|
23
|
+
end
|
24
|
+
|
25
|
+
def receive_updates(&block)
|
26
|
+
loop do
|
27
|
+
begin
|
28
|
+
data, addr = @socket.recvfrom_nonblock 8192
|
29
|
+
data = YAML.load(data)
|
30
|
+
block.call(data)
|
31
|
+
rescue Psych::SyntaxError => error
|
32
|
+
logger.error error
|
33
|
+
end
|
34
|
+
end
|
35
|
+
rescue Errno::EAGAIN
|
36
|
+
end
|
37
|
+
|
38
|
+
def send_update(data)
|
39
|
+
data = data.merge(hostname: hostname)
|
40
|
+
|
41
|
+
begin
|
42
|
+
@socket.send data.to_yaml, 0, '255.255.255.255', PORT
|
43
|
+
rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH, Errno::EMSGSIZE, Errno::ENETDOWN => error
|
44
|
+
logger.error error
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def hostname
|
49
|
+
@hostname ||= `hostname -s`.strip
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module GameEngine
|
2
|
+
class Sound
|
3
|
+
def self.play(sound)
|
4
|
+
case RUBY_PLATFORM
|
5
|
+
when /darwin/
|
6
|
+
system "afplay assets/sounds/#{sound} &"
|
7
|
+
when /linux/
|
8
|
+
system "command -v mplayer >/dev/null 2>&1 && mplayer -msglevel all=-1 -nolirc assets/sounds/#{sound} &"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/snek.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'snek/version'
|
2
|
+
|
3
|
+
module Snek
|
4
|
+
class Snek < Array
|
5
|
+
DIRECTIONS = %w[n s e w]
|
6
|
+
|
7
|
+
attr_accessor :snek_length, :direction
|
8
|
+
|
9
|
+
def initialize(*args)
|
10
|
+
@snek_length = 5
|
11
|
+
@direction = random_direction
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def <<(*args)
|
16
|
+
shift if count >= snek_length
|
17
|
+
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
alias_method :orig_inspect, :inspect
|
22
|
+
def inspect
|
23
|
+
"#<Snek @snek_length=#{@snek_length.inspect} self=#{orig_inspect.inspect}>"
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def random_direction
|
29
|
+
DIRECTIONS.sample
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/snek/version.rb
ADDED
data/snek.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
#: coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'snek/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'snek'
|
8
|
+
spec.version = Snek::VERSION
|
9
|
+
spec.authors = ['Odin Dutton']
|
10
|
+
spec.email = ['odindutton@gmail.com']
|
11
|
+
|
12
|
+
spec.summary = 'Terminal multiplayer snek game made at Railscamp 19, Adelaide'
|
13
|
+
spec.homepage = 'https://github.com/twe4ked/snek'
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
16
|
+
spec.bindir = 'bin'
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.add_development_dependency 'bundler', '~> 1.10'
|
21
|
+
spec.add_development_dependency 'rake', '~> 11.0'
|
22
|
+
spec.add_development_dependency 'rspec'
|
23
|
+
spec.add_development_dependency 'pry'
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: snek
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Odin Dutton
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-07-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.10'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.10'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '11.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '11.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description:
|
70
|
+
email:
|
71
|
+
- odindutton@gmail.com
|
72
|
+
executables:
|
73
|
+
- snek
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- Gemfile
|
79
|
+
- Gemfile.lock
|
80
|
+
- README.markdown
|
81
|
+
- Rakefile
|
82
|
+
- assets/sounds/explosion.wav
|
83
|
+
- assets/sounds/pickup.wav
|
84
|
+
- assets/sounds/startup.wav
|
85
|
+
- bin/snek
|
86
|
+
- lib/game.rb
|
87
|
+
- lib/game_engine/engine.rb
|
88
|
+
- lib/game_engine/frame.rb
|
89
|
+
- lib/game_engine/input.rb
|
90
|
+
- lib/game_engine/network.rb
|
91
|
+
- lib/game_engine/sound.rb
|
92
|
+
- lib/game_engine/window.rb
|
93
|
+
- lib/snek.rb
|
94
|
+
- lib/snek/version.rb
|
95
|
+
- snek.gemspec
|
96
|
+
homepage: https://github.com/twe4ked/snek
|
97
|
+
licenses: []
|
98
|
+
metadata: {}
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
requirements: []
|
114
|
+
rubyforge_project:
|
115
|
+
rubygems_version: 2.4.5
|
116
|
+
signing_key:
|
117
|
+
specification_version: 4
|
118
|
+
summary: Terminal multiplayer snek game made at Railscamp 19, Adelaide
|
119
|
+
test_files: []
|