ruby_terminal_games 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.
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: []