ruby-snake 0.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/bin/ruby-snake +2 -0
- data/lib/ruby-snake.rb +3 -0
- data/lib/ruby-snake/game.rb +137 -0
- data/lib/ruby-snake/snake.rb +90 -0
- metadata +66 -0
data/bin/ruby-snake
ADDED
data/lib/ruby-snake.rb
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
class Game
|
|
2
|
+
|
|
3
|
+
require 'curses'
|
|
4
|
+
|
|
5
|
+
TOP = 0
|
|
6
|
+
BOTTOM = 22
|
|
7
|
+
LEFT = 0
|
|
8
|
+
RIGHT = 70
|
|
9
|
+
|
|
10
|
+
include Curses
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
Curses.init_screen
|
|
14
|
+
|
|
15
|
+
Curses.noecho # Don't show typed key.
|
|
16
|
+
Curses.stdscr.keypad(true)
|
|
17
|
+
|
|
18
|
+
# colors
|
|
19
|
+
Curses.start_color
|
|
20
|
+
Curses.init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_BLUE) # Color of boders
|
|
21
|
+
Curses.init_pair(COLOR_RED, COLOR_RED, COLOR_RED)
|
|
22
|
+
Curses.init_pair(COLOR_BLACK, COLOR_BLACK, COLOR_BLACK)
|
|
23
|
+
Curses.init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_YELLOW)
|
|
24
|
+
|
|
25
|
+
setup
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def start
|
|
29
|
+
# Create a thread to montior key events
|
|
30
|
+
key_listener = Thread.new do
|
|
31
|
+
loop {Thread.current[:key] = Curses.getch}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
while true
|
|
35
|
+
handle_key key_listener[:key]
|
|
36
|
+
if !@pause
|
|
37
|
+
|
|
38
|
+
if @dead_snake # erase dead snake
|
|
39
|
+
@dead_snake.body.each {|pos| erase pos}
|
|
40
|
+
erase @dead_snake.food
|
|
41
|
+
@dead_snake = false
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
tail = @snake.goto @direction
|
|
45
|
+
|
|
46
|
+
if @snake.alive?
|
|
47
|
+
draw_snake
|
|
48
|
+
draw_food
|
|
49
|
+
erase tail
|
|
50
|
+
@speed += 1 if @snake.score / 100 > @speed - 1
|
|
51
|
+
else
|
|
52
|
+
@dead_snake = @snake.dup
|
|
53
|
+
setup
|
|
54
|
+
@message = "You die! Press 'S' to restart the game."
|
|
55
|
+
@pause = true
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
draw_ui
|
|
59
|
+
Curses.refresh
|
|
60
|
+
sleep(0.2 * (0.8 ** (@speed - 1)))
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def setup
|
|
70
|
+
@snake = Snake.new(RIGHT / 2 - 1, BOTTOM - 1)
|
|
71
|
+
@score = 0
|
|
72
|
+
@speed = 1
|
|
73
|
+
@pause = false
|
|
74
|
+
@direction = Snake::RIGHT
|
|
75
|
+
@message = "Press 'P' to pause, Press 'Q' to quit."
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def draw_ui
|
|
79
|
+
# top border
|
|
80
|
+
Curses.setpos(TOP, LEFT)
|
|
81
|
+
Curses.attron(color_pair(COLOR_BLUE)|A_NORMAL) {Curses.addstr(' ' * RIGHT)}
|
|
82
|
+
# bottom border
|
|
83
|
+
Curses.setpos(BOTTOM, LEFT)
|
|
84
|
+
Curses.attron(color_pair(COLOR_BLUE)|A_NORMAL) {Curses.addstr(' ' * RIGHT)}
|
|
85
|
+
Curses.addstr(' ' * RIGHT)
|
|
86
|
+
# left boder & right boder
|
|
87
|
+
Curses.attron(color_pair(COLOR_BLUE)|A_NORMAL) do
|
|
88
|
+
TOP.upto(BOTTOM) do |i|
|
|
89
|
+
Curses.setpos(i, LEFT); Curses.addstr " "
|
|
90
|
+
Curses.setpos(i, RIGHT); Curses.addstr " "
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
Curses.setpos(BOTTOM + 1, LEFT)
|
|
94
|
+
Curses.addstr("Score: #{@snake.score} Speed: #{@speed}, #{@message}.")
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def draw_snake
|
|
98
|
+
@snake.body.each do |pos|
|
|
99
|
+
Curses.setpos(pos.y, (pos.x - 1) * 2)
|
|
100
|
+
Curses.attron(color_pair(COLOR_RED)|A_NORMAL) {Curses.addstr " "}
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def draw_food
|
|
105
|
+
Curses.setpos(@snake.food.y, (@snake.food.x - 1) * 2)
|
|
106
|
+
Curses.attron(color_pair(COLOR_YELLOW)|A_NORMAL) {Curses.addstr " "}
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def erase pos
|
|
110
|
+
Curses.setpos(pos.y, (pos.x - 1) * 2)
|
|
111
|
+
Curses.attron(color_pair(COLOR_BLACK)|A_NORMAL) {Curses.addstr " "}
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def handle_key key
|
|
115
|
+
case key
|
|
116
|
+
when 'q', 'Q'
|
|
117
|
+
exit
|
|
118
|
+
when 'p', 'P'
|
|
119
|
+
@message = "Press 'S' to start, Press 'Q' to quit."
|
|
120
|
+
@pause = true
|
|
121
|
+
draw_ui
|
|
122
|
+
Curses.refresh
|
|
123
|
+
when 's', 'S'
|
|
124
|
+
@message = "Press 'P' to pause, Press 'Q' to quit."
|
|
125
|
+
@pause = false
|
|
126
|
+
when Curses::Key::UP
|
|
127
|
+
@direction = Snake::UP
|
|
128
|
+
when Curses::Key::DOWN
|
|
129
|
+
@direction = Snake::DOWN
|
|
130
|
+
when Curses::Key::LEFT
|
|
131
|
+
@direction = Snake::LEFT
|
|
132
|
+
when Curses::Key::RIGHT
|
|
133
|
+
@direction = Snake::RIGHT
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
class Snake
|
|
2
|
+
|
|
3
|
+
# Direction:
|
|
4
|
+
UP = 0
|
|
5
|
+
RIGHT = 1
|
|
6
|
+
DOWN = 2
|
|
7
|
+
LEFT = 3
|
|
8
|
+
|
|
9
|
+
attr_reader :body, :food, :score
|
|
10
|
+
|
|
11
|
+
def initialize width, height, length = 5
|
|
12
|
+
@body = []
|
|
13
|
+
@direction = RIGHT
|
|
14
|
+
length.times do |i|
|
|
15
|
+
@body << Pos.new(length - i + 1, height)
|
|
16
|
+
end
|
|
17
|
+
@width, @height = width, height
|
|
18
|
+
@food = make_food
|
|
19
|
+
@wall = []
|
|
20
|
+
0.upto(width) do |i|
|
|
21
|
+
@wall << Pos.new(i, 0)
|
|
22
|
+
@wall << Pos.new(i, height + 1)
|
|
23
|
+
end
|
|
24
|
+
1.upto(height - 1) do |j|
|
|
25
|
+
@wall << Pos.new(0, j)
|
|
26
|
+
@wall << Pos.new(width + 1, j)
|
|
27
|
+
end
|
|
28
|
+
@alive = true
|
|
29
|
+
@score = 0
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def make_food
|
|
33
|
+
food = Pos.new(rand(@width - 2) + 2, rand(@height - 1) + 1)
|
|
34
|
+
while @body.include?(food)
|
|
35
|
+
food = Pos.new(rand(@width - 2) + 2, rand(@height - 1) + 1)
|
|
36
|
+
end
|
|
37
|
+
food
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def goto direction
|
|
41
|
+
n_pos = next_pos direction
|
|
42
|
+
tail = @body.last
|
|
43
|
+
case
|
|
44
|
+
when @wall.include?(n_pos) || @body.include?(n_pos)
|
|
45
|
+
@alive = false
|
|
46
|
+
when n_pos == @food
|
|
47
|
+
eat n_pos
|
|
48
|
+
else
|
|
49
|
+
move n_pos
|
|
50
|
+
end
|
|
51
|
+
tail # when the snake moves, the UI class could know which cell should be erased.
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def alive?
|
|
55
|
+
@alive
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def next_pos direction
|
|
59
|
+
if [[RIGHT, LEFT], [UP, DOWN]].include? [direction, @direction].sort
|
|
60
|
+
direction = @direction
|
|
61
|
+
else
|
|
62
|
+
@direction = direction
|
|
63
|
+
end
|
|
64
|
+
head = @body[0]
|
|
65
|
+
case direction
|
|
66
|
+
when UP
|
|
67
|
+
Pos.new(head.x, head.y - 1)
|
|
68
|
+
when DOWN
|
|
69
|
+
Pos.new(head.x, head.y + 1)
|
|
70
|
+
when RIGHT
|
|
71
|
+
Pos.new(head.x + 1, head.y)
|
|
72
|
+
when LEFT
|
|
73
|
+
Pos.new(head.x - 1, head.y)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def move pos
|
|
78
|
+
@body.unshift pos
|
|
79
|
+
@body.pop
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def eat pos
|
|
83
|
+
@body.unshift pos
|
|
84
|
+
@food = make_food
|
|
85
|
+
@score += 10
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
Pos = Struct.new :x, :y
|
|
89
|
+
|
|
90
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ruby-snake
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Zhang Kang
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2014-02-07 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: curses
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ! '>='
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '0'
|
|
22
|
+
type: :development
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ! '>='
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '0'
|
|
30
|
+
description: Writed by Ruby, Curses.
|
|
31
|
+
email: piecehealth@sina.com
|
|
32
|
+
executables:
|
|
33
|
+
- ruby-snake
|
|
34
|
+
extensions: []
|
|
35
|
+
extra_rdoc_files: []
|
|
36
|
+
files:
|
|
37
|
+
- lib/ruby-snake.rb
|
|
38
|
+
- lib/ruby-snake/snake.rb
|
|
39
|
+
- lib/ruby-snake/game.rb
|
|
40
|
+
- bin/ruby-snake
|
|
41
|
+
homepage: https://github.com/piecehealth/snake-game-ruby
|
|
42
|
+
licenses:
|
|
43
|
+
- MIT
|
|
44
|
+
post_install_message:
|
|
45
|
+
rdoc_options: []
|
|
46
|
+
require_paths:
|
|
47
|
+
- lib
|
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
49
|
+
none: false
|
|
50
|
+
requirements:
|
|
51
|
+
- - ! '>='
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
55
|
+
none: false
|
|
56
|
+
requirements:
|
|
57
|
+
- - ! '>='
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: '0'
|
|
60
|
+
requirements: []
|
|
61
|
+
rubyforge_project:
|
|
62
|
+
rubygems_version: 1.8.24
|
|
63
|
+
signing_key:
|
|
64
|
+
specification_version: 3
|
|
65
|
+
summary: Terminal(command line) Snake Game.
|
|
66
|
+
test_files: []
|