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 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: