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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fe83920a037beecde5b1bfb7abe7c81f6722a90a
4
- data.tar.gz: 6506f6288be1a550cb4fee734797f7d933a7eab1
3
+ metadata.gz: 169c96337916c0265c9bcf9f76ed322a221728be
4
+ data.tar.gz: 7712f1815cc6a4e4abe44c1da513354c2b6c6be7
5
5
  SHA512:
6
- metadata.gz: '039c7e5d4462a0191bd0c21de97b129ba74dad41a8224161f878f93b4a45b02faa4c3fece018b242d2f7d100cf17acfe49787c6caef414294771e51268cce82d'
7
- data.tar.gz: 656d2266224a829cd6c2ba195670d0b943607827e9f1955f65f29f1e2e72194efc8d538795ee238f58c4c3b1036287a3f7c71740821e7a0259b1c2ebeaf442cc
6
+ metadata.gz: 49c55706b034d1a427dd69939bdf202eec5b97476b365fc0e95b6e3cdacc405dd6fa990939443f145603e4f365a4c93d129857106bade1cba5ff7145dd2aee23
7
+ data.tar.gz: e0c82620996f5656a79057d50425d1ab9b104d001f0cefceb22ffb17795fb114abab60e4ac3a7b2d69da2f86e947559e1b7a697aa5932e8dff8c441271bf10e7
@@ -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 more options)'
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
 
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "bundler/setup"
4
- require "TwentyFortyEight"
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
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
9
+ @game = TwentyFortyEight.endless verbose: true do
10
+ down || left || right || up
11
+ end
12
12
 
13
- require "irb"
14
- IRB.start(__FILE__)
13
+ require 'pry'
14
+ Pry.start
@@ -11,17 +11,20 @@ require_relative 'TwentyFortyEight/screen'
11
11
  require_relative 'TwentyFortyEight/dsl'
12
12
 
13
13
  module TwentyFortyEight
14
- @@games = []
15
- @@best = nil
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 if settings.is_a? Hash
21
+ settings = Options.new SETTINGS.merge(settings)
19
22
  game = Game.new @@games.count, settings
20
23
  dirs = game.directions - (settings.except || [])
21
- dirs = dirs - (settings.only || [])
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
- @@best ||= game
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
- print_extra = { interactive: settings.interactive?,
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
- print_extra[:history] = (@@games + [game]) if settings.history?
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, print_extra if final
107
- Screen.render game.board.to_a, print_extra
129
+ return Screen.game_over game, h if final
130
+ Screen.render game.board.to_a, h
108
131
  end
109
132
  end
@@ -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.modes.include? mode
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'
@@ -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 sym if game.action(sym, insert: false).changed?
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
- :move_count, :log, :current_dir
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
- @move_count = 0
17
- @settings = Options.new SETTINGS.merge(opts).merge(rest_opts)
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
- @move_count += 1
79
+ @moves += 1
81
80
 
82
- log << { move: move_count, score: score, direction: dir } if log
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' then :quit
92
- when 'r' then :restart
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
 
@@ -1,3 +1,3 @@
1
1
  module TwentyFortyEight
2
- VERSION = '0.1.1'
2
+ VERSION = '0.2.0'
3
3
  end
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.1.1
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-19 00:00:00.000000000 Z
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 more options)
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: