TwentyFortyEight 0.1.1 → 0.2.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.
- checksums.yaml +4 -4
- data/TwentyFortyEight.gemspec +1 -1
- data/bin/console +7 -7
- data/lib/TwentyFortyEight.rb +43 -20
- data/lib/TwentyFortyEight/cli.rb +6 -1
- data/lib/TwentyFortyEight/dsl.rb +9 -4
- data/lib/TwentyFortyEight/game.rb +5 -6
- data/lib/TwentyFortyEight/screen.rb +6 -6
- data/lib/TwentyFortyEight/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 169c96337916c0265c9bcf9f76ed322a221728be
|
4
|
+
data.tar.gz: 7712f1815cc6a4e4abe44c1da513354c2b6c6be7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49c55706b034d1a427dd69939bdf202eec5b97476b365fc0e95b6e3cdacc405dd6fa990939443f145603e4f365a4c93d129857106bade1cba5ff7145dd2aee23
|
7
|
+
data.tar.gz: e0c82620996f5656a79057d50425d1ab9b104d001f0cefceb22ffb17795fb114abab60e4ac3a7b2d69da2f86e947559e1b7a697aa5932e8dff8c441271bf10e7
|
data/TwentyFortyEight.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
|
12
12
|
spec.summary = %(A 2048 game for terminals)
|
13
13
|
spec.description = 'Play a game of 2048 in the terminal, colorized using ' \
|
14
|
-
'Ruby curses. See --help for
|
14
|
+
'Ruby curses. (See --help for options / controls)'
|
15
15
|
spec.homepage = 'https://sidofc.github.io/projects/2048'
|
16
16
|
spec.license = 'MIT'
|
17
17
|
|
data/bin/console
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'TwentyFortyEight'
|
5
5
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
@game = TwentyFortyEight.endless verbose: true do
|
10
|
+
down || left || right || up
|
11
|
+
end
|
12
12
|
|
13
|
-
require
|
14
|
-
|
13
|
+
require 'pry'
|
14
|
+
Pry.start
|
data/lib/TwentyFortyEight.rb
CHANGED
@@ -11,17 +11,20 @@ require_relative 'TwentyFortyEight/screen'
|
|
11
11
|
require_relative 'TwentyFortyEight/dsl'
|
12
12
|
|
13
13
|
module TwentyFortyEight
|
14
|
-
|
15
|
-
|
14
|
+
MODES = [:play, :endless].freeze
|
15
|
+
SETTINGS = { size: 4, fill: 0, empty: 0 }.freeze
|
16
|
+
|
17
|
+
@@games = []
|
18
|
+
@@highscore = nil
|
16
19
|
|
17
20
|
def self.play(settings = {}, &block)
|
18
|
-
settings = Options.new settings
|
21
|
+
settings = Options.new SETTINGS.merge(settings)
|
19
22
|
game = Game.new @@games.count, settings
|
20
23
|
dirs = game.directions - (settings.except || [])
|
21
|
-
dirs
|
22
|
-
dsl = Dsl.new settings, &block if block_given?
|
24
|
+
dirs -= (settings.only || [])
|
25
|
+
dsl = Dsl.new game, settings, &block if block_given?
|
23
26
|
|
24
|
-
|
27
|
+
load_or_set_highscore!(game.score, settings) unless @@highscore
|
25
28
|
|
26
29
|
Screen.init! settings if settings.verbose? && @@games.empty?
|
27
30
|
|
@@ -36,8 +39,6 @@ module TwentyFortyEight
|
|
36
39
|
render_game game, settings if settings.verbose?
|
37
40
|
|
38
41
|
loop do
|
39
|
-
@@best = game if @@best != game && game.score > @@best.score
|
40
|
-
# binding.pry
|
41
42
|
if game.end?
|
42
43
|
break if settings.mode?(:endless) ||
|
43
44
|
!settings.verbose? ||
|
@@ -66,6 +67,7 @@ module TwentyFortyEight
|
|
66
67
|
end
|
67
68
|
|
68
69
|
game.action action
|
70
|
+
load_or_set_highscore! game.score, settings
|
69
71
|
render_game game, settings if settings.verbose? || settings.interactive?
|
70
72
|
sleep(settings.delay.to_f / 1000) if settings.delay?
|
71
73
|
end
|
@@ -79,31 +81,52 @@ module TwentyFortyEight
|
|
79
81
|
end
|
80
82
|
|
81
83
|
return play(settings, &block) if restart
|
82
|
-
|
83
84
|
game
|
84
85
|
ensure
|
85
86
|
Screen.restore! if settings.verbose? && settings.mode?(:play)
|
86
87
|
end
|
87
88
|
|
89
|
+
def self.load_or_set_highscore!(current_score, settings, path = '~/.2048')
|
90
|
+
@@highscore ||= load_highscore
|
91
|
+
@@highscore[settings.size.to_s] ||= 0
|
92
|
+
|
93
|
+
return unless current_score > @@highscore[settings.size.to_s]
|
94
|
+
|
95
|
+
@@highscore[settings.size.to_s] = current_score
|
96
|
+
write_highscore
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.write_highscore(path = '~/.2048')
|
100
|
+
File.write File.expand_path(path), @@highscore.to_json
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.load_highscore(path = '~/.2048')
|
104
|
+
path = File.expand_path path
|
105
|
+
|
106
|
+
if File.exists?(path)
|
107
|
+
contents = File.read path
|
108
|
+
hsh = JSON.parse contents.start_with?('{') && contents || '{}'
|
109
|
+
else
|
110
|
+
File.new path, File::CREAT
|
111
|
+
{}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
88
115
|
def self.endless(settings = {}, &block)
|
89
116
|
loop { TwentyFortyEight.play settings, &block }
|
90
117
|
ensure
|
91
118
|
Screen.restore! if settings.verbose?
|
92
119
|
end
|
93
120
|
|
94
|
-
def self.modes
|
95
|
-
(TwentyFortyEight.methods - [:modes, :render_game]) - Object.methods
|
96
|
-
end
|
97
|
-
|
98
121
|
def self.render_game(game, settings, final = false)
|
99
|
-
|
100
|
-
info: [{ highscore: @@best&.score},
|
101
|
-
{ score: game.score, dir: game.current_dir},
|
102
|
-
{ id: @@games.count, move: game.move_count }]}
|
122
|
+
h = { interactive: settings.interactive?, info: [] }
|
103
123
|
|
104
|
-
|
124
|
+
h[:info] << { game: (1 + game.id) } if settings.mode? :endless
|
125
|
+
h[:info] << { highscore: @@highscore[settings.size.to_s], move: game.moves }
|
126
|
+
h[:info] << { score: game.score, dir: game.current_dir}
|
127
|
+
h[:history] = (@@games + [game]) if settings.history?
|
105
128
|
|
106
|
-
return Screen.game_over game,
|
107
|
-
Screen.render game.board.to_a,
|
129
|
+
return Screen.game_over game, h if final
|
130
|
+
Screen.render game.board.to_a, h
|
108
131
|
end
|
109
132
|
end
|
data/lib/TwentyFortyEight/cli.rb
CHANGED
@@ -6,7 +6,7 @@ module TwentyFortyEight
|
|
6
6
|
mode = ARGV[0].to_s.downcase.to_sym
|
7
7
|
settings = defaults_for(mode).merge user_defaults
|
8
8
|
settings[:mode] = mode
|
9
|
-
settings[:mode] = :play unless TwentyFortyEight.
|
9
|
+
settings[:mode] = :play unless TwentyFortyEight::MODES.include? mode
|
10
10
|
|
11
11
|
OptionParser.new do |cli|
|
12
12
|
cli.banner = ''
|
@@ -50,6 +50,11 @@ module TwentyFortyEight
|
|
50
50
|
|
51
51
|
cli.on('--help', 'Display this help') do
|
52
52
|
puts 'usage: 2048 [mode] [options]'
|
53
|
+
puts 'controls:'
|
54
|
+
puts ' W A S D'
|
55
|
+
puts ' K J H L'
|
56
|
+
puts ' ARROW KEYS'
|
57
|
+
puts ''
|
53
58
|
puts 'modes:'
|
54
59
|
puts ' play' + (' ' * 28) + 'Plays the game automatically in order :down, :left, :right, :up'
|
55
60
|
puts ' endless' + (' ' * 25) + 'Loops play until ctrl+C'
|
data/lib/TwentyFortyEight/dsl.rb
CHANGED
@@ -4,20 +4,25 @@ module TwentyFortyEight
|
|
4
4
|
class Dsl
|
5
5
|
attr_reader :settings, :game
|
6
6
|
|
7
|
-
def initialize(settings = {}, &block)
|
7
|
+
def initialize(game, settings = {}, &block)
|
8
8
|
@callable = block
|
9
9
|
@settings = settings
|
10
|
+
@game = game
|
10
11
|
end
|
11
12
|
|
12
13
|
def apply(game)
|
13
14
|
@queue = []
|
14
|
-
@game = game.dup
|
15
|
-
|
16
15
|
instance_eval(&@callable)
|
17
16
|
end
|
18
17
|
|
18
|
+
def quit!
|
19
|
+
game.quit! && :quit
|
20
|
+
end
|
21
|
+
|
19
22
|
def method_missing(sym, *args, &block)
|
20
|
-
return
|
23
|
+
return game.send(sym) if [:won?, :lost?, :changed?, :available,
|
24
|
+
:score, :prev_score].include?(sym)
|
25
|
+
return sym if game.dup.action(sym, insert: false).changed?
|
21
26
|
end
|
22
27
|
|
23
28
|
def respond_to_missing?(sym, *args, &block)
|
@@ -3,9 +3,8 @@ module TwentyFortyEight
|
|
3
3
|
# Game
|
4
4
|
class Game
|
5
5
|
attr_reader :id, :board, :settings, :score, :prev_score, :prev_available,
|
6
|
-
:
|
6
|
+
:moves, :log, :current_dir
|
7
7
|
|
8
|
-
SETTINGS = { size: 4, fill: 0, empty: 0 }.freeze
|
9
8
|
MOVES = [:up, :down, :left, :right].freeze
|
10
9
|
ACTIONS = [*MOVES, :quit].freeze
|
11
10
|
|
@@ -13,8 +12,8 @@ module TwentyFortyEight
|
|
13
12
|
@id = id
|
14
13
|
@score = 0
|
15
14
|
@prev_score = 0
|
16
|
-
@
|
17
|
-
@settings = Options.new
|
15
|
+
@moves = 0
|
16
|
+
@settings = Options.new opts.merge(rest_opts)
|
18
17
|
@board = Board.new(settings)
|
19
18
|
@prev_available = available
|
20
19
|
@current_dir = nil
|
@@ -77,9 +76,9 @@ module TwentyFortyEight
|
|
77
76
|
send dir
|
78
77
|
|
79
78
|
if changed?
|
80
|
-
@
|
79
|
+
@moves += 1
|
81
80
|
|
82
|
-
log << { move:
|
81
|
+
log << { move: moves, score: score, direction: dir } if log
|
83
82
|
insert! unless opts[:insert] == false
|
84
83
|
end
|
85
84
|
|
@@ -84,12 +84,12 @@ module TwentyFortyEight
|
|
84
84
|
def self.handle_keypress(allow_moves = true)
|
85
85
|
case Curses.getch
|
86
86
|
when ' ' then sleep 0.2 until Curses.getch == ' '
|
87
|
-
when Curses::KEY_DOWN, 's' then :down if allow_moves
|
88
|
-
when Curses::KEY_UP, 'w' then :up if allow_moves
|
89
|
-
when Curses::KEY_LEFT, 'a' then :left if allow_moves
|
90
|
-
when Curses::KEY_RIGHT, 'd' then :right if allow_moves
|
91
|
-
when Curses::KEY_CLOSE, 'q'
|
92
|
-
when 'r'
|
87
|
+
when Curses::KEY_DOWN, 's', 'j' then :down if allow_moves
|
88
|
+
when Curses::KEY_UP, 'w', 'k' then :up if allow_moves
|
89
|
+
when Curses::KEY_LEFT, 'a', 'h' then :left if allow_moves
|
90
|
+
when Curses::KEY_RIGHT, 'd', 'l' then :right if allow_moves
|
91
|
+
when Curses::KEY_CLOSE, 'q' then :quit
|
92
|
+
when 'r' then :restart
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: TwentyFortyEight
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sidney Liebrand
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-03-
|
11
|
+
date: 2017-03-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -94,8 +94,8 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
-
description: Play a game of 2048 in the terminal, colorized using Ruby curses. See
|
98
|
-
--help for
|
97
|
+
description: Play a game of 2048 in the terminal, colorized using Ruby curses. (See
|
98
|
+
--help for options / controls)
|
99
99
|
email:
|
100
100
|
- sidneyliebrand@gmail.com
|
101
101
|
executables:
|