text2048 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e85082a7a9811119fd638e5dc7e163c670ea45fb
4
- data.tar.gz: 6072216598424d89bc4ac20b4c8c62b507b87a8b
3
+ metadata.gz: b0e75242c094ba3e75243ce53f9c089c09da2e24
4
+ data.tar.gz: a0410d80241c4e0067873cc4fe1bfe9fe9acdb09
5
5
  SHA512:
6
- metadata.gz: dbf18ee75d43a5c61dbe9c866f0fdcef642b7321db7fe7d1e4d441acab10f517d1bce4a0c8aa5b6cee8e82510bd95a5e2cff3de3f0db4ecdc0eee737cd892ae2
7
- data.tar.gz: 30a1bca88794b26870d799cc037339dbf6214672a54a65da00221a69871125982628dca00f974c52ef4ce409f207b2dc9ece7b6636171769a51d64e17399d7af
6
+ metadata.gz: a1e94bc8de48cb973501983cf4c131b091362589c4c2eca09052a689111660e58557b6b344dea329641fb40b03b55477817e8191df01a28a2425bf1e7d396a4e
7
+ data.tar.gz: 421b6c1f62274af76bfa224c1605c4f31f81bb337586251fd667c43c2ec0a932c0f1fefc28ab6bfa969f7abac98919f43dbcb4fd0506e74488a4e811e9c3a95c
data/README.md CHANGED
@@ -1,8 +1,19 @@
1
1
  text2048
2
2
  ========
3
+ [![Gem Version](http://img.shields.io/gem/v/text2048.svg)][gem]
4
+ [![Build Status](http://img.shields.io/travis/yasuhito/text2048/develop.svg)][travis]
5
+ [![Code Climate](http://img.shields.io/codeclimate/github/yasuhito/text2048.svg)][codeclimate]
6
+ [![Coverage Status](http://img.shields.io/coveralls/yasuhito/text2048/develop.svg)][coveralls]
7
+ [![Dependency Status](http://img.shields.io/gemnasium/yasuhito/text2048.svg)][gemnasium]
3
8
 
4
9
  Text mode 2048 game.
5
10
 
11
+ [gem]: https://rubygems.org/gems/text2048
12
+ [travis]: http://travis-ci.org/yasuhito/text2048
13
+ [codeclimate]: https://codeclimate.com/github/yasuhito/text2048
14
+ [coveralls]: https://coveralls.io/r/yasuhito/text2048?branch=develop
15
+ [gemnasium]: https://gemnasium.com/yasuhito/text2048
16
+
6
17
  How to Play
7
18
  ===========
8
19
 
@@ -22,3 +33,8 @@ Installation
22
33
  ```
23
34
  $ gem install text2048
24
35
  ```
36
+
37
+ Link
38
+ ====
39
+
40
+ * [The official version of 2048](http://gabrielecirulli.github.io/2048/) by Gabriele Cirulli
data/Rakefile CHANGED
@@ -1,8 +1,13 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'bundler/gem_tasks'
4
+ require 'coveralls/rake/task'
4
5
 
5
- task default: [:spec, :cucumber, :rubocop]
6
+ task default: [:test, :reek, :rubocop]
7
+ task test: [:spec, :cucumber, 'coveralls:push']
8
+ task travis: :default
9
+
10
+ Coveralls::RakeTask.new
6
11
 
7
12
  begin
8
13
  require 'rspec/core/rake_task'
@@ -30,3 +35,17 @@ rescue LoadError
30
35
  $stderr.puts 'Rubocop is disabled'
31
36
  end
32
37
  end
38
+
39
+ begin
40
+ require 'reek/rake/task'
41
+ Reek::Rake::Task.new do |t|
42
+ t.fail_on_error = false
43
+ t.verbose = false
44
+ t.reek_opts = '--quiet'
45
+ t.source_files = FileList['lib/**/*.rb']
46
+ end
47
+ rescue LoadError
48
+ task :reek do
49
+ $stderr.puts 'Reek is disabled'
50
+ end
51
+ end
data/bin/2048 CHANGED
@@ -1,33 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
+ # encoding: utf-8
2
3
 
3
4
  $LOAD_PATH.unshift(File.dirname(File.realpath(__FILE__)) + '/../lib')
4
5
 
5
- require 'curses'
6
- require 'text2048'
6
+ require 'text2048/app'
7
7
 
8
- include Curses
9
-
10
- KEYS = {
11
- 'h' => :left!, 'l' => :right!, 'k' => :up!, 'j' => :down!,
12
- Key::LEFT => :left!, Key::RIGHT => :right!,
13
- Key::UP => :up!, Key::DOWN => :down!,
14
- '+' => :larger!, '-' => :smaller!,
15
- 'q' => :quit
16
- }
17
-
18
- game = Text2048::Game.new(Text2048::CursesView.new)
19
- game.start
20
- game.draw
21
-
22
- loop do
23
- game.game_over if game.lose?
24
- command = KEYS[Curses.getch]
25
- game.input(command) if command
26
- case command
27
- when :left!, :right!, :up!, :down!
28
- game.generate
29
- game.draw
30
- else
31
- # noop
32
- end
33
- end
8
+ Text2048::App.new.start
@@ -0,0 +1,10 @@
1
+ Feature: Game Over
2
+ Scenario: Game Over
3
+ When a board:
4
+ """
5
+ 2 4 8 16
6
+ 4 8 16 32
7
+ 8 16 32 64
8
+ 16 32 64 128
9
+ """
10
+ Then it is game over
@@ -1,33 +1,40 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'text2048'
2
4
 
3
5
  Given(/^a board:$/) do |string|
4
6
  layout = string.split("\n").reduce([]) do |result, row|
5
7
  result << row.split(' ').map(&:to_i)
6
8
  end
7
- @game = Text2048::Game.new(Text2048::TextView.new(output), layout)
9
+ @view = Text2048::TextView.new(output)
10
+ @board = Text2048::Board.new(layout)
8
11
  end
9
12
 
10
13
  When(/^I move the board to the right$/) do
11
- @game.right!
14
+ @board = @board.right
12
15
  end
13
16
 
14
17
  When(/^I move the board to the left$/) do
15
- @game.left!
18
+ @board = @board.left
16
19
  end
17
20
 
18
21
  When(/^I move the board up$/) do
19
- @game.up!
22
+ @board = @board.up
20
23
  end
21
24
 
22
25
  When(/^I move the board down$/) do
23
- @game.down!
26
+ @board = @board.down
24
27
  end
25
28
 
26
29
  Then(/^the board is:$/) do |string|
27
- @game.draw
30
+ @view.update(@board)
28
31
  output.messages.should eq(string)
29
32
  end
30
33
 
31
34
  Then(/^the score is (\d+)$/) do |score|
32
- @game.score.should eq(score.to_i)
35
+ @board.score.should eq(score.to_i)
36
+ end
37
+
38
+ Then(/^it is game over$/) do
39
+ @board.lose?.should be_true
33
40
  end
@@ -1,5 +1,8 @@
1
1
  # encoding: utf-8
2
2
 
3
+ require 'coveralls'
4
+ Coveralls.wear_merged!
5
+
3
6
  # Dummy output
4
7
  class Output
5
8
  def messages
@@ -0,0 +1,64 @@
1
+ # encoding: utf-8
2
+
3
+ require 'curses'
4
+ require 'text2048'
5
+
6
+ # This module smells of :reek:UncommunicativeModuleName
7
+ module Text2048
8
+ # Controller class.
9
+ class App
10
+ include Curses
11
+
12
+ KEYS = {
13
+ 'h' => :left, 'l' => :right, 'k' => :up, 'j' => :down,
14
+ Key::LEFT => :left, Key::RIGHT => :right,
15
+ Key::UP => :up, Key::DOWN => :down,
16
+ '+' => :larger, '-' => :smaller,
17
+ 'q' => :quit
18
+ }
19
+
20
+ def initialize
21
+ @view = CursesView.new
22
+ @board = Board.new
23
+ @view.update(@board)
24
+ end
25
+
26
+ def start
27
+ loop do
28
+ @view.win if @board.win?
29
+ @view.game_over if @board.lose?
30
+ input KEYS[Curses.getch]
31
+ end
32
+ sleep
33
+ end
34
+
35
+ private
36
+
37
+ def input(command)
38
+ case command
39
+ when :left, :right, :up, :down
40
+ move_and_generate(command)
41
+ when :larger, :smaller
42
+ @view.__send__ command, @board
43
+ when :quit
44
+ exit 0
45
+ end
46
+ end
47
+
48
+ def move_and_generate(command)
49
+ last = move(command)
50
+ generate if @board != last
51
+ end
52
+
53
+ def move(command)
54
+ last = @board.dup
55
+ @board = @board.__send__(command)
56
+ last
57
+ end
58
+
59
+ def generate
60
+ @board.generate
61
+ @view.update(@board)
62
+ end
63
+ end
64
+ end
@@ -3,16 +3,19 @@
3
3
  require 'text2048/tile'
4
4
  require 'text2048/tiles'
5
5
 
6
+ # This module smells of :reek:UncommunicativeModuleName
6
7
  module Text2048
7
8
  # Game board
8
9
  class Board
10
+ attr_reader :score
9
11
  attr_reader :tiles
10
12
 
11
- def initialize(tiles = nil)
12
- @tiles = Array.new(4) { Array.new(4) { Tile.new(0) } }
13
+ def initialize(tiles = nil, score = 0)
14
+ @score = score
13
15
  if tiles
14
- load_tiles(tiles)
16
+ @tiles = tiles.dup
15
17
  else
18
+ @tiles = Array.new(4) { Array.new(4) { Tile.new(0) } }
16
19
  2.times { generate }
17
20
  end
18
21
  end
@@ -27,54 +30,54 @@ module Text2048
27
30
  end
28
31
  end
29
32
 
30
- def right!
31
- move! :right
33
+ def win?
34
+ numbers.select do |each|
35
+ each.to_i >= 2048
36
+ end.size > 0
32
37
  end
33
38
 
34
- def left!
35
- move! :left
39
+ def lose?
40
+ right.left.up.down.numbers.size == 4 * 4
36
41
  end
37
42
 
38
- def up!
39
- transpose { move! :left }
43
+ def left
44
+ tiles, score = move(:left)
45
+ self.class.new tiles, @score + score
40
46
  end
41
47
 
42
- def down!
43
- transpose { move! :right }
48
+ def right
49
+ tiles, score = move(:right)
50
+ self.class.new tiles, @score + score
51
+ end
52
+
53
+ def up
54
+ tiles, score = transpose { move(:left) }
55
+ self.class.new tiles, @score + score
56
+ end
57
+
58
+ def down
59
+ tiles, score = transpose { move(:right) }
60
+ self.class.new tiles, @score + score
44
61
  end
45
62
 
46
63
  def ==(other)
47
- @tiles.zip(other.tiles).reduce(true) do |result, each|
48
- result && Tiles.new(each[0]) == Tiles.new(each[1])
49
- end
64
+ layout == other.layout
50
65
  end
51
66
 
52
67
  def merged_tiles
53
- result = []
54
- @tiles.each_with_index do |row, y|
55
- row.each_with_index do |each, x|
56
- result << [y, x] if each.status == :merged
57
- end
58
- end
59
- result
68
+ find_tiles :merged
60
69
  end
61
70
 
62
71
  def generated_tiles
63
- result = []
64
- @tiles.each_with_index do |row, y|
65
- row.each_with_index do |each, x|
66
- result << [y, x] if each.status == :generated
67
- end
68
- end
69
- result
72
+ find_tiles :generated
70
73
  end
71
74
 
72
75
  def generate
73
76
  loop do
74
- x = rand(4)
75
- y = rand(4)
76
- if @tiles[y][x] == 0
77
- @tiles[y][x] = Tile.new(rand < 0.8 ? 2 : 4, :generated)
77
+ line = rand(4)
78
+ col = rand(4)
79
+ if @tiles[line][col] == 0
80
+ @tiles[line][col] = Tile.new(rand < 0.8 ? 2 : 4, :generated)
78
81
  return
79
82
  end
80
83
  end
@@ -88,29 +91,32 @@ module Text2048
88
91
 
89
92
  private
90
93
 
91
- def move!(direction)
94
+ def move(direction)
92
95
  score = 0
93
- @tiles.map! do |each|
96
+ tiles = @tiles.map do |each|
94
97
  row, sc = Tiles.new(each).__send__ direction
95
98
  score += sc
96
99
  row
97
100
  end
98
- score
101
+ [tiles, score]
99
102
  end
100
103
 
104
+ def find_tiles(status)
105
+ list = []
106
+ @tiles.each_with_index do |row, line|
107
+ row.each_with_index do |each, col|
108
+ list << [line, col] if each.status == status
109
+ end
110
+ end
111
+ list
112
+ end
113
+
114
+ # FIXME: this method is destructive.
101
115
  def transpose
102
116
  @tiles = @tiles.transpose
103
- score = yield
117
+ @tiles, score = yield
104
118
  @tiles = @tiles.transpose
105
- score
106
- end
107
-
108
- def load_tiles(tiles)
109
- tiles.each_with_index do |row, y|
110
- row.each_with_index do |number, x|
111
- @tiles[y][x] = Tile.new(number)
112
- end
113
- end
119
+ [@tiles, score]
114
120
  end
115
121
  end
116
122
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'curses'
4
4
 
5
+ # This module smells of :reek:UncommunicativeModuleName
5
6
  module Text2048
6
7
  # Shows tiles in curses.
7
8
  class CursesTile
@@ -14,107 +15,102 @@ module Text2048
14
15
  DEFAULT_HEIGHT = 3
15
16
  DEFAULT_WIDTH = 5
16
17
 
17
- def initialize(value, y, x, color, scale = 1)
18
+ def initialize(value, line, col, color, scale = 1)
18
19
  @value = value.to_i
19
- @y = y
20
- @x = x
21
- @color = color
22
20
  @height = (DEFAULT_HEIGHT * scale).to_i
21
+ @box_height = @height + 2
23
22
  @width = (DEFAULT_WIDTH * scale).to_i
23
+ @box_width = @width + 2
24
+ @line = (@height + 1) * line + 2
25
+ @col = (@width + 1) * col + 1
26
+ @color = color
24
27
  end
25
28
 
26
29
  def show
27
30
  draw_box
28
- attron(color_pair(@color + 100)) { fill }
29
- attron(color_pair(@color)) { draw_number }
31
+ fill_tile_color
32
+ draw_number
30
33
  self
31
34
  end
32
35
 
33
- def pop1
34
- setpos(yc - 1, xc - 1)
35
- addstr('.' * (@width + 2))
36
-
37
- (0..(@height - 1)).each do |dy|
38
- setpos(yc + dy, xc - 1)
39
- addstr('.')
40
- setpos(yc + dy, xc + @width)
41
- addstr('.')
36
+ def pop
37
+ attron(color_pair(@color + 100)) do
38
+ draw_box
42
39
  end
40
+ end
43
41
 
44
- setpos(yc + @height, xc - 1)
45
- addstr('.' * (@width + 2))
42
+ def draw_box
43
+ draw_square
44
+ [box_upper_left, box_upper_right,
45
+ box_lower_left, box_lower_right].each do |line, col|
46
+ setpos(line, col)
47
+ addstr('+')
48
+ end
46
49
  end
47
50
 
48
- def pop2
49
- draw_box
50
- refresh
51
+ def fill_tile_color
52
+ attron(color_pair(@color + 100)) { fill }
51
53
  end
52
54
 
53
- def zoom1
55
+ def fill_black
54
56
  attron(color_pair(COLOR_BLACK + 100)) { fill }
55
- attron(color_pair(@color)) { draw_number }
56
57
  refresh
57
58
  end
58
59
 
59
- def zoom2
60
- setpos(yc + @height / 2 - 1, xc + @width / 2 - 1)
61
- attron(color_pair(@color + 100)) { addstr('...') }
62
- setpos(yc + @height / 2, xc + @width / 2 - 1)
63
- attron(color_pair(@color + 100)) { addstr('...') }
64
- setpos(yc + @height / 2 + 1, xc + @width / 2 - 1)
65
- attron(color_pair(@color + 100)) { addstr('...') }
60
+ def draw_number
61
+ return if @value == 0
62
+ setpos(@line + @height / 2, @col)
63
+ attron(color_pair(@color)) do
64
+ addstr @value.to_s.center(@width)
65
+ end
66
+ end
66
67
 
67
- attron(color_pair(@color)) { draw_number }
68
+ private
68
69
 
69
- refresh
70
+ def box_upper_left
71
+ [@line - 1, @col - 1]
70
72
  end
71
73
 
72
- def zoom3
73
- attron(color_pair(@color + 100)) { fill }
74
- attron(color_pair(@color)) { draw_number }
75
- refresh
74
+ def box_upper_right
75
+ [@line - 1, @col + @width]
76
76
  end
77
77
 
78
- private
78
+ def box_lower_left
79
+ [@line + @height, @col - 1]
80
+ end
79
81
 
80
- def yc
81
- (@height + 1) * @y + 2
82
+ def box_lower_right
83
+ [@line + @height, @col + @width]
82
84
  end
83
85
 
84
- def xc
85
- (@width + 1) * @x + 1
86
+ def draw_square
87
+ draw_horizonal_line(*box_upper_left, @box_width)
88
+ draw_vertical_line(*box_upper_left, @box_height)
89
+ draw_vertical_line(*box_upper_right, @box_height)
90
+ draw_horizonal_line(*box_lower_left, @box_width)
86
91
  end
87
92
 
88
- def draw_box
89
- setpos(yc - 1, xc - 1)
90
- addstr("+#{'-' * @width}+")
93
+ def draw_horizonal_line(line, col, length)
94
+ setpos(line, col)
95
+ addstr('-' * length)
96
+ end
91
97
 
92
- (0..(@height - 1)).each do |dy|
93
- setpos(yc + dy, xc - 1)
94
- addstr('|')
95
- setpos(yc + dy, xc + @width)
98
+ def draw_vertical_line(line, col, length)
99
+ (0..(length - 1)).each do |each|
100
+ setpos(line + each, col)
96
101
  addstr('|')
97
102
  end
98
-
99
- setpos(yc + @height, xc - 1)
100
- addstr("+#{'-' * @width}+")
101
103
  end
102
104
 
103
105
  def fill
104
- (0..(@height - 1)).each do |dy|
105
- setpos(yc + dy, xc)
106
- if @value != 0 && dy == @height / 2
106
+ (0..(@height - 1)).each do |each|
107
+ setpos(@line + each, @col)
108
+ if @value != 0 && each == @height / 2
107
109
  addstr @value.to_s.center(@width)
108
110
  else
109
111
  addstr('.' * @width)
110
112
  end
111
113
  end
112
114
  end
113
-
114
- def draw_number
115
- return if @value == 0
116
- setpos(yc + @height / 2, xc)
117
- addstr @value.to_s.center(@width)
118
- end
119
115
  end
120
116
  end
@@ -3,10 +3,41 @@
3
3
  require 'curses'
4
4
  require 'text2048/curses_tile'
5
5
 
6
+ # This module smells of :reek:UncommunicativeModuleName
6
7
  module Text2048
7
8
  # Curses UI
8
9
  class CursesView
10
+ # Curses tile effects
11
+ module TileEffects
12
+ def pop_tiles(list)
13
+ pop(list)
14
+ refresh
15
+ sleep 0.1
16
+ draw_box(list)
17
+ refresh
18
+ end
19
+
20
+ def zoom_tiles(list)
21
+ [:fill_black, :draw_number, :show].each do |each|
22
+ list.each { |line, col| @tiles[line][col].__send__ each }
23
+ refresh
24
+ sleep 0.05
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def pop(list)
31
+ list.each { |line, col| @tiles[line][col].pop }
32
+ end
33
+
34
+ def draw_box(list)
35
+ list.each { |line, col| @tiles[line][col].draw_box }
36
+ end
37
+ end
38
+
9
39
  include Curses
40
+ include TileEffects
10
41
 
11
42
  COLORS = {
12
43
  0 => COLOR_BLACK,
@@ -23,6 +54,9 @@ module Text2048
23
54
  2048 => COLOR_RED
24
55
  }
25
56
 
57
+ DEFAULT_WIDTH = (CursesTile::DEFAULT_WIDTH + 1) * 4 + 1
58
+ DEFAULT_HEIGHT = (CursesTile::DEFAULT_HEIGHT + 1) * 4 + 2
59
+
26
60
  def initialize
27
61
  @tiles = Array.new(4) { Array.new(4) }
28
62
  @scale = 2
@@ -30,70 +64,66 @@ module Text2048
30
64
  @scale_step = 0.5
31
65
  end
32
66
 
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 }
67
+ def update(board)
68
+ maybe_init_curses
69
+ draw_score(board.score)
70
+ draw_tiles(board.tiles)
71
+ refresh
72
+ pop_tiles(board.merged_tiles)
73
+ zoom_tiles(board.generated_tiles)
41
74
  end
42
75
 
43
- def update(tiles, score)
44
- draw_score(score)
45
- tiles.each_with_index do |row, y|
46
- draw_row(row, y)
47
- end
76
+ def height
77
+ (@tiles[0][0].height + 1) * 4 + 2
48
78
  end
49
79
 
50
- def larger!(tiles, score)
80
+ def width
81
+ (@tiles[0][0].width + 1) * 4 + 1
82
+ end
83
+
84
+ def larger(board)
51
85
  return if @scale > scale_max
86
+ maybe_init_curses
52
87
  @scale += @scale_step
53
88
  clear
54
- update(tiles, score)
89
+ update(board)
55
90
  end
56
91
 
57
- def smaller!(tiles, score)
92
+ def smaller(board)
58
93
  return if @scale <= @scale_min
94
+ maybe_init_curses
59
95
  @scale -= @scale_step
60
96
  clear
61
- update(tiles, score)
97
+ update(board)
62
98
  end
63
99
 
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
100
+ def win
101
+ setpos(height / 2, width / 2 - 1)
102
+ attron(color_pair(COLOR_RED)) { addstr('WIN!') }
85
103
  end
86
104
 
87
105
  def game_over
88
- width = (@tiles[0][0].width + 1) * 4 + 1
89
- height = (@tiles[0][0].height + 1) * 4 + 2
90
-
91
106
  setpos(height / 2, width / 2 - 4)
92
107
  attron(color_pair(COLOR_RED)) { addstr('GAME OVER') }
93
108
  end
94
109
 
95
110
  private
96
111
 
112
+ def maybe_init_curses
113
+ @curses_initialized || init_curses
114
+ @curses_initialized = true
115
+ end
116
+
117
+ def init_curses
118
+ init_screen
119
+ curs_set(0)
120
+ start_color
121
+ stdscr.keypad(true)
122
+ noecho
123
+ init_color_pairs
124
+ at_exit { close_screen }
125
+ end
126
+
97
127
  def init_color_pairs
98
128
  COLORS.each_pair do |_key, value|
99
129
  init_pair value, COLOR_BLACK, value
@@ -102,9 +132,9 @@ module Text2048
102
132
  end
103
133
 
104
134
  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
135
+ ratio_width = (cols - 1) / DEFAULT_WIDTH
136
+ ratio_height = lines / DEFAULT_HEIGHT
137
+ ratio_width < ratio_height ? ratio_width : ratio_height
108
138
  end
109
139
 
110
140
  def draw_score(score)
@@ -112,12 +142,15 @@ module Text2048
112
142
  addstr("Score: #{score}")
113
143
  end
114
144
 
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
145
+ def draw_tiles(tiles)
146
+ tiles.each_with_index { |row, line| draw_row(row, line) }
147
+ end
148
+
149
+ def draw_row(tiles, line)
150
+ tiles.each_with_index do |each, col|
151
+ @tiles[line][col] =
152
+ CursesTile.new(each, line, col, COLORS[each.to_i], @scale).show
119
153
  end
120
- refresh
121
154
  end
122
155
  end
123
156
  end
@@ -1,5 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
+ # This module smells of :reek:UncommunicativeModuleName
3
4
  module Text2048
4
5
  module MonkeyPatch
5
6
  module Array
@@ -1,15 +1,26 @@
1
+ # encoding: utf-8
2
+
3
+ # This module smells of :reek:UncommunicativeModuleName
1
4
  module Text2048
2
5
  # Simple text view.
3
6
  class TextView
4
- def initialize(output)
7
+ # Board row in text.
8
+ class Row
9
+ def initialize(row)
10
+ @row = row
11
+ end
12
+
13
+ def to_s
14
+ @row.map { |each| each != 0 ? each : '_' }.join(' ')
15
+ end
16
+ end
17
+
18
+ def initialize(output = STDOUT)
5
19
  @output = output
6
20
  end
7
21
 
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
22
+ def update(game)
23
+ @output.puts game.tiles.map { |row| Row.new(row).to_s }.join("\n")
13
24
  end
14
25
 
15
26
  def pop_tiles(_list)
data/lib/text2048/tile.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'forwardable'
4
4
 
5
+ # This module smells of :reek:UncommunicativeModuleName
5
6
  module Text2048
6
7
  # 2048 tile
7
8
  class Tile
@@ -4,6 +4,7 @@ require 'forwardable'
4
4
  require 'text2048/monkey_patch/array'
5
5
  require 'text2048/tile'
6
6
 
7
+ # This module smells of :reek:UncommunicativeModuleName
7
8
  module Text2048
8
9
  # Each row or column of a game board.
9
10
  class Tiles
@@ -23,10 +24,6 @@ module Text2048
23
24
  [list.rshrink.reverse, score]
24
25
  end
25
26
 
26
- def ==(other)
27
- rshrink == other.rshrink
28
- end
29
-
30
27
  def_delegators :@list, :map, :rshrink
31
28
  end
32
29
  end
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
- # Base module.
3
+ # This module smells of :reek:UncommunicativeModuleName
4
4
  module Text2048
5
5
  # gem version.
6
- VERSION = '0.1.0'.freeze
6
+ VERSION = '0.2.0'.freeze
7
7
  end
data/lib/text2048.rb CHANGED
@@ -1,4 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'text2048/board'
2
4
  require 'text2048/curses_view'
3
- require 'text2048/game'
4
5
  require 'text2048/text_view'
data/spec/spec_helper.rb CHANGED
@@ -2,5 +2,8 @@
2
2
 
3
3
  $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
4
 
5
+ require 'coveralls'
6
+ Coveralls.wear_merged!
7
+
5
8
  require 'rspec'
6
9
  require 'rspec/given'
@@ -1,7 +1,9 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'text2048'
2
4
 
3
5
  describe Text2048::Board, '.new' do
4
- context 'with no numbers' do
6
+ context 'with all zeroes' do
5
7
  Given(:board) do
6
8
  Text2048::Board.new([[0, 0, 0, 0],
7
9
  [0, 0, 0, 0],
@@ -10,13 +12,13 @@ describe Text2048::Board, '.new' do
10
12
  end
11
13
 
12
14
  describe '#right' do
13
- When { board.right! }
15
+ When(:result) { board.right }
14
16
 
15
17
  Then do
16
- board.layout == [[0, 0, 0, 0],
17
- [0, 0, 0, 0],
18
- [0, 0, 0, 0],
19
- [0, 0, 0, 0]]
18
+ result.layout == [[0, 0, 0, 0],
19
+ [0, 0, 0, 0],
20
+ [0, 0, 0, 0],
21
+ [0, 0, 0, 0]]
20
22
  end
21
23
  end
22
24
  end
@@ -30,26 +32,15 @@ describe Text2048::Board, '.new' do
30
32
  end
31
33
 
32
34
  describe '#right' do
33
- When { board.right! }
35
+ When(:result) { board.right }
34
36
 
35
37
  Then do
36
- board.layout == [[0, 0, 0, 2],
37
- [0, 0, 0, 2],
38
- [0, 0, 0, 2],
39
- [0, 0, 0, 2]]
38
+ result.layout == [[0, 0, 0, 2],
39
+ [0, 0, 0, 2],
40
+ [0, 0, 0, 2],
41
+ [0, 0, 0, 2]]
40
42
  end
41
43
  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
44
  end
54
45
 
55
46
  context 'with six 2s that can be merged' do
@@ -61,13 +52,13 @@ describe Text2048::Board, '.new' do
61
52
  end
62
53
 
63
54
  describe '#right' do
64
- When { board.right! }
55
+ When(:result) { board.right }
65
56
 
66
57
  Then do
67
- board.layout == [[0, 0, 0, 4],
68
- [0, 0, 0, 2],
69
- [0, 0, 0, 4],
70
- [0, 0, 0, 2]]
58
+ result.layout == [[0, 0, 0, 4],
59
+ [0, 0, 0, 2],
60
+ [0, 0, 0, 4],
61
+ [0, 0, 0, 2]]
71
62
  end
72
63
  end
73
64
  end
data/text2048.gemspec CHANGED
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  lib = File.expand_path('../lib', __FILE__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
5
  require 'text2048/version'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: text2048
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yasuhito Takamiya
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-02 00:00:00.000000000 Z
11
+ date: 2014-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -40,6 +40,7 @@ files:
40
40
  - README.md
41
41
  - Rakefile
42
42
  - bin/2048
43
+ - features/game_over.feature
43
44
  - features/move_down.feature
44
45
  - features/move_left.feature
45
46
  - features/move_right.feature
@@ -47,10 +48,10 @@ files:
47
48
  - features/step_definitions/2048_steps.rb
48
49
  - features/support/env.rb
49
50
  - lib/text2048.rb
51
+ - lib/text2048/app.rb
50
52
  - lib/text2048/board.rb
51
53
  - lib/text2048/curses_tile.rb
52
54
  - lib/text2048/curses_view.rb
53
- - lib/text2048/game.rb
54
55
  - lib/text2048/monkey_patch/array.rb
55
56
  - lib/text2048/monkey_patch/array/tile.rb
56
57
  - lib/text2048/text_view.rb
@@ -89,10 +90,10 @@ test_files:
89
90
  - spec/spec_helper.rb
90
91
  - spec/text2048/board_spec.rb
91
92
  - spec/text2048/tiles_spec.rb
93
+ - features/game_over.feature
92
94
  - features/move_down.feature
93
95
  - features/move_left.feature
94
96
  - features/move_right.feature
95
97
  - features/move_up.feature
96
98
  - features/step_definitions/2048_steps.rb
97
99
  - features/support/env.rb
98
- has_rdoc:
data/lib/text2048/game.rb DELETED
@@ -1,81 +0,0 @@
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