ruby_terminal_games 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e7fc58451957c43c34d3b0b50ce03ec8ce1ac778
4
+ data.tar.gz: 576e6a57b18cb64b30038afb63b1ad5578a0a48e
5
+ SHA512:
6
+ metadata.gz: 12a135fd8c7e67f6c792356908ad875fd595df99662f67f6cbb672d78f467afe58eddc9c1883ab71ae1ed166b5eff093ccbac499fa5f8fd7bf7fa56a052eccf5
7
+ data.tar.gz: d9a8537ed71df86ce045aa40617c34e69d9ca17ae2a5ef37642d83be6a1364b1470e12e56e582ab4052916f7170a483ded3d9e8fabcfda3dc4a383761af2041d
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ ## RubyTerminalGames
2
+
3
+ The idea of the gem is provide some basic games to play on Terminal. Currently the gem has the games below:
4
+
5
+ - [x] Snake
6
+ - [ ] Hangman
7
+ - Any suggestions?
8
+
9
+ ## Installation
10
+
11
+ $ gem install ruby_terminal_games
12
+
13
+ ## Usage
14
+
15
+ ```shell
16
+ $ ruby_terminal_games
17
+ Usage: ruby_terminal_games COMMAND [ARGS]
18
+
19
+ The most common commands are:
20
+ list Get the list of games
21
+ play Have fun!
22
+ about What is the game about?
23
+ ```
24
+
25
+ ## Contributing
26
+
27
+ I would love your contribution. Feel free to push some code!
28
+
29
+
30
+ ## License
31
+
32
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/ruby_terminal_games'
3
+ command = ARGV.shift
4
+ arg = ARGV.shift
5
+
6
+ help = <<-EOT
7
+ Usage: ruby_terminal_games COMMAND [ARGS]
8
+
9
+ The most common commands are:
10
+ list Get the list of games
11
+ play Have fun!
12
+ about What is the game about?
13
+ EOT
14
+
15
+ if command =~ /list/
16
+ puts <<-EOT
17
+ Games:
18
+ - Snake (play snake)
19
+ EOT
20
+ exit
21
+ end
22
+
23
+ unless command && arg
24
+ puts help
25
+ exit
26
+ end
27
+
28
+ game = case arg.downcase
29
+ when /snake/
30
+ RubyTerminalGames::Snake::Game.new
31
+ end
32
+
33
+ if game
34
+ method = case command.downcase
35
+ when /play/
36
+ game.play!
37
+ when /about/
38
+ puts game.about
39
+ else
40
+ puts help
41
+ end
42
+ else
43
+ puts help
44
+ end
@@ -0,0 +1,17 @@
1
+ require 'io/console'
2
+ require 'curses'
3
+ require 'colorize'
4
+
5
+ module RubyTerminalGames
6
+ UP = 0
7
+ RIGHT = 1
8
+ DOWN = 2
9
+ LEFT = 3
10
+ end
11
+
12
+ require_relative 'ruby_terminal_games/game'
13
+ require_relative 'ruby_terminal_games/board'
14
+ require_relative 'ruby_terminal_games/keyboard'
15
+ require_relative 'ruby_terminal_games/snake'
16
+
17
+ KEYBOARD = RubyTerminalGames::Keyboard.new
@@ -0,0 +1,45 @@
1
+
2
+ module RubyTerminalGames
3
+ class Board
4
+ attr_accessor :rows, :cols, :width, :height
5
+ def initialize(width: nil, height: nil)
6
+ @rows, @cols = STDOUT.winsize
7
+ @width = width || @cols
8
+ @height = height || @rows
9
+ end
10
+
11
+ def clear!
12
+ move_cursor(1, 1)
13
+ rows.times { write(" " * cols) }
14
+ end
15
+
16
+ def write(text, row: nil, col: nil)
17
+ move_cursor(row, col) if (row && col)
18
+ STDOUT.write(text)
19
+ end
20
+
21
+ def move_cursor(row, col)
22
+ write("\e[#{row};#{col}H")
23
+ end
24
+
25
+ def draw_border!
26
+ # Left and right border
27
+ (0..height).each do |i|
28
+ write("│", row: i, col: 0)
29
+ write("│", row: i, col: width)
30
+ end
31
+
32
+ # Top and bottom border
33
+ (0..width).each do |i|
34
+ write("─", row: 0, col: i)
35
+ write("─", row: height, col: i)
36
+ end
37
+
38
+ # Corners
39
+ write("┌", row: 0, col: 0)
40
+ write("┘", row: height, col: width)
41
+ write("┐", row: 0, col: width)
42
+ write("└", row: height, col: 0)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,7 @@
1
+ module RubyTerminalGames
2
+ class Game
3
+ def about
4
+ "Oops! I don't know anything about this game."
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,34 @@
1
+ module RubyTerminalGames
2
+ class Keyboard
3
+ attr_reader :thread
4
+
5
+ def capture(detect_direction: false, &block)
6
+ Curses.noecho
7
+ Curses.stdscr.keypad(true)
8
+ Curses.curs_set(0)
9
+ Curses.cbreak
10
+ Curses.raw
11
+
12
+ Thread.new do
13
+ loop do
14
+ key = Curses.getch
15
+ command = direction(key) || key
16
+ command = key unless detect_direction
17
+ block.call(command)
18
+ end
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def direction(key)
25
+ case key
26
+ when Curses::KEY_UP; then UP;
27
+ when Curses::KEY_DOWN; then DOWN;
28
+ when Curses::KEY_RIGHT; then RIGHT;
29
+ when Curses::KEY_LEFT; then LEFT;
30
+ end
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,5 @@
1
+ module RubyTerminalGames
2
+ module Snake
3
+ end
4
+ end
5
+ require_relative 'snake/game'
@@ -0,0 +1,22 @@
1
+ module RubyTerminalGames
2
+ module Snake
3
+ class Apple
4
+ attr_reader :position, :width, :height
5
+ def initialize(width:, height:)
6
+ @width = width
7
+ @height = height
8
+ @position = [height - 4, width - 4]
9
+ end
10
+
11
+ def move(snake)
12
+ begin
13
+ moved = [
14
+ rand(height - 4) + 2,
15
+ rand(width - 4) + 2
16
+ ]
17
+ end while snake.used?(moved)
18
+ @position = moved
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,63 @@
1
+ module RubyTerminalGames
2
+ module Snake
3
+ class Board < RubyTerminalGames::Board
4
+ def initialize(width: nil, height: nil)
5
+ super
6
+ @width = cols
7
+ @height = rows - 1
8
+ end
9
+
10
+ def print_world!(game)
11
+ clear!
12
+ draw_border!
13
+ draw_exit_instructions!
14
+ draw_apple!(game.apple)
15
+ draw_stats!(game.counter, game.points)
16
+ draw_snake!(game.snake.state, game.direction)
17
+ end
18
+
19
+ private
20
+
21
+ def draw_stats!(speed, points)
22
+ stats = [
23
+ "SPEED:", speed + 1, "POINTS:", points
24
+ ].join(' ')
25
+ write(stats, row: rows, col: 0)
26
+ end
27
+
28
+ def draw_exit_instructions!
29
+ text = "Press Q to exit"
30
+ write(text, row: rows, col: cols - text.length)
31
+ end
32
+
33
+ def draw_apple!(apple)
34
+ row, col = apple.position
35
+ write("❤", row: row, col: col)
36
+ end
37
+
38
+ def draw_snake!(snake_state, direction)
39
+ snake_state.each do |state|
40
+ index, pos = state
41
+ head = (index == snake_state.length - 1)
42
+ draw_snake_body(direction, pos, head: head)
43
+ end
44
+ end
45
+
46
+ def snake_head(position)
47
+ case position
48
+ when UP then '∩'
49
+ when RIGHT then '⊃'
50
+ when DOWN then '∪'
51
+ when LEFT then '⊂'
52
+ end
53
+ end
54
+
55
+ def draw_snake_body(direction, position, head: false)
56
+ row, col = position
57
+ text = head ? snake_head(direction) : '◆'
58
+ write(text, row: row, col: col)
59
+ end
60
+
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,87 @@
1
+ require_relative 'board'
2
+ require_relative 'snake'
3
+ require_relative 'apple'
4
+
5
+ module RubyTerminalGames
6
+ module Snake
7
+ class Game < RubyTerminalGames::Game
8
+ attr_reader :board, :snake, :direction, :apple,
9
+ :points, :speed, :counter
10
+
11
+ def initialize
12
+ @direction = RIGHT
13
+ @board = Board.new
14
+
15
+ @apple = Apple.new(
16
+ width: @board.width,
17
+ height: @board.height
18
+ )
19
+
20
+ @snake = Snake.new(
21
+ width: @board.width,
22
+ height: @board.height
23
+ )
24
+
25
+ @points = 0
26
+ @speed = 0
27
+ @counter = 0
28
+ end
29
+
30
+ def play!
31
+ @playing = true
32
+
33
+ KEYBOARD.capture(detect_direction: true) do |key|
34
+ exit if key =~ /q/i
35
+ next unless direction_allowed?(key)
36
+ @direction = key
37
+ end
38
+
39
+ while @playing
40
+ eat?
41
+ snake.move!(direction)
42
+ snake.died? and @playing = false
43
+ game_interval!
44
+ board.print_world!(self)
45
+ end
46
+ end
47
+
48
+ def about
49
+ [
50
+ "Remember the good old times. Use the keyboard ",
51
+ "arrows to control the snake."
52
+ ].join
53
+ end
54
+
55
+ private
56
+
57
+ def eat?
58
+ return unless snake.eat?(apple)
59
+ snake.grow!(direction)
60
+ add_points!
61
+ increase_speed!
62
+ end
63
+
64
+ def add_points!
65
+ @points += (1 * @counter += 1)
66
+ end
67
+
68
+ def increase_speed!
69
+ @speed += 0.0005
70
+ end
71
+
72
+ def game_interval!
73
+ sleep([0.1 - @speed, 0].max)
74
+ end
75
+
76
+ def direction_allowed?(dir)
77
+ allowed = case @direction
78
+ when UP, DOWN
79
+ [LEFT, RIGHT]
80
+ when LEFT, RIGHT
81
+ [UP, DOWN]
82
+ end
83
+ allowed.include?(dir)
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,80 @@
1
+ module RubyTerminalGames
2
+ module Snake
3
+ class Snake
4
+ attr_reader :state, :width, :height
5
+ def initialize(width:, height:)
6
+ @width = width
7
+ @height = height
8
+ @state = [
9
+ [0, [2, 2]],
10
+ [1, [2, 3]],
11
+ [2, [2, 4]],
12
+ [3, [2, 5]],
13
+ [4, [2, 6]],
14
+ [5, [2, 7]],
15
+ [6, [2, 8]],
16
+ [7, [2, 9]]
17
+ ]
18
+ end
19
+
20
+ def move!(direction)
21
+ *tail, head = state
22
+ (0..state.length-2).each do |i|
23
+ i, _ = tail[i]
24
+ tail[i] = [i, state[i + 1].last]
25
+ end
26
+
27
+ index, position = head
28
+ moved = update_position(position, direction)
29
+ @state = tail.concat([[index, moved]])
30
+ end
31
+
32
+ def died?
33
+ _, position = state.last
34
+ row, col = position
35
+ across_rows_limit?(row) || across_cols_limit?(col)
36
+ end
37
+
38
+ def eat?(apple)
39
+ eat = used_positions.include?(apple.position)
40
+ apple.move(self) if eat
41
+ eat
42
+ end
43
+
44
+ def grow!(direction)
45
+ last_state = @state.last
46
+ index, pos = last_state
47
+ moved = update_position(pos, direction)
48
+ @state.concat([[index + 1, moved]])
49
+ end
50
+
51
+ def used?(position)
52
+ used_positions.include?(position)
53
+ end
54
+
55
+ private
56
+
57
+ def update_position(position, direction)
58
+ row, col = position
59
+ case direction
60
+ when UP then [row - 1, col]
61
+ when RIGHT then [row, col + 1]
62
+ when DOWN then [row + 1, col]
63
+ when LEFT then [row, col - 1]
64
+ end
65
+ end
66
+
67
+ def across_rows_limit?(row)
68
+ (row < 2 || row > height - 1)
69
+ end
70
+
71
+ def across_cols_limit?(col)
72
+ (col < 2 || col > width - 1)
73
+ end
74
+
75
+ def used_positions
76
+ state.map { |s| s.last }
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,3 @@
1
+ module RubyTerminalGames
2
+ VERSION = '0.0.1'
3
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_terminal_games
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Alves
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: curses
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: colorize
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
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: Simple basic bash game implementations in Ruby.
70
+ email: daniel@danielalves.me
71
+ executables:
72
+ - ruby_terminal_games
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - README.md
77
+ - bin/ruby_terminal_games
78
+ - lib/ruby_terminal_games.rb
79
+ - lib/ruby_terminal_games/board.rb
80
+ - lib/ruby_terminal_games/game.rb
81
+ - lib/ruby_terminal_games/keyboard.rb
82
+ - lib/ruby_terminal_games/snake.rb
83
+ - lib/ruby_terminal_games/snake/apple.rb
84
+ - lib/ruby_terminal_games/snake/board.rb
85
+ - lib/ruby_terminal_games/snake/game.rb
86
+ - lib/ruby_terminal_games/snake/snake.rb
87
+ - lib/ruby_terminal_games/version.rb
88
+ homepage: https://github.com/alvesdan/ruby_terminal_games
89
+ licenses:
90
+ - MIT
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubyforge_project:
108
+ rubygems_version: 2.2.2
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: Ruby Terminal Games
112
+ test_files: []