-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgame.rb
152 lines (125 loc) · 3.02 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
require "active_record"
ActiveRecord::Base.establish_connection(
adapter: 'sqlite3',
database: 'db.sqlite3'
)
ActiveRecord::Schema.define do
create_table :games do |t|
t.string :game
t.string :state
t.string :board
t.string :mine_locations
t.integer :difficulty
t.timestamps
end
end
class Game < ActiveRecord::Base
serialize :board, Array
serialize :mine_locations, Array
EMPTY = " "
MINE = "*"
FLAG = "F"
SAFE = "@"
CLEAR = "_"
before_create :make_board
def make_board
self.board = size.times.map { size.times.map { EMPTY } }
end
def place_mines(row, col)
self.state = "playing"
while mine_locations.length < mine_count
loc = [rand(size), rand(size)]
banned_locations = [
[row - 1, col - 1],
[row + 0, col - 1],
[row + 1, col - 1],
[row - 1, col + 0],
[row + 0, col + 0],
[row + 1, col + 0],
[row - 1, col + 1],
[row + 0, col + 1],
[row + 1, col + 1],
]
banned_locations.concat(mine_locations)
mine_locations << loc unless banned_locations.include?(loc)
end
end
def flag(row, col)
if board[row][col] == EMPTY
board[row][col] = FLAG
elsif board[row][col] == FLAG
board[row][col] = EMPTY
end
end
def out_of_bounds?(row, col)
row < 0 || col < 0 || row >= size || col >= size
end
def check(row, col)
# If we don't have any mines, go ahead and place them
place_mines(row, col) if mine_locations.empty?
# If the player is checking a mine space
if mine_locations.include?([row, col])
self.state = "lost"
mine_locations.each do |r, c|
if board[r][c] == FLAG
board[r][c] = SAFE
else
board[r][c] = MINE
end
end
return
end
reveal(row, col)
if board.flatten.count { |cell| [EMPTY, FLAG].include?(cell) } == mine_locations.length
self.state = "won"
mine_locations.each { |row, col| board[row][col] = MINE }
end
end
def reveal(row, col)
if (count = mine_count_for(row, col)) > 0
board[row][col] = count
return
else
board[row][col] = CLEAR
end
(-1..1).each do |y|
(-1..1).each do |x|
neighbor = [row + y, col + x]
next if x == 0 && y == 0
next if out_of_bounds?(*neighbor)
next if revealed?(*neighbor)
reveal(*neighbor)
end
end
end
def mine_count_for(row, col)
total = 0
(-1..1).each do |y|
(-1..1).each do |x|
total += 1 if mine_locations.include?([row + y, col + x])
end
end
total
end
def revealed?(row, col)
![EMPTY, MINE].include?(board[row][col])
end
def flag_count
board.flatten.count { |cell| cell == FLAG }
end
def size
[8, 16, 24][difficulty]
end
def mine_count
[10, 40, 99][difficulty]
end
def as_json(*)
{
"id": id,
"board": board,
"state": state,
"mines": [10, 40, 99][difficulty] - flag_count,
"difficulty": difficulty,
}
end
end