その前にコードをリファクタした
少しよくなったと思う
- BoardクラスをEnumerableにした
- col, rowを1から数えるようにした
1 module Othero
2 class Board
3 include Enumerable
4 attr_reader :size
5 Size = {:small => 6, :medium => 8, :large => 10}
6
7 def initialize(size= :small)
8 @size = Size[size]
9 @cells = Array.new(@size){ Array.new(@size) }
10 end
11
12 def [](col, row)
13 @cells[col-1][row-1]
14 end
15
16 def []=(col, row, *colors)
17 if colors[0]
18 @cells[col-1][row-1] = Piece.new(col, row, *colors)
19 else
20 @cells[col-1][row-1] = nil
21 end
22 end
23
24 def to_s
25 @cells.flatten
26 end
27
28 def each
29 @cells.each { |cols| cols.each { |cell| yield cell } }
30 end
31
32 def each_with_square_index
33 @cells.each_with_index { |cols, i| cols.each_with_index { |cell, j| yield(cell, i+1, j+1) } }
34 end
35
36 def filled_cells
37 select_cells { |c| c }
38 end
39
40 def empty_cells
41 select_cells { |c| c.nil? }
42 end
43
44 private
45 def select_cells
46 result = []
47 self.each_with_square_index { |cell, col, row| result << [col, row] if yield cell }
48 result
49 end
50 end
51
52 class Piece
53 attr_reader :col, :row, :face, :back
54 def initialize(col, row, colors)
55 @col, @row = col, row
56 @face, @back = *colors
57 end
58
59 def to_s
60 @face.to_s
61 end
62
63 def flip
64 @face, @back = @back, @face
65 end
66 end
67 end
68
69 module Draw
70 def initial_set
71 c = Board.size/2
72 Board[c, c] = Colors
73 Board[c+1, c+1] = Colors
74 Board[c+1, c] = Colors.flip
75 Board[c, c+1] = Colors.flip
76 draw_board("Start Game!")
77 end
78
79 def draw_board(msg='')
80 clear do
81 background black
82 stack :margin => Margin do
83 fill BoardColor
84 rect :left => 0, :top => 0, :width => BoardWidth, :height => BoardHeight
85 end
86
87 Board.each_with_square_index do |piece, col, row|
88 left, top = (row-1)*CellWidth+Margin, (col-1)*CellHeight+Margin
89 fill BoardColor; strokewidth 1; stroke rgb(0, 0, 0)
90 rect :left => left, :top => top, :width => CellWidth, :height => CellHeight
91 if piece
92 strokewidth 0
93 fill (piece.face == Colors[1] ? rgb(155,155,155) : rgb(100,100,100))
94 oval left+5, top+6, CellWidth-10, CellHeight-10
95
96 fill (piece.face == Colors[1] ? Color_set[1] : Color_set[0])
97 oval left+4, top+4, CellWidth-10, CellHeight-10
98 else
99 fill BoardColor
100 rect :left => left, :top => top, :width => CellWidth, :height => CellHeight
101 end
102 end
103 draw_message_board(msg)
104 end
105 end
106
107 def draw_message_board(msg)
108 pt1, pt2, elapsed = current_status
109 stack :top => 610, :left => 0, :margin => Margin do
110 background darkorange
111 para "#{msg} #{Colors[0]}:#{pt1} - #{Colors[1]}:#{pt2} #{@flag ? Colors[0] : Colors[1]} turn.", :stroke => darkred
112 end
113 end
114
115 def find_cell(left, top)
116 while left.between?(Margin, Margin+BoardWidth) and top.between?(Margin, Margin+BoardHeight)
117 return (top-Margin)/CellHeight+1, (left-Margin)/CellWidth+1
118 end
119 end
120
121 def current_status
122 cnt_c1, cnt_c2 = 0, 0
123 Board.each do |piece|
124 next unless piece
125 case piece.face
126 when Colors[0]
127 cnt_c1 += 1
128 when Colors[1]
129 cnt_c2 += 1
130 end
131 end
132 elapsed = (cnt_c1+cnt_c2)*100/Board.size**2
133 [cnt_c1, cnt_c2, elapsed]
134 end
135
136 def alert_winner
137 if who = winner?
138 pt1, pt2 = current_status
139 if who
140 alert "#{Colors[who]} wins!! by +#{(pt1-pt2).abs}"
141 else
142 alert "Tie Game"
143 end
144 break
145 end
146 end
147
148 def winner?
149 cnt_c1, cnt_c2 = current_status
150 if (cnt_c1+cnt_c2) == Board.size**2 or (!flippable?(Colors) and !flippable?(Colors.flip))
151 if cnt_c1 > cnt_c2
152 0
153 elsif cnt_c1 < cnt_c2
154 1
155 else
156 -1
157 end
158 else
159 nil
160 end
161 end
162
163 def flip_around?(piece, flip=false)
164 flag = []
165 [:E, :W, :S, :N, :NE, :NW, :SE, :SW].each do |dir|
166 pieces = flippable_line(piece, dir)
167 flag << pieces
168 pieces.each { |p| p.flip } if flip
169 end
170 !flag.all?{ |p| p.empty? }
171 end
172
173 def alert_flippable
174 next_color = @flag ? Colors : Colors.flip
175 unless flippable?(next_color)
176 alert("#{next_color[0]} can't flip any pieces!\n Wait next turn")
177 @flag = !@flag
178 draw_message_board("")
179 end
180 end
181
182 def flippable?(color)
183 Board.empty_cells.each do |col, row|
184 if flip_around?(Othero::Piece.new(col, row, color))
185 return true
186 end
187 end
188 false
189 end
190
191 def lay_piece(col, row)
192 unless Board[col, row]
193 Board[col, row] = @flag ? Colors : Colors.flip
194 @msg = if flip_around?(Board[col, row], true)
195 @flag = !@flag
196 "Yeh! Good one!"
197 else
198 Board[col, row] = nil
199 "Wrong place!"
200 end
201 end
202 end
203
204 private
205 def flippable_line(piece, dir)
206 col, row = piece.col, piece.row
207 case dir
208 when :E
209 check_line(piece, col, row, op(:+, 0), op(:+, 1))
210 when :W
211 check_line(piece, col, row, op(:+, 0), op(:-, 1))
212 when :S
213 check_line(piece, col, row, op(:+, 1), op(:+, 0))
214 when :N
215 check_line(piece, col, row, op(:-, 1), op(:+, 0))
216 when :NE
217 check_line(piece, col, row, op(:-, 1), op(:+, 1))
218 when :NW
219 check_line(piece, col, row, op(:-, 1), op(:-, 1))
220 when :SE
221 check_line(piece, col, row, op(:+, 1), op(:+, 1))
222 when :SW
223 check_line(piece, col, row, op(:+, 1), op(:-, 1))
224 end
225 end
226
227 def op(op, arg)
228 lambda { |x| x.send(op, arg) }
229 end
230
231 def check_line(piece, col, row, op_col, op_row)
232 col = op_col[col]; row = op_row[row]
233 list = []
234 while col.between?(1, Board.size) and row.between?(1, Board.size)
235 if Board[col, row].nil?
236 return list.clear
237 elsif Board[col, row].face == piece.face
238 return list
239 else
240 list << Board[col, row]
241 end
242 col = op_col[col]; row = op_row[row]
243 end
244 list.clear
245 end
246 end
247
248 module NetService
249 require "drb/drb"
250 def service_start(host='192.168.1.3', port=12345)
251 @front = {}
252 DRb.start_service("druby://#{host}:#{port}", @front)
253 end
254
255 def connect_service(host='192.168.1.3', port=12345)
256 DRb.start_service
257 DRbObject.new_with_uri("druby://#{host}:#{port}")
258 end
259
260 class Pipe
261 def put(col, row)
262 msg = BOARD.lay_piece(col, row)
263 BOARD.draw_board(msg)
264 BOARD.alert_winner
265 BOARD.alert_flippable
266 end
267 end
268 end
269
270 BOARD = Shoes.app :width => 620, :height => 670 do
271 extend Draw
272 extend NetService
273 Board = Othero::Board.new(:small)
274 # service_start()
275 # @front[1] = DRbObject.new(NetService::Pipe.new)
276
277 BoardWidth, BoardHeight = 600, 600
278 Margin = 10
279 CellWidth, CellHeight = BoardWidth/Board.size, BoardHeight/Board.size
280 BoardColor = rgb(0, 50, 150)
281 Colors = [:Black, :White]
282 Color_set = [black, white]
283 def Colors.flip
284 self.reverse
285 end
286
287 initial_set
288
289 @flag = true
290
291 click do |button, left, top|
292 col, row = find_cell(left, top)
293 msg = lay_piece(col, row)
294 # @front[2].put(col, row)
295 draw_board(msg)
296 end
297
298 release do
299 alert_winner
300 alert_flippable
301 end
302 end
No comments:
Post a Comment