text2048 0.1.0

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.
@@ -0,0 +1,123 @@
1
+ # encoding: utf-8
2
+
3
+ require 'curses'
4
+ require 'text2048/curses_tile'
5
+
6
+ module Text2048
7
+ # Curses UI
8
+ class CursesView
9
+ include Curses
10
+
11
+ COLORS = {
12
+ 0 => COLOR_BLACK,
13
+ 2 => COLOR_WHITE,
14
+ 4 => COLOR_GREEN,
15
+ 8 => COLOR_GREEN,
16
+ 16 => COLOR_CYAN,
17
+ 32 => COLOR_CYAN,
18
+ 64 => COLOR_BLUE,
19
+ 128 => COLOR_BLUE,
20
+ 256 => COLOR_YELLOW,
21
+ 512 => COLOR_YELLOW,
22
+ 1024 => COLOR_MAGENTA,
23
+ 2048 => COLOR_RED
24
+ }
25
+
26
+ def initialize
27
+ @tiles = Array.new(4) { Array.new(4) }
28
+ @scale = 2
29
+ @scale_min = 1
30
+ @scale_step = 0.5
31
+ end
32
+
33
+ def start
34
+ init_screen
35
+ curs_set(0)
36
+ start_color
37
+ stdscr.keypad(true)
38
+ noecho
39
+ init_color_pairs
40
+ at_exit { close_screen }
41
+ end
42
+
43
+ def update(tiles, score)
44
+ draw_score(score)
45
+ tiles.each_with_index do |row, y|
46
+ draw_row(row, y)
47
+ end
48
+ end
49
+
50
+ def larger!(tiles, score)
51
+ return if @scale > scale_max
52
+ @scale += @scale_step
53
+ clear
54
+ update(tiles, score)
55
+ end
56
+
57
+ def smaller!(tiles, score)
58
+ return if @scale <= @scale_min
59
+ @scale -= @scale_step
60
+ clear
61
+ update(tiles, score)
62
+ end
63
+
64
+ def pop_tiles(list)
65
+ list.each do |y, x|
66
+ attron(color_pair(@tiles[y][x].color + 100)) do
67
+ @tiles[y][x].pop1
68
+ end
69
+ end
70
+ refresh
71
+ sleep 0.1
72
+
73
+ list.each do |y, x|
74
+ @tiles[y][x].pop2
75
+ end
76
+ end
77
+
78
+ def zoom_tiles(list)
79
+ [:zoom1, :zoom2, :zoom3].each do |each|
80
+ list.each do |y, x|
81
+ @tiles[y][x].__send__ each
82
+ end
83
+ sleep 0.05
84
+ end
85
+ end
86
+
87
+ def game_over
88
+ width = (@tiles[0][0].width + 1) * 4 + 1
89
+ height = (@tiles[0][0].height + 1) * 4 + 2
90
+
91
+ setpos(height / 2, width / 2 - 4)
92
+ attron(color_pair(COLOR_RED)) { addstr('GAME OVER') }
93
+ end
94
+
95
+ private
96
+
97
+ def init_color_pairs
98
+ COLORS.each_pair do |_key, value|
99
+ init_pair value, COLOR_BLACK, value
100
+ init_pair value + 100, value, value
101
+ end
102
+ end
103
+
104
+ def scale_max
105
+ w = (CursesTile::DEFAULT_WIDTH + 1) * 4 + 1
106
+ h = (CursesTile::DEFAULT_HEIGHT + 1) * 4 + 2
107
+ (cols - 1) / w < lines / h ? (cols - 1) / w : lines / h
108
+ end
109
+
110
+ def draw_score(score)
111
+ setpos(0, 0)
112
+ addstr("Score: #{score}")
113
+ end
114
+
115
+ def draw_row(tiles, y)
116
+ tiles.each_with_index do |each, x|
117
+ @tiles[y][x] =
118
+ CursesTile.new(each, y, x, COLORS[each.to_i], @scale).show
119
+ end
120
+ refresh
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,81 @@
1
+ # encoding: utf-8
2
+
3
+ require 'forwardable'
4
+ require 'text2048/board'
5
+
6
+ module Text2048
7
+ # A class responsible of handling all the command line interface
8
+ # logic.
9
+ class Game
10
+ attr_reader :score
11
+
12
+ extend Forwardable
13
+
14
+ def initialize(view, tiles = nil)
15
+ @score = 0
16
+ @board = Board.new(tiles)
17
+ @view = view
18
+ end
19
+
20
+ def start
21
+ @view.start
22
+ end
23
+
24
+ def draw
25
+ @view.update(@board.tiles, @score)
26
+ @view.pop_tiles(@board.merged_tiles)
27
+ @view.zoom_tiles(@board.generated_tiles)
28
+ end
29
+
30
+ def lose?
31
+ b = @board.dup
32
+ b.right!
33
+ b.left!
34
+ b.up!
35
+ b.down!
36
+ b.numbers.size == 4 * 4
37
+ end
38
+
39
+ def input(command)
40
+ @last = @board.tiles.dup
41
+ __send__ command
42
+ end
43
+
44
+ def left!
45
+ @score += @board.left!
46
+ end
47
+
48
+ def right!
49
+ @score += @board.right!
50
+ end
51
+
52
+ def up!
53
+ @score += @board.up!
54
+ end
55
+
56
+ def down!
57
+ @score += @board.down!
58
+ end
59
+
60
+ def generate
61
+ return if @last == @board.tiles
62
+ @board.generate
63
+ end
64
+
65
+ def larger!
66
+ @view.larger!(@board.tiles, @score)
67
+ end
68
+
69
+ def smaller!
70
+ @view.smaller!(@board.tiles, @score)
71
+ end
72
+
73
+ def game_over
74
+ @view.game_over
75
+ end
76
+
77
+ def quit
78
+ exit 0
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ module Text2048
4
+ module MonkeyPatch
5
+ module Array
6
+ # 2048 related methods
7
+ module Tile
8
+ def rmerge
9
+ score = 0
10
+ tiles = dup
11
+ (size - 1).downto(1) do |each|
12
+ if tiles[each - 1] == tiles[each]
13
+ tiles[each] = Text2048::Tile.new(tiles[each].to_i * 2, :merged)
14
+ tiles[each - 1] = Text2048::Tile.new(0)
15
+ score += tiles[each].to_i
16
+ end
17
+ end
18
+ [tiles, score]
19
+ end
20
+
21
+ def rshrink
22
+ tiles = dup
23
+ orig_size = tiles.size
24
+ tiles.select! { |each| each != 0 }
25
+ ::Array.new(orig_size - tiles.size) { Text2048::Tile.new(0) } + tiles
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+
3
+ require 'text2048/monkey_patch/array/tile'
4
+
5
+ # Monkey-patched standard Array class.
6
+ class Array
7
+ include Text2048::MonkeyPatch::Array::Tile
8
+ end
@@ -0,0 +1,23 @@
1
+ module Text2048
2
+ # Simple text view.
3
+ class TextView
4
+ def initialize(output)
5
+ @output = output
6
+ end
7
+
8
+ def update(layout, _score)
9
+ string = layout.map do |row|
10
+ row.map { |num| num != 0 ? num : '_' }.join(' ')
11
+ end.join("\n")
12
+ @output.puts string
13
+ end
14
+
15
+ def pop_tiles(_list)
16
+ # noop
17
+ end
18
+
19
+ def zoom_tiles(_list)
20
+ # noop
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ require 'forwardable'
4
+
5
+ module Text2048
6
+ # 2048 tile
7
+ class Tile
8
+ attr_reader :status
9
+
10
+ extend Forwardable
11
+
12
+ def initialize(value, status = nil)
13
+ @value = value.to_i
14
+ @status = status
15
+ end
16
+
17
+ def ==(other)
18
+ @value == other.to_i
19
+ end
20
+
21
+ def_delegators :@value, :to_i, :to_s
22
+ end
23
+ end
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+
3
+ require 'forwardable'
4
+ require 'text2048/monkey_patch/array'
5
+ require 'text2048/tile'
6
+
7
+ module Text2048
8
+ # Each row or column of a game board.
9
+ class Tiles
10
+ extend Forwardable
11
+
12
+ def initialize(list)
13
+ @list = list.map { |each| Tile.new(each) }
14
+ end
15
+
16
+ def right
17
+ list, score = @list.rshrink.rmerge
18
+ [list.rshrink, score]
19
+ end
20
+
21
+ def left
22
+ list, score = @list.reverse.rshrink.rmerge
23
+ [list.rshrink.reverse, score]
24
+ end
25
+
26
+ def ==(other)
27
+ rshrink == other.rshrink
28
+ end
29
+
30
+ def_delegators :@list, :map, :rshrink
31
+ end
32
+ end
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+
3
+ # Base module.
4
+ module Text2048
5
+ # gem version.
6
+ VERSION = '0.1.0'.freeze
7
+ end
data/lib/text2048.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'text2048/board'
2
+ require 'text2048/curses_view'
3
+ require 'text2048/game'
4
+ require 'text2048/text_view'
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+
3
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+
5
+ require 'rspec'
6
+ require 'rspec/given'
@@ -0,0 +1,74 @@
1
+ require 'text2048'
2
+
3
+ describe Text2048::Board, '.new' do
4
+ context 'with no numbers' do
5
+ Given(:board) do
6
+ Text2048::Board.new([[0, 0, 0, 0],
7
+ [0, 0, 0, 0],
8
+ [0, 0, 0, 0],
9
+ [0, 0, 0, 0]])
10
+ end
11
+
12
+ describe '#right' do
13
+ When { board.right! }
14
+
15
+ Then do
16
+ board.layout == [[0, 0, 0, 0],
17
+ [0, 0, 0, 0],
18
+ [0, 0, 0, 0],
19
+ [0, 0, 0, 0]]
20
+ end
21
+ end
22
+ end
23
+
24
+ context 'with four 2s' do
25
+ Given(:board) do
26
+ Text2048::Board.new([[2, 0, 0, 0],
27
+ [0, 2, 0, 0],
28
+ [0, 0, 2, 0],
29
+ [0, 0, 0, 2]])
30
+ end
31
+
32
+ describe '#right' do
33
+ When { board.right! }
34
+
35
+ Then do
36
+ board.layout == [[0, 0, 0, 2],
37
+ [0, 0, 0, 2],
38
+ [0, 0, 0, 2],
39
+ [0, 0, 0, 2]]
40
+ end
41
+ end
42
+
43
+ describe '#==' do
44
+ When(:result) do
45
+ board == Text2048::Board.new([[0, 0, 0, 2],
46
+ [0, 0, 2, 0],
47
+ [0, 2, 0, 0],
48
+ [2, 0, 0, 0]])
49
+ end
50
+
51
+ Then { result == true }
52
+ end
53
+ end
54
+
55
+ context 'with six 2s that can be merged' do
56
+ Given(:board) do
57
+ Text2048::Board.new([[2, 0, 2, 0],
58
+ [0, 2, 0, 0],
59
+ [0, 2, 0, 2],
60
+ [0, 0, 0, 2]])
61
+ end
62
+
63
+ describe '#right' do
64
+ When { board.right! }
65
+
66
+ Then do
67
+ board.layout == [[0, 0, 0, 4],
68
+ [0, 0, 0, 2],
69
+ [0, 0, 0, 4],
70
+ [0, 0, 0, 2]]
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,115 @@
1
+ # encoding: utf-8
2
+
3
+ require 'text2048'
4
+
5
+ describe Text2048::Tiles, '.new' do
6
+ context 'with [0, 0, 0, 0]' do
7
+ Given(:tiles) { Text2048::Tiles.new([0, 0, 0, 0]) }
8
+
9
+ describe '#right' do
10
+ When(:result) { tiles.right }
11
+
12
+ Then { result[0] == [0, 0, 0, 0] }
13
+ end
14
+ end
15
+
16
+ context 'with [2, 0, 0, 0]' do
17
+ Given(:tiles) { Text2048::Tiles.new([2, 0, 0, 0]) }
18
+
19
+ describe '#right' do
20
+ When(:result) { tiles.right }
21
+
22
+ Then { result[0] == [0, 0, 0, 2] }
23
+ end
24
+ end
25
+
26
+ context 'with [0, 2, 0, 0]' do
27
+ Given(:tiles) { Text2048::Tiles.new([0, 2, 0, 0]) }
28
+
29
+ describe '#right' do
30
+ When(:result) { tiles.right }
31
+
32
+ Then { result[0] == [0, 0, 0, 2] }
33
+ end
34
+ end
35
+
36
+ context 'with [0, 0, 2, 0]' do
37
+ Given(:tiles) { Text2048::Tiles.new([0, 0, 2, 0]) }
38
+
39
+ describe '#right' do
40
+ When(:result) { tiles.right }
41
+
42
+ Then { result[0] == [0, 0, 0, 2] }
43
+ end
44
+ end
45
+
46
+ context 'with [0, 0, 0, 2]' do
47
+ Given(:tiles) { Text2048::Tiles.new([0, 0, 0, 2]) }
48
+
49
+ describe '#right' do
50
+ When(:result) { tiles.right }
51
+
52
+ Then { result[0] == [0, 0, 0, 2] }
53
+ end
54
+ end
55
+
56
+ context 'with [2, 2, 0, 0]' do
57
+ Given(:tiles) { Text2048::Tiles.new([2, 2, 0, 0]) }
58
+
59
+ describe '#right' do
60
+ When(:result) { tiles.right }
61
+
62
+ Then { result[0] == [0, 0, 0, 4] }
63
+ end
64
+ end
65
+
66
+ context 'with [2, 2, 2, 0]' do
67
+ Given(:tiles) { Text2048::Tiles.new([2, 2, 2, 0]) }
68
+
69
+ describe '#right' do
70
+ When(:result) { tiles.right }
71
+
72
+ Then { result[0] == [0, 0, 2, 4] }
73
+ end
74
+ end
75
+
76
+ context 'with [2, 2, 2, 2]' do
77
+ Given(:tiles) { Text2048::Tiles.new([2, 2, 2, 2]) }
78
+
79
+ describe '#right' do
80
+ When(:result) { tiles.right }
81
+
82
+ Then { result[0] == [0, 0, 4, 4] }
83
+ end
84
+ end
85
+
86
+ context 'with [4, 4, 2, 2]' do
87
+ Given(:tiles) { Text2048::Tiles.new([4, 4, 2, 2]) }
88
+
89
+ describe '#right' do
90
+ When(:result) { tiles.right }
91
+
92
+ Then { result[0] == [0, 0, 8, 4] }
93
+ end
94
+ end
95
+
96
+ context 'with [0, 4, 0, 2]' do
97
+ Given(:tiles) { Text2048::Tiles.new([0, 4, 0, 2]) }
98
+
99
+ describe '#right' do
100
+ When(:result) { tiles.right }
101
+
102
+ Then { result[0] == [0, 0, 4, 2] }
103
+ end
104
+ end
105
+
106
+ context 'with [16, 8, 4, 2]' do
107
+ Given(:tiles) { Text2048::Tiles.new([16, 8, 4, 2]) }
108
+
109
+ describe '#right' do
110
+ When(:result) { tiles.right }
111
+
112
+ Then { result[0] == [16, 8, 4, 2] }
113
+ end
114
+ end
115
+ end
data/text2048.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'text2048/version'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = 'text2048'
7
+ gem.version = Text2048::VERSION
8
+ gem.summary = 'Text mode 2048 game.'
9
+ gem.description = 'Text mode 2048 game in Ruby.'
10
+
11
+ gem.license = 'GPL3'
12
+
13
+ gem.authors = ['Yasuhito Takamiya']
14
+ gem.email = ['yasuhito@gmail.com']
15
+ gem.homepage = 'http://github.com/yasuhito/text2048'
16
+
17
+ gem.files = %w(LICENSE Rakefile text2048.gemspec)
18
+ gem.files += Dir.glob('lib/**/*.rb')
19
+ gem.files += Dir.glob('bin/**/*')
20
+ gem.files += Dir.glob('spec/**/*')
21
+
22
+ gem.executables = ['2048']
23
+ gem.require_paths = ['lib']
24
+
25
+ gem.extra_rdoc_files =
26
+ [
27
+ 'CONTRIBUTING.md',
28
+ 'README.md',
29
+ 'LICENSE'
30
+ ]
31
+ gem.test_files = Dir.glob('spec/**/*')
32
+ gem.test_files += Dir.glob('features/**/*')
33
+
34
+ gem.required_ruby_version = '>= 1.9.3'
35
+ gem.add_development_dependency 'bundler', '~> 1.6.2'
36
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: text2048
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yasuhito Takamiya
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 1.6.2
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 1.6.2
27
+ description: Text mode 2048 game in Ruby.
28
+ email:
29
+ - yasuhito@gmail.com
30
+ executables:
31
+ - '2048'
32
+ extensions: []
33
+ extra_rdoc_files:
34
+ - CONTRIBUTING.md
35
+ - README.md
36
+ - LICENSE
37
+ files:
38
+ - CONTRIBUTING.md
39
+ - LICENSE
40
+ - README.md
41
+ - Rakefile
42
+ - bin/2048
43
+ - features/move_down.feature
44
+ - features/move_left.feature
45
+ - features/move_right.feature
46
+ - features/move_up.feature
47
+ - features/step_definitions/2048_steps.rb
48
+ - features/support/env.rb
49
+ - lib/text2048.rb
50
+ - lib/text2048/board.rb
51
+ - lib/text2048/curses_tile.rb
52
+ - lib/text2048/curses_view.rb
53
+ - lib/text2048/game.rb
54
+ - lib/text2048/monkey_patch/array.rb
55
+ - lib/text2048/monkey_patch/array/tile.rb
56
+ - lib/text2048/text_view.rb
57
+ - lib/text2048/tile.rb
58
+ - lib/text2048/tiles.rb
59
+ - lib/text2048/version.rb
60
+ - spec/spec_helper.rb
61
+ - spec/text2048/board_spec.rb
62
+ - spec/text2048/tiles_spec.rb
63
+ - text2048.gemspec
64
+ homepage: http://github.com/yasuhito/text2048
65
+ licenses:
66
+ - GPL3
67
+ metadata: {}
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - '>='
75
+ - !ruby/object:Gem::Version
76
+ version: 1.9.3
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubyforge_project:
84
+ rubygems_version: 2.2.2
85
+ signing_key:
86
+ specification_version: 4
87
+ summary: Text mode 2048 game.
88
+ test_files:
89
+ - spec/spec_helper.rb
90
+ - spec/text2048/board_spec.rb
91
+ - spec/text2048/tiles_spec.rb
92
+ - features/move_down.feature
93
+ - features/move_left.feature
94
+ - features/move_right.feature
95
+ - features/move_up.feature
96
+ - features/step_definitions/2048_steps.rb
97
+ - features/support/env.rb
98
+ has_rdoc: