rb-snake 0.0.1 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +13 -1
- data/README.md +5 -9
- data/bin/rb-snake +8 -0
- data/lib/rb_snake/actions/change_direction.rb +32 -0
- data/lib/rb_snake/actions/move_snake.rb +35 -0
- data/lib/rb_snake/app.rb +10 -33
- data/lib/rb_snake/models/coordinate.rb +18 -0
- data/lib/rb_snake/models/direction.rb +12 -0
- data/lib/rb_snake/models/food.rb +42 -0
- data/lib/rb_snake/models/grid.rb +14 -0
- data/lib/rb_snake/models/snake.rb +101 -0
- data/lib/rb_snake/models/state.rb +53 -0
- data/lib/rb_snake/version.rb +1 -1
- data/lib/rb_snake/views/window.rb +96 -0
- data/lib/rb_snake.rb +0 -1
- metadata +33 -13
- data/.byebug_history +0 -4
- data/lib/rb_snake/actions/actions.rb +0 -100
- data/lib/rb_snake/model/state.rb +0 -37
- data/lib/rb_snake/view/ruby2d.rb +0 -69
- data/rb-snake.gemspec +0 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 529079a6646e1e0bfc700fa65d4a8fe80d01f85c5e3871790797fe628d5b5a07
|
4
|
+
data.tar.gz: 5eb2921b933580848c2c5a7d7a51127ea1b02d64e36b998704477975978261ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57b85516859d4bf5ba21ad80ced31eb8d7acaef84fb09b3e15a15629b1e7f4dfc155c6c783462608e5cdf8eb2cba944da9d75c4aab35c7242c80e132e5c78f88
|
7
|
+
data.tar.gz: 4a1262d36a8146d3fdf3937ffd0ae8bca0356eefe2e59bbd98d11ba8f5ba251d5e1774a80f2965c3e5ccee0a997514cfd6f534aa33c59fde8035c7d714bbbf75
|
data/.rubocop.yml
CHANGED
@@ -2,7 +2,7 @@ require:
|
|
2
2
|
- rubocop-rspec
|
3
3
|
|
4
4
|
AllCops:
|
5
|
-
TargetRubyVersion:
|
5
|
+
TargetRubyVersion: 2.6.0
|
6
6
|
|
7
7
|
Style/StringLiterals:
|
8
8
|
Enabled: true
|
@@ -14,3 +14,15 @@ Style/StringLiteralsInInterpolation:
|
|
14
14
|
|
15
15
|
Layout/LineLength:
|
16
16
|
Max: 120
|
17
|
+
|
18
|
+
Style/Documentation:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Metrics/MethodLength:
|
22
|
+
Max: 17
|
23
|
+
|
24
|
+
Metrics/ParameterLists:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
RSpec/MultipleMemoizedHelpers:
|
28
|
+
Enabled: false
|
data/README.md
CHANGED
@@ -1,22 +1,18 @@
|
|
1
|
-
#
|
1
|
+
# rb-snake
|
2
2
|
|
3
|
-
|
3
|
+
This is a Ruby adapted version of the Snake classic game, using [Ruby2d](https://www.ruby2d.com) gem
|
4
4
|
|
5
|
-
|
5
|
+
![](https://i.imgur.com/wC6W4VH.png)
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
9
|
-
Install the gem
|
10
|
-
|
11
|
-
$ bundle add rb-snake
|
12
|
-
|
13
|
-
If bundler is not being used to manage dependencies, install the gem by executing:
|
9
|
+
Install the gem
|
14
10
|
|
15
11
|
$ gem install rb-snake
|
16
12
|
|
17
13
|
## Usage
|
18
14
|
|
19
|
-
|
15
|
+
Run `rb-snake` on your terminal to start the game. Use the arrow keys on the keyboard to move the snake. Try to feed your snake as much as possible without hitting your own body!
|
20
16
|
|
21
17
|
## Development
|
22
18
|
|
data/bin/rb-snake
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rb_snake/models/direction"
|
4
|
+
|
5
|
+
module RbSnake
|
6
|
+
module Actions
|
7
|
+
class ChangeDirection
|
8
|
+
class << self
|
9
|
+
def call(state, new_direction:)
|
10
|
+
return unless valid_direction?(state.current_direction, new_direction)
|
11
|
+
|
12
|
+
state.update_direction(new_direction)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def valid_direction?(current_direction, new_direction)
|
18
|
+
case current_direction
|
19
|
+
when RbSnake::Models::Direction::UP
|
20
|
+
!new_direction.eql?(RbSnake::Models::Direction::DOWN)
|
21
|
+
when RbSnake::Models::Direction::DOWN
|
22
|
+
!new_direction.eql?(RbSnake::Models::Direction::UP)
|
23
|
+
when RbSnake::Models::Direction::LEFT
|
24
|
+
!new_direction.eql?(RbSnake::Models::Direction::RIGHT)
|
25
|
+
when RbSnake::Models::Direction::RIGHT
|
26
|
+
!new_direction.eql?(RbSnake::Models::Direction::LEFT)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RbSnake
|
4
|
+
module Actions
|
5
|
+
class MoveSnake
|
6
|
+
class << self
|
7
|
+
def call(state, window)
|
8
|
+
snake = state.snake
|
9
|
+
current_direction = state.current_direction
|
10
|
+
food = state.food
|
11
|
+
grid = state.grid
|
12
|
+
|
13
|
+
make_next_move(snake, current_direction, food, grid, state)
|
14
|
+
|
15
|
+
window.render(state)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def make_next_move(snake, current_direction, food, grid, state)
|
21
|
+
next_position = snake.next_position(current_direction, grid)
|
22
|
+
if next_position.eql?(food.location)
|
23
|
+
snake.eat(food)
|
24
|
+
food.regenerate(snake, grid)
|
25
|
+
state.increase_speed if (snake.body.length % 10).zero?
|
26
|
+
elsif snake.body.any? { |body_pos| body_pos.eql?(next_position) }
|
27
|
+
state.finish_game!
|
28
|
+
else
|
29
|
+
snake.move_to(next_position)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/rb_snake/app.rb
CHANGED
@@ -1,42 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
require_relative 'actions/actions'
|
3
|
+
require "rb_snake/models/state"
|
4
|
+
require "rb_snake/views/window"
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
11
|
-
|
12
|
-
def start
|
13
|
-
@view = View::Ruby2dView.new(self)
|
14
|
-
timer_thread = Thread.new { init_timer(@view) }
|
15
|
-
@view.start(@state)
|
16
|
-
timer_thread.join
|
17
|
-
end
|
6
|
+
module RbSnake
|
7
|
+
class App
|
8
|
+
attr_reader :state, :window
|
18
9
|
|
19
|
-
|
20
|
-
|
21
|
-
if @state.game_finished
|
22
|
-
puts 'Juego Finalizado'
|
23
|
-
puts "Puntaje: #{@state.snake.positions.length}"
|
24
|
-
break
|
25
|
-
end
|
26
|
-
@state = Actions::move_snake(@state)
|
27
|
-
view.render(@state)
|
28
|
-
sleep 0.1
|
10
|
+
def initialize
|
11
|
+
@state = Models::State.initial_state
|
29
12
|
end
|
30
|
-
end
|
31
13
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
@state = new_state
|
36
|
-
@view.render(@state)
|
14
|
+
def start
|
15
|
+
@window = Views::Window.new
|
16
|
+
window.start(state)
|
37
17
|
end
|
38
18
|
end
|
39
19
|
end
|
40
|
-
|
41
|
-
app = App.new
|
42
|
-
app.start
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RbSnake
|
4
|
+
module Models
|
5
|
+
class Coordinate
|
6
|
+
attr_accessor :row, :col
|
7
|
+
|
8
|
+
def initialize(row:, col:)
|
9
|
+
@row = row
|
10
|
+
@col = col
|
11
|
+
end
|
12
|
+
|
13
|
+
def eql?(other)
|
14
|
+
row == other.row && col == other.col
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rb_snake/models/coordinate"
|
4
|
+
|
5
|
+
module RbSnake
|
6
|
+
module Models
|
7
|
+
class Food
|
8
|
+
attr_reader :location
|
9
|
+
|
10
|
+
RenderedElement = Struct.new(:elem, :location)
|
11
|
+
|
12
|
+
def initialize(row:, col:)
|
13
|
+
@location = Coordinate.new(row: row, col: col)
|
14
|
+
end
|
15
|
+
|
16
|
+
def render(window)
|
17
|
+
return if rendered_element&.location == location
|
18
|
+
|
19
|
+
window.remove(rendered_element.elem) if rendered_element
|
20
|
+
|
21
|
+
elem = yield(location.row, location.col)
|
22
|
+
@rendered_element = RenderedElement.new(elem, location)
|
23
|
+
end
|
24
|
+
|
25
|
+
def regenerate(snake, grid)
|
26
|
+
loop do
|
27
|
+
new_row = rand(0...grid.rows)
|
28
|
+
new_col = rand(0...grid.cols)
|
29
|
+
|
30
|
+
if snake.body.none? { |position| position.row == new_row && position.col == new_col }
|
31
|
+
@location = Coordinate.new(row: new_row, col: new_col)
|
32
|
+
break
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_reader :rendered_element
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rb_snake/models/direction"
|
4
|
+
require "rb_snake/models/coordinate"
|
5
|
+
|
6
|
+
module RbSnake
|
7
|
+
module Models
|
8
|
+
class Snake
|
9
|
+
RenderedBodyElem = Struct.new(:elem, :position)
|
10
|
+
|
11
|
+
attr_reader :body
|
12
|
+
|
13
|
+
def initialize(body:)
|
14
|
+
@body = body
|
15
|
+
end
|
16
|
+
|
17
|
+
def render(window, &block)
|
18
|
+
return build_rendered_body(&block) if rendered_body.nil?
|
19
|
+
|
20
|
+
update_last_rendered_position(window)
|
21
|
+
update_first_rendered_position(&block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def next_position(direction, grid)
|
25
|
+
new_row = head.row
|
26
|
+
new_col = head.col
|
27
|
+
|
28
|
+
case direction
|
29
|
+
when Direction::UP
|
30
|
+
new_row -= 1
|
31
|
+
when Direction::RIGHT
|
32
|
+
new_col += 1
|
33
|
+
when Direction::DOWN
|
34
|
+
new_row += 1
|
35
|
+
when Direction::LEFT
|
36
|
+
new_col -= 1
|
37
|
+
else
|
38
|
+
raise StandardError, "direction #{direction} not recognized"
|
39
|
+
end
|
40
|
+
|
41
|
+
new_row = truncate_row(new_row, grid)
|
42
|
+
new_col = truncate_col(new_col, grid)
|
43
|
+
|
44
|
+
Coordinate.new(row: new_row, col: new_col)
|
45
|
+
end
|
46
|
+
|
47
|
+
def eat(food)
|
48
|
+
body.unshift(food.location)
|
49
|
+
end
|
50
|
+
|
51
|
+
def move_to(position)
|
52
|
+
body.unshift(position)
|
53
|
+
body.pop
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def head
|
59
|
+
body.first
|
60
|
+
end
|
61
|
+
|
62
|
+
def build_rendered_body(&block)
|
63
|
+
@rendered_body = body.map do |position|
|
64
|
+
elem = block.call(position.row, position.col)
|
65
|
+
RenderedBodyElem.new(elem, position)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def update_last_rendered_position(window)
|
70
|
+
return if rendered_body.last.position == body.last
|
71
|
+
|
72
|
+
window.remove(rendered_body.last.elem)
|
73
|
+
rendered_body.pop
|
74
|
+
end
|
75
|
+
|
76
|
+
def update_first_rendered_position(&block)
|
77
|
+
return if rendered_body.first.position == body.first
|
78
|
+
|
79
|
+
new_position = body.first
|
80
|
+
elem = block.call(new_position.row, new_position.col)
|
81
|
+
rendered_body.unshift(RenderedBodyElem.new(elem, new_position))
|
82
|
+
end
|
83
|
+
|
84
|
+
def truncate_row(new_row, grid)
|
85
|
+
return 0 if new_row >= grid.rows
|
86
|
+
return grid.rows - 1 if new_row.negative?
|
87
|
+
|
88
|
+
new_row
|
89
|
+
end
|
90
|
+
|
91
|
+
def truncate_col(new_col, grid)
|
92
|
+
return 0 if new_col >= grid.cols
|
93
|
+
return grid.cols - 1 if new_col.negative?
|
94
|
+
|
95
|
+
new_col
|
96
|
+
end
|
97
|
+
|
98
|
+
attr_reader :rendered_body
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rb_snake/models/coordinate"
|
4
|
+
require "rb_snake/models/snake"
|
5
|
+
require "rb_snake/models/food"
|
6
|
+
require "rb_snake/models/grid"
|
7
|
+
require "rb_snake/models/direction"
|
8
|
+
|
9
|
+
module RbSnake
|
10
|
+
module Models
|
11
|
+
class State
|
12
|
+
attr_reader :snake, :food, :grid, :current_direction, :game_finished, :speed_factor
|
13
|
+
|
14
|
+
def initialize(snake:, food:, grid:, current_direction:, game_finished:, speed_factor:)
|
15
|
+
@snake = snake
|
16
|
+
@food = food
|
17
|
+
@grid = grid
|
18
|
+
@current_direction = current_direction
|
19
|
+
@game_finished = game_finished
|
20
|
+
@speed_factor = speed_factor
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.initial_state
|
24
|
+
new(
|
25
|
+
snake: Snake.new(
|
26
|
+
body: [Coordinate.new(row: 1, col: 1), Coordinate.new(row: 0, col: 1)]
|
27
|
+
),
|
28
|
+
food: Food.new(row: 10, col: 1),
|
29
|
+
grid: Grid.new(rows: 12, cols: 24),
|
30
|
+
current_direction: Direction::DOWN,
|
31
|
+
game_finished: false,
|
32
|
+
speed_factor: 6
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def finish_game!
|
37
|
+
@game_finished = true
|
38
|
+
end
|
39
|
+
|
40
|
+
def game_score
|
41
|
+
snake.body.length
|
42
|
+
end
|
43
|
+
|
44
|
+
def update_direction(new_direction)
|
45
|
+
@current_direction = new_direction
|
46
|
+
end
|
47
|
+
|
48
|
+
def increase_speed
|
49
|
+
@speed_factor = [speed_factor - 1, 1].max # the lower, the faster
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/rb_snake/version.rb
CHANGED
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ruby2d"
|
4
|
+
require "rb_snake/models/direction"
|
5
|
+
require "rb_snake/actions/move_snake"
|
6
|
+
require "rb_snake/actions/change_direction"
|
7
|
+
|
8
|
+
module RbSnake
|
9
|
+
module Views
|
10
|
+
class Window
|
11
|
+
PIXEL_SIZE = 50
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@ruby2d_window = Ruby2D::Window.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def start(state)
|
18
|
+
setup_window(state.grid)
|
19
|
+
add_key_listener(state)
|
20
|
+
render_on_each_frame(state)
|
21
|
+
|
22
|
+
ruby2d_window.show
|
23
|
+
end
|
24
|
+
|
25
|
+
def render(state)
|
26
|
+
state.food.render(ruby2d_window) do |row, col|
|
27
|
+
render_square(row: row, col: col, color: "yellow")
|
28
|
+
end
|
29
|
+
|
30
|
+
state.snake.render(ruby2d_window) do |row, col|
|
31
|
+
render_square(row: row, col: col, color: "green")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
attr_reader :ruby2d_window
|
38
|
+
|
39
|
+
def setup_window(grid)
|
40
|
+
ruby2d_window.set(
|
41
|
+
title: "Snake",
|
42
|
+
width: PIXEL_SIZE * grid.cols,
|
43
|
+
height: PIXEL_SIZE * grid.rows
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_key_listener(state)
|
48
|
+
ruby2d_window.on :key_down do |event|
|
49
|
+
handle_key_event(event, state)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def render_on_each_frame(state)
|
54
|
+
tick = 0
|
55
|
+
|
56
|
+
ruby2d_window.update do
|
57
|
+
Actions::MoveSnake.call(state, self) if (tick % state.speed_factor).zero?
|
58
|
+
|
59
|
+
if state.game_finished
|
60
|
+
ruby2d_window.close
|
61
|
+
|
62
|
+
puts "Game Over"
|
63
|
+
puts "Score: #{state.game_score}"
|
64
|
+
end
|
65
|
+
|
66
|
+
tick += 1
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def render_square(row:, col:, color:)
|
71
|
+
square = Ruby2D::Square.new(
|
72
|
+
x: col * PIXEL_SIZE,
|
73
|
+
y: row * PIXEL_SIZE,
|
74
|
+
size: PIXEL_SIZE,
|
75
|
+
color: color
|
76
|
+
)
|
77
|
+
|
78
|
+
ruby2d_window.add(square)
|
79
|
+
square
|
80
|
+
end
|
81
|
+
|
82
|
+
def handle_key_event(event, state)
|
83
|
+
case event.key
|
84
|
+
when "up"
|
85
|
+
Actions::ChangeDirection.call(state, new_direction: Models::Direction::UP)
|
86
|
+
when "down"
|
87
|
+
Actions::ChangeDirection.call(state, new_direction: Models::Direction::DOWN)
|
88
|
+
when "left"
|
89
|
+
Actions::ChangeDirection.call(state, new_direction: Models::Direction::LEFT)
|
90
|
+
when "right"
|
91
|
+
Actions::ChangeDirection.call(state, new_direction: Models::Direction::RIGHT)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/lib/rb_snake.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rb-snake
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miguel Prada
|
8
|
-
autorequire:
|
9
|
-
bindir:
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-04-
|
11
|
+
date: 2023-04-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby2d
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.12.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: byebug
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rake
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -83,11 +97,11 @@ dependencies:
|
|
83
97
|
description: The classic snake game recreated using ruby
|
84
98
|
email:
|
85
99
|
- mapra99@gmail.com
|
86
|
-
executables:
|
100
|
+
executables:
|
101
|
+
- rb-snake
|
87
102
|
extensions: []
|
88
103
|
extra_rdoc_files: []
|
89
104
|
files:
|
90
|
-
- ".byebug_history"
|
91
105
|
- ".rspec"
|
92
106
|
- ".rubocop.yml"
|
93
107
|
- ".stickler.yml"
|
@@ -97,13 +111,19 @@ files:
|
|
97
111
|
- LICENSE.txt
|
98
112
|
- README.md
|
99
113
|
- Rakefile
|
114
|
+
- bin/rb-snake
|
100
115
|
- lib/rb_snake.rb
|
101
|
-
- lib/rb_snake/actions/
|
116
|
+
- lib/rb_snake/actions/change_direction.rb
|
117
|
+
- lib/rb_snake/actions/move_snake.rb
|
102
118
|
- lib/rb_snake/app.rb
|
103
|
-
- lib/rb_snake/
|
119
|
+
- lib/rb_snake/models/coordinate.rb
|
120
|
+
- lib/rb_snake/models/direction.rb
|
121
|
+
- lib/rb_snake/models/food.rb
|
122
|
+
- lib/rb_snake/models/grid.rb
|
123
|
+
- lib/rb_snake/models/snake.rb
|
124
|
+
- lib/rb_snake/models/state.rb
|
104
125
|
- lib/rb_snake/version.rb
|
105
|
-
- lib/rb_snake/
|
106
|
-
- rb-snake.gemspec
|
126
|
+
- lib/rb_snake/views/window.rb
|
107
127
|
- sig/rb/snake.rbs
|
108
128
|
homepage: https://github.com/mapra99/rb-snake
|
109
129
|
licenses:
|
@@ -111,7 +131,7 @@ licenses:
|
|
111
131
|
metadata:
|
112
132
|
homepage_uri: https://github.com/mapra99/rb-snake
|
113
133
|
source_code_uri: https://github.com/mapra99/rb-snake
|
114
|
-
post_install_message:
|
134
|
+
post_install_message:
|
115
135
|
rdoc_options: []
|
116
136
|
require_paths:
|
117
137
|
- lib
|
@@ -126,8 +146,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
126
146
|
- !ruby/object:Gem::Version
|
127
147
|
version: '0'
|
128
148
|
requirements: []
|
129
|
-
rubygems_version: 3.3.
|
130
|
-
signing_key:
|
149
|
+
rubygems_version: 3.3.26
|
150
|
+
signing_key:
|
131
151
|
specification_version: 4
|
132
152
|
summary: The classic snake game recreated using ruby
|
133
153
|
test_files: []
|
data/.byebug_history
DELETED
@@ -1,100 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Actions
|
4
|
-
def self.move_snake(state)
|
5
|
-
next_direction = state.curr_direction
|
6
|
-
next_position = calc_next_position(state)
|
7
|
-
|
8
|
-
if position_is_food? state, next_position
|
9
|
-
state = grow_snake_to state, next_position
|
10
|
-
generate_food state
|
11
|
-
elsif position_is_valid? state, next_position
|
12
|
-
move_snake_to state, next_position
|
13
|
-
else
|
14
|
-
end_game state
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.change_direction(state, direction)
|
19
|
-
if next_direction_is_valid? state, direction
|
20
|
-
state.curr_direction = direction
|
21
|
-
else
|
22
|
-
puts "Invalid direction"
|
23
|
-
end
|
24
|
-
|
25
|
-
state
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def self.generate_food(state)
|
31
|
-
new_food = Model::Food.new(rand(state.grid.rows), rand(state.grid.cols))
|
32
|
-
state.food = new_food
|
33
|
-
state
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.calc_next_position(state)
|
37
|
-
curr_position = state.snake.positions.first
|
38
|
-
case state.curr_direction
|
39
|
-
when Model::Direction::UP
|
40
|
-
Model::Coord.new(curr_position.row - 1,
|
41
|
-
curr_position.col)
|
42
|
-
when Model::Direction::RIGHT
|
43
|
-
Model::Coord.new(curr_position.row,
|
44
|
-
curr_position.col + 1)
|
45
|
-
when Model::Direction::DOWN
|
46
|
-
Model::Coord.new(curr_position.row + 1,
|
47
|
-
curr_position.col)
|
48
|
-
when Model::Direction::LEFT
|
49
|
-
Model::Coord.new(curr_position.row,
|
50
|
-
curr_position.col - 1)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.position_is_food?(state, next_position)
|
55
|
-
(state.food.row == next_position.row) && (state.food.col == next_position.col)
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.position_is_valid?(state, position)
|
59
|
-
# verificar que este en la grilla
|
60
|
-
is_invalid = ((position.row >= state.grid.rows) || (position.row < 0)) ||
|
61
|
-
((position.col >= state.grid.cols) || (position.col < 0))
|
62
|
-
|
63
|
-
return false if is_invalid
|
64
|
-
|
65
|
-
# verificar que no este superponiendo a la serpiente
|
66
|
-
!(state.snake.positions.include? position)
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.grow_snake_to(state, next_position)
|
70
|
-
state.snake.positions = [next_position] + state.snake.positions
|
71
|
-
state
|
72
|
-
end
|
73
|
-
|
74
|
-
def self.move_snake_to(state, next_position)
|
75
|
-
new_positions = [next_position] + state.snake.positions[0...-1]
|
76
|
-
state.snake.positions = new_positions
|
77
|
-
|
78
|
-
state
|
79
|
-
end
|
80
|
-
|
81
|
-
def self.end_game(state)
|
82
|
-
state.game_finished = true
|
83
|
-
state
|
84
|
-
end
|
85
|
-
|
86
|
-
def self.next_direction_is_valid?(state, direction)
|
87
|
-
case state.curr_direction
|
88
|
-
when Model::Direction::UP
|
89
|
-
direction != Model::Direction::DOWN
|
90
|
-
when Model::Direction::RIGHT
|
91
|
-
direction != Model::Direction::LEFT
|
92
|
-
when Model::Direction::DOWN
|
93
|
-
direction != Model::Direction::UP
|
94
|
-
when Model::Direction::LEFT
|
95
|
-
direction != Model::Direction::RIGHT
|
96
|
-
else
|
97
|
-
false
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
data/lib/rb_snake/model/state.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Representation of Game State
|
4
|
-
module Model
|
5
|
-
module Direction
|
6
|
-
UP = :up
|
7
|
-
RIGHT = :right
|
8
|
-
DOWN = :down
|
9
|
-
LEFT = :left
|
10
|
-
end
|
11
|
-
|
12
|
-
class Coord < Struct.new(:row, :col)
|
13
|
-
end
|
14
|
-
|
15
|
-
class Food < Coord
|
16
|
-
end
|
17
|
-
|
18
|
-
class Snake < Struct.new(:positions)
|
19
|
-
end
|
20
|
-
|
21
|
-
class Grid < Struct.new(:rows, :cols)
|
22
|
-
end
|
23
|
-
|
24
|
-
class State < Struct.new(:snake, :food, :grid, :curr_direction, :game_finished)
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.initial_state
|
28
|
-
Model::State.new(
|
29
|
-
Model::Snake.new([Model::Coord.new(1, 1),
|
30
|
-
Model::Coord.new(0, 1)]),
|
31
|
-
Model::Food.new(4, 4),
|
32
|
-
Model::Grid.new(8, 12),
|
33
|
-
Direction::DOWN,
|
34
|
-
false
|
35
|
-
)
|
36
|
-
end
|
37
|
-
end
|
data/lib/rb_snake/view/ruby2d.rb
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'ruby2d'
|
4
|
-
module View
|
5
|
-
class Ruby2dView
|
6
|
-
def initialize(app)
|
7
|
-
@pixel_size = 50
|
8
|
-
@app = app
|
9
|
-
end
|
10
|
-
|
11
|
-
def start(state)
|
12
|
-
extend Ruby2D::DSL
|
13
|
-
set(title: 'Snake',
|
14
|
-
width: @pixel_size * state.grid.cols,
|
15
|
-
height: @pixel_size * state.grid.rows)
|
16
|
-
on :key_down do |event|
|
17
|
-
handle_key_event event
|
18
|
-
end
|
19
|
-
show
|
20
|
-
end
|
21
|
-
|
22
|
-
def render(state)
|
23
|
-
close if state.game_finished
|
24
|
-
render_food(state)
|
25
|
-
render_snake(state)
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def render_food(state)
|
31
|
-
@food.remove if @food
|
32
|
-
extend Ruby2D::DSL
|
33
|
-
food = state.food
|
34
|
-
@food = Square.new(
|
35
|
-
x: food.col * @pixel_size,
|
36
|
-
y: food.row * @pixel_size,
|
37
|
-
size: @pixel_size,
|
38
|
-
color: 'yellow'
|
39
|
-
)
|
40
|
-
end
|
41
|
-
|
42
|
-
def render_snake(state)
|
43
|
-
@snake.each(&:remove) if @snake
|
44
|
-
extend Ruby2D::DSL
|
45
|
-
snake = state.snake
|
46
|
-
@snake = snake.positions.map do |pos|
|
47
|
-
Square.new(
|
48
|
-
x: pos.col * @pixel_size,
|
49
|
-
y: pos.row * @pixel_size,
|
50
|
-
size: @pixel_size,
|
51
|
-
color: 'green'
|
52
|
-
)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def handle_key_event(event)
|
57
|
-
case event.key
|
58
|
-
when "up"
|
59
|
-
@app.send_action(:change_direction, Model::Direction::UP)
|
60
|
-
when "down"
|
61
|
-
@app.send_action(:change_direction, Model::Direction::DOWN)
|
62
|
-
when "left"
|
63
|
-
@app.send_action(:change_direction, Model::Direction::LEFT)
|
64
|
-
when "right"
|
65
|
-
@app.send_action(:change_direction, Model::Direction::RIGHT)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
data/rb-snake.gemspec
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "lib/rb_snake/version"
|
4
|
-
|
5
|
-
Gem::Specification.new do |spec|
|
6
|
-
spec.name = "rb-snake"
|
7
|
-
spec.version = RbSnake::VERSION
|
8
|
-
spec.authors = ["Miguel Prada"]
|
9
|
-
spec.email = ["mapra99@gmail.com"]
|
10
|
-
|
11
|
-
spec.summary = "The classic snake game recreated using ruby"
|
12
|
-
spec.description = "The classic snake game recreated using ruby"
|
13
|
-
spec.homepage = "https://github.com/mapra99/rb-snake"
|
14
|
-
spec.license = "MIT"
|
15
|
-
spec.required_ruby_version = ">= 2.6.0"
|
16
|
-
|
17
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
-
spec.metadata["source_code_uri"] = spec.homepage
|
19
|
-
|
20
|
-
# Specify which files should be added to the gem when it is released.
|
21
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
|
-
spec.files = Dir.chdir(__dir__) do
|
23
|
-
`git ls-files -z`.split("\x0").reject do |f|
|
24
|
-
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
25
|
-
end
|
26
|
-
end
|
27
|
-
spec.bindir = "exe"
|
28
|
-
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
29
|
-
spec.require_paths = ["lib"]
|
30
|
-
|
31
|
-
# Uncomment to register a new dependency of your gem
|
32
|
-
spec.add_dependency 'ruby2d', '~> 0.12.0'
|
33
|
-
|
34
|
-
spec.add_development_dependency 'rake', '~> 13.0'
|
35
|
-
spec.add_development_dependency 'rspec', '~> 3.0'
|
36
|
-
spec.add_development_dependency 'rubocop', '~> 1.21'
|
37
|
-
spec.add_development_dependency 'rubocop-rspec', '~> 2.16.0'
|
38
|
-
|
39
|
-
# For more information and examples about making a new gem, check out our
|
40
|
-
# guide at: https://bundler.io/guides/creating_gem.html
|
41
|
-
end
|