-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgame.rb
172 lines (155 loc) · 5.55 KB
/
game.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
require_relative 'board'
require 'yaml'
require 'io/console'
class Game
attr_reader :size
def initialize(player_name, size, difficulty)
@board = Board.new(size, (size * difficulty))
@player_name, @size, @difficulty = player_name, size, difficulty
@attempts, @elapsed, @cursor_pos = 0, 0, [0,0]
end
def play
starting = Process.clock_gettime(Process::CLOCK_MONOTONIC) - @elapsed
won, lost = false, false
until won || lost
system "clear"
@board.print_board
ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
@elapsed = ending - starting
time_string = get_time_string(@elapsed)
print "\nBombs: #{@board.total_bombs} | "
print "Flags: #{@board.flag_count}/#{@board.total_bombs} | "
print "Attempts: #{@attempts}\n"
print "Time Elapsed: #{time_string}\n"
make_a_move()
@attempts += 1
won, lost = @board.solved?, @board.bomb_revealed
end
if won
system "clear"
@board.print_board
print "\nCongrats! You Won!\n"
sleep 3
save_and_print_score()
elsif lost
print_lost_animation()
print "\nYou Lost the Game\n"
sleep 3
end
end
private
def get_time_string(elapsed)
time_str = ""
if elapsed < 60
time_str = elapsed.to_i.to_s + " seconds"
elsif elapsed < 3600
time_str = (elapsed / 60).to_i.to_s + " minutes " + (elapsed % 60).to_i.to_s + " seconds"
else
time_str = (elapsed / 3600).to_i.to_s + " hours " + (elapsed / 60).to_i.to_s + " minutes " + (elapsed % 60).to_i.to_s + " seconds"
end
time_str
end
def make_a_move
instructions = "\nInstructions:"
instructions += "\n > Press UP/DOWN/LEFT/RIGHT arrow key to navigate"
instructions += "\n > Press ENTER to reveal a cell"
instructions += "\n > Press SPACE to flag a cell"
instructions += "\n > Press BACKSPACE to unflag a cell"
instructions += "\n > Press ESCAPE to exit the game\n\n"
print instructions
cmd = get_command()
case cmd
when "\e[A" then move_cursor(-1, 0)
when "\e[B" then move_cursor(1, 0)
when "\e[C" then move_cursor(0, 1)
when "\e[D" then move_cursor(0, -1)
when "\r" then @board.reveal_cell(@cursor_pos)
when " " then @board.flag_cell(@cursor_pos)
when "\177" then @board.unflag_cell(@cursor_pos)
when "\e" then exit 101
else
puts "#{cmd.inspect} is not a valid key"
sleep 2
end
end
def move_cursor(x_val, y_val)
past_pos = @cursor_pos.dup
@cursor_pos[0] = (@cursor_pos[0] + x_val) % size
@cursor_pos[1] = (@cursor_pos[1] + y_val) % size
@board.unselect(past_pos)
@board.select(@cursor_pos)
end
def get_command
STDIN.echo = false
STDIN.raw!
input = STDIN.getc.chr
if input == "\e" then
input << STDIN.read_nonblock(3) rescue nil
input << STDIN.read_nonblock(2) rescue nil
end
ensure
STDIN.echo = true
STDIN.cooked!
return input
end
def get_position
pos = gets.chomp
until pos.match?(/\d,\d/) && pos.split(",").map(&:to_i).all? {|i| i.between?(0, size-1)}
print "\nInvalid position. Try again > "
pos = gets.chomp
end
pos.split(",").map(&:to_i)
end
def print_lost_animation
system "clear"
while @board.reveal_next_bomb
system "clear"
@board.print_board
sleep 0.2
end
end
def save_and_print_score
past_file = Dir["scores/#{@size}_#{@difficulty}.yml"]
past_score = YAML.load(File.read("scores/#{@size}_#{@difficulty}.yml")) unless past_file.empty?
scores = past_file.empty? ? [] : deep_dup(past_score)
file = File.open("scores/#{@size}_#{@difficulty}.yml", "w+")
current_score = [@player_name, @elapsed]
scores << current_score
scores.sort! {|a, b| a.last <=> b.last}
scores = scores[0...20]
file.write(scores.to_yaml)
position = scores.index(current_score) || nil
print_score(scores, position)
end
def deep_dup(array)
array.map {|el| el.is_a?(Array) ? deep_dup(el) : el}
end
def print_score(scores, position)
system "clear"
if position.nil?
print "You didn't make it within Top 20".center(60)
else
print "Wow! You positioned #{position+1} in top 20 list".center(60)
end
print "\n\n"
print "Top 20 Scores".center(60)
print "\n"
print "Board size: #{@size} | Difficulty Level: #{@difficulty}".center(60)
print "\n"
print "="*60 + "\n\n\n"
print "Player Name".center(30) + "Time to Solve".center(30)
print "\n"
print "="*60 + "\n"
scores.each_with_index do |score, idx|
if idx == position
print score.first.center(30).colorize(:light_yellow).on_black
print get_time_string(score.last).center(30).colorize(:light_yellow).on_black
else
print score.first.center(30)
print get_time_string(score.last).center(30)
end
print "\n" + "-"*60 + "\n"
end
sleep 5
end
end