TwentyFortyEight 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|