- コンピューター対戦
- ネットワーク対戦
1 module Othero
2 class Board
3 Size = {:small => 6, :medium => 8, :large => 10}
4 attr_reader :size
5
6 def initialize(size= :small)
7 @size = Size[size]
8 @cells = Array.new(@size){ Array.new(@size) }
9 end
10
11 def [](row, col)
12 @cells[col][row]
13 end
14
15 def []=(row, col, *colors)
16 if colors[0]
17 @cells[col][row] = Piece.new(row, col, *colors)
18 else
19 @cells[col][row] = nil
20 end
21 end
22
23 def cells
24 @cells
25 end
26 end
27
28 class Piece
29 attr_reader :col, :row, :face, :back
30 def initialize(row, col, colors)
31 @row, @col = row, col
32 @face, @back = *colors
33 end
34
35 def to_s
36 @face
37 end
38
39 def flip
40 @face, @back = @back, @face
41 end
42 end
43 end
44
45 module Draw
46 def initial_set
47 c = Board.size/2
48 Board[c, c] = Colors
49 Board[c-1, c-1] = Colors
50 Board[c-1, c] = Colors.reverse
51 Board[c, c-1] = Colors.reverse
52 draw_board("Start Game!")
53 end
54
55 def draw_board(msg=nil)
56 clear do
57 background black
58 stack :margin => Margin do
59 fill rgb(0, 190, 0)
60 rect :left => 0, :top => 0, :width => BoardWidth, :height => BoardHeight
61 end
62
63 Board.cells.each_with_index do |rows, i|
64 rows.each_with_index do |piece, j|
65 left, top = i*CellWidth+Margin, j*CellHeight+Margin
66 fill rgb(0, 440, 0, 90); strokewidth 1; stroke rgb(0, 100, 0)
67 rect :left => left, :top => top, :width => CellWidth, :height => CellHeight
68 if piece
69 strokewidth 0
70 fill (piece.to_s == Colors[1] ? rgb(155,155,155) : rgb(100,100,100))
71 oval left+5, top+6, CellWidth-10, CellHeight-10
72
73 fill (piece.to_s == Colors[1] ? Color_set[1] : Color_set[0])
74 oval left+4, top+4, CellWidth-10, CellHeight-10
75 else
76 fill rgb(0, 190, 0)
77 rect :left => left, :top => top, :width => CellWidth, :height => CellHeight
78 end
79 end
80 end
81 draw_message_board(msg)
82 end
83 end
84
85 def draw_message_board(msg)
86 stack :top => 610, :left => 0, :margin => Margin do
87 background yellow
88 para msg
89 end
90 end
91
92 def find_cell(y, x)
93 while x.between?(Margin, Margin+BoardWidth) and y.between?(Margin, Margin+BoardHeight)
94 return (x-Margin)/CellWidth, (y-Margin)/CellHeight
95 end
96 end
97
98 def current_status
99 cnt_c1, cnt_c2 = 0, 0
100 Board.cells.each_with_index do |rows, i|
101 rows.each_with_index do |piece, j|
102 next unless piece
103 case piece.face
104 when Colors[0]
105 cnt_c1 += 1
106 when Colors[1]
107 cnt_c2 += 1
108 end
109 end
110 end
111 elapsed = (cnt_c1+cnt_c2)*100/Board.size**2
112 [cnt_c1, cnt_c2, elapsed]
113 end
114
115 def winner?
116 cnt_c1, cnt_c2 = current_status
117 if (cnt_c1+cnt_c2) == Board.size**2 or (!flippable?(Colors) and !flippable?(Colors.reverse))
118 if cnt_c1 > cnt_c2
119 0
120 elsif cnt_c1 < cnt_c2
121 1
122 else
123 -1
124 end
125 else
126 nil
127 end
128 end
129
130 def flip_around?(piece, flip=false)
131 flag = []
132 [:E, :W, :S, :N, :NE, :NW, :SE, :SW].each do |dir|
133 pieces = flippable_line(piece, dir)
134 flag << pieces
135 pieces.each { |p| p.flip } if flip
136 end
137 !flag.all?{ |p| p.empty? }
138 end
139
140 def flippable?(color)
141 free_cells.each do |row, col|
142 if flip_around?(Othero::Piece.new(row, col, color))
143 return true
144 end
145 end
146 false
147 end
148
149 private
150 def flippable_line(piece, dir)
151 row, col = piece.row, piece.col
152 case dir
153 when :E
154 check_line(piece, row, col, op(:+, 0), op(:+, 1))
155 when :W
156 check_line(piece, row, col, op(:+, 0), op(:-, 1))
157 when :S
158 check_line(piece, row, col, op(:+, 1), op(:+, 0))
159 when :N
160 check_line(piece, row, col, op(:-, 1), op(:+, 0))
161 when :NE
162 check_line(piece, row, col, op(:-, 1), op(:+, 1))
163 when :NW
164 check_line(piece, row, col, op(:-, 1), op(:-, 1))
165 when :SE
166 check_line(piece, row, col, op(:+, 1), op(:+, 1))
167 when :SW
168 check_line(piece, row, col, op(:+, 1), op(:-, 1))
169 end
170 end
171
172 def op(op, arg=1)
173 lambda { |x| x.send(op, arg) }
174 end
175
176 def check_line(piece, row, col, op_row, op_col)
177 row = op_row[row]; col = op_col[col]
178 list = []
179 while col.between?(0, Board.size-1) and row.between?(0, Board.size-1)
180 if Board[row, col].nil?
181 return list.clear
182 elsif Board[row, col].face == piece.face
183 return list
184 else
185 list << Board[row, col]
186 end
187 row = op_row[row]; col = op_col[col]
188 end
189 list.clear
190 end
191
192 def free_cells
193 fc = []
194 Board.cells.each_with_index do |rows, i|
195 rows.each_with_index do |cell, j|
196 fc << [j, i] unless cell
197 end
198 end
199 fc
200 end
201 end
202
203 Shoes.app :width => 620, :height => 670 do
204 extend Draw
205 Board = Othero::Board.new(:small)
206
207 BoardWidth, BoardHeight = 600, 600
208 Margin = 10
209 CellWidth, CellHeight = BoardWidth/Board.size, BoardHeight/Board.size
210 Colors = [:Black, :White]
211 Color_set = [black, white]
212
213 initial_set
214
215 flag = true
216
217 click do |button, left, top|
218 row, col = find_cell(left, top)
219 unless Board[row, col]
220 Board[row, col] = flag ? Colors : Colors.reverse
221 msg = if flip_around?(Board[row, col], true)
222 flag = !flag
223 "Yeh! Good one!"
224 else
225 Board[row, col] = nil
226 "Wrong place!"
227 end
228
229 pt1, pt2, elapsed = current_status
230
231 draw_board msg + " #{Colors[0]}:#{pt1} - #{Colors[1]}:#{pt2}(#{elapsed}%)" + " #{flag ? Colors[0] : Colors[1]} turn."
232 end
233 end
234
235 release do |button, x, y|
236 computer_turn
237 if who = winner?
238 pt1, pt2 = current_status
239 if who
240 alert "#{Colors[who]} wins!! by #{pt1 > pt2 ? pt1 : pt2}"
241 else
242 alert "Tie Game"
243 end
244 break
245 end
246
247 next_color = flag ? Colors : Colors.reverse
248 unless flippable?(next_color)
249 alert("#{next_color[0]} can't flip any pieces!")
250 flag = !flag
251 draw_message_board("#{next_color[1]} turn")
252 end
253 end
254 end
No comments:
Post a Comment