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 ADDED
@@ -0,0 +1,2 @@
1
+ require 'ruby-snake'
2
+ Game.new.start
data/lib/ruby-snake.rb ADDED
@@ -0,0 +1,3 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/ruby-snake'
2
+ require 'snake'
3
+ require 'game'
@@ -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: []