├── .gitignore
├── .idea
├── Gomoku.iml
├── misc.xml
├── modules.xml
├── vcs.xml
└── workspace.xml
├── GUI.py
├── Point.py
├── README.md
├── Record.py
├── main.py
└── screenshot.png
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 |
--------------------------------------------------------------------------------
/.idea/Gomoku.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
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 |
75 |
76 |
77 |
78 |
79 | true
80 | DEFINITION_ORDER
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 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 | 1465214550054
384 |
385 |
386 | 1465214550054
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
--------------------------------------------------------------------------------
/GUI.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #-*- coding: utf-8 -*-
3 |
4 | import Tkinter
5 | import math
6 | import Point
7 | import Record
8 |
9 | class Chess_Board_Canvas(Tkinter.Canvas):
10 | #棋盘绘图板,继承自Tkinter.Canvas类
11 | def __init__(self, master=None, height=0, width=0):
12 | '''
13 | 棋盘类初始化
14 | :param master: 画到那个对象
15 | :param height: 棋盘的高度
16 | :param width: 棋盘的宽度
17 | '''
18 | Tkinter.Canvas.__init__(self, master, height=height, width=width)
19 | self.step_record_chess_board = Record.Step_Record_Chess_Board()
20 | #初始化计步器对象
21 | self.init_chess_board_points() #画点
22 | self.init_chess_board_canvas() #绘制棋盘
23 |
24 | def init_chess_board_points(self):
25 | '''
26 | 生成各个棋盘点,根据棋盘坐标生成像素表座
27 | 并且保存到 chess_board_points 属性
28 | :return:
29 | '''
30 | self.chess_board_points = [[None for i in range(15)] for j in range(15)]
31 |
32 | for i in range(15):
33 | for j in range(15):
34 | self.chess_board_points[i][j] = Point.Point(i, j); #棋盘坐标向像素坐标转化
35 |
36 | def init_chess_board_canvas(self):
37 | '''
38 | 初始化棋盘
39 | :return:
40 | '''
41 |
42 | for i in range(15): #绘制竖线
43 | self.create_line(self.chess_board_points[i][0].pixel_x, self.chess_board_points[i][0].pixel_y, self.chess_board_points[i][14].pixel_x, self.chess_board_points[i][14].pixel_y)
44 |
45 | for j in range(15): #绘制横线
46 | self.create_line(self.chess_board_points[0][j].pixel_x, self.chess_board_points[0][j].pixel_y, self.chess_board_points[14][j].pixel_x, self.chess_board_points[14][j].pixel_y)
47 |
48 | for i in range(15): #绘制椭圆,但是这个功能似乎是要加强交点的视觉效果,但是效果一般,视错觉没有出现
49 | for j in range(15):
50 | r = 1
51 | self.create_oval(self.chess_board_points[i][j].pixel_x-r, self.chess_board_points[i][j].pixel_y-r, self.chess_board_points[i][j].pixel_x+r, self.chess_board_points[i][j].pixel_y+r);
52 |
53 | def click1(self, event): #为何是click1因为关键字重复
54 | '''
55 | 侦听鼠标事件,根据鼠标的位置判断落点
56 | :param event:
57 | :return:
58 | '''
59 | for i in range(15):
60 | for j in range(15):
61 | square_distance = math.pow((event.x - self.chess_board_points[i][j].pixel_x), 2) + math.pow((event.y - self.chess_board_points[i][j].pixel_y), 2)
62 | #计算鼠标的位置和点的距离
63 | #距离小于14的点
64 | #这里其实有更优化的做法就是根据鼠标的位置计算点
65 | #pyganme开发里面似乎有这个算法
66 |
67 | if (square_distance <= 200) and (not self.step_record_chess_board.has_record(i, j)): #距离小于14并且没有落子
68 | if self.step_record_chess_board.who_to_play() == 1:
69 | #若果根据步数判断是奇数次,那么白下
70 | self.create_oval(self.chess_board_points[i][j].pixel_x-10, self.chess_board_points[i][j].pixel_y-10, self.chess_board_points[i][j].pixel_x+10, self.chess_board_points[i][j].pixel_y+10, fill='red')
71 |
72 | elif self.step_record_chess_board.who_to_play() == 2:
73 | self.create_oval(self.chess_board_points[i][j].pixel_x-10, self.chess_board_points[i][j].pixel_y-10, self.chess_board_points[i][j].pixel_x+10, self.chess_board_points[i][j].pixel_y+10, fill='green')
74 |
75 | self.step_record_chess_board.insert_record(i, j)
76 | #插入落子数据,落子最多225,这个程序没有实现AI
77 |
78 | result = self.step_record_chess_board.check()
79 | #判断是否有五子连珠
80 |
81 |
82 | if result == 1:
83 | self.create_text(240, 550, text='the white wins')
84 | #解除鼠标左键绑定
85 | self.unbind('')
86 | # """Unbind for this widget for event SEQUENCE the
87 | # function identified with FUNCID."""
88 |
89 | elif result == 2:
90 | self.create_text(240, 550, text='the black wins')
91 | #解除鼠标左键绑定
92 | self.unbind('')
93 |
94 |
95 | class Chess_Board_Frame(Tkinter.Frame):
96 | def __init__(self, master=None):
97 | Tkinter.Frame.__init__(self, master)
98 | self.create_widgets()
99 |
100 | def create_widgets(self):
101 | self.chess_board_label_frame = Tkinter.LabelFrame(self, text="Chess Board", padx=5, pady=5)
102 | self.chess_board_canvas = Chess_Board_Canvas(self.chess_board_label_frame, height=600, width=480)
103 |
104 | self.chess_board_canvas.bind('', self.chess_board_canvas.click1)
105 |
106 | self.chess_board_label_frame.pack();
107 | self.chess_board_canvas.pack();
108 |
--------------------------------------------------------------------------------
/Point.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #-*- coding: utf-8 -*-
3 |
4 | class Point:
5 |
6 | def __init__(self, x, y):
7 | '''
8 | 点,生成棋盘上的交点,并计算每个棋子多赢的实际像素坐标
9 | 棋盘坐标和像素坐标的转换
10 | :param x:
11 | :param y:
12 | '''
13 | self.x = x;
14 | self.y = y;
15 | self.pixel_x = 30 + 30 * self.x
16 | self.pixel_y = 30 + 30 * self.y
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #GOMOKU
2 |
3 | ##Overview
4 | *Gomoku*, a very easy and light computher game implemented with python and Tkinter.
5 |
6 | Gomoku, 这是一个非常简单的轻量级的电脑游戏,这款游戏被用Python语言和Tkinter图形库实现。
7 |
8 | ##Screenshot
9 | 
10 |
11 | ##Version
12 | * ###version 1.0
13 | Basic Functions that you can play with other player
14 | 实现了可以去其他玩家一起下棋的基本功能
15 |
16 | ##Donate
17 | if you like my application, you can donate for us. And we will release update and support more and more good applications.
18 | 如果你喜欢我的应用,你可以给我捐款。这样鼓励我们推出更多更新,并提供越来越好的应用。
19 |
--------------------------------------------------------------------------------
/Record.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #-*- coding: utf-8 -*-
3 |
4 | class Step_Record:
5 | def __init__(self, count):
6 | """
7 | :param count: int default 1
8 |
9 | 记录走步,根据当前步数,初始值为1
10 | 颜色是加1模2再加1
11 | 用1和0来区分黑白两色
12 | 先走的1是黑
13 | 后奏的是白
14 | """
15 | self.count = count
16 | self.color = (self.count+1) % 2 + 1;
17 |
18 |
19 |
20 | class Step_Record_Chess_Board:
21 | def __init__(self):
22 | """
23 | 初始化棋盘记录
24 | """
25 | self.count = 1;
26 | self.records = [[None for i in range(15)] for j in range(15)]
27 | #初始化棋盘15x15,如果没有落子,棋盘值是None
28 |
29 | def has_record(self, x, y):
30 | """
31 |
32 | :param x: 棋子横坐标
33 | :param y: 棋子中坐标
34 | :return: 返回某处是否已经落子,通过判断棋盘位置是否是None实现
35 | 如果不是None就是已经落子的了
36 | """
37 | return not self.records[x][y] == None
38 |
39 | def insert_record(self, x, y):
40 | '''
41 |
42 | :param x: 棋子横坐标
43 | :param y: 棋子纵坐标
44 | :return: 没有返回值
45 | 和一般的程序不同的是,棋盘上每个坐标都是一个Step_Record对象
46 | 黑子还是白字看属性,这样开销是否大呢
47 | 根据步数落子,步数可以判断是黑子还是白子
48 | 步数加1
49 | '''
50 | self.records[x][y] = Step_Record(self.count)
51 | print '{0}'.format('white' if ((self.count+1) % 2 + 1) == 1 else 'black') ,'< x:', x, ', y:', y,'>'
52 |
53 | self.count += 1;
54 |
55 | def who_to_play(self):
56 | '''
57 |
58 | :return: 判断谁改走了
59 | '''
60 | return (self.count+1) % 2 + 1
61 |
62 | def check_row(self, x, y):
63 | """
64 | :param x:
65 | :param y:
66 | :return:
67 |
68 | 检测行里是否连续的5个子
69 | """
70 | if self.has_record(x, y) and self.has_record(x, y+1) and self.has_record(x, y+2) and self.has_record(x, y+3) and self.has_record(x, y+4):
71 | #判断一个子右侧是否5个连续有子,如果是判断是否连续的黑色或者白色,返回1或者2代表胜利
72 | if self.records[x][y].color == 1 and self.records[x][y+1].color == 1 and self.records[x][y+2].color == 1 and self.records[x][y+3].color == 1 and self.records[x][y+4].color == 1:
73 | return 1;
74 |
75 | elif self.records[x][y].color == 2 and self.records[x][y+1].color == 2 and self.records[x][y+2].color == 2 and self.records[x][y+3].color == 2 and self.records[x][y+4].color == 2:
76 | return 2;
77 |
78 | else:
79 | return 0;
80 |
81 | def check_col(self, x, y):
82 | """
83 | 检测列里是否有连续的5个子
84 | :param x:
85 | :param y:
86 | :return:
87 | """
88 | if self.has_record(x, y) and self.has_record(x+1, y) and self.has_record(x+2, y) and self.has_record(x+3, y) and self.has_record(x+4, y):
89 |
90 | if self.records[x][y].color == 1 and self.records[x+1][y].color == 1 and self.records[x+2][y].color == 1 and self.records[x+3][y].color == 1 and self.records[x+4][y].color == 1:
91 | return 1;
92 |
93 | elif self.records[x][y].color == 2 and self.records[x+1][y].color == 2 and self.records[x+2][y].color == 2 and self.records[x+3][y].color == 2 and self.records[x+4][y].color == 2:
94 | return 2;
95 |
96 | else:
97 | return 0;
98 |
99 | def check_up(self, x, y):
100 | '''
101 | 检测/斜线方向是否有连续的子
102 | :param x:
103 | :param y:
104 | :return:
105 | '''
106 | if self.has_record(x, y) and self.has_record(x+1, y+1) and self.has_record(x+2, y+2) and self.has_record(x+3, y+3) and self.has_record(x+4, y+4):
107 |
108 | if self.records[x][y].color == 1 and self.records[x+1][y+1].color == 1 and self.records[x+2][y+2].color == 1 and self.records[x+3][y+3].color == 1 and self.records[x+4][y+4].color == 1:
109 | return 1;
110 |
111 | elif self.records[x][y].color == 2 and self.records[x+1][y+1].color == 2 and self.records[x+2][y+2].color == 2 and self.records[x+3][y+3].color == 2 and self.records[x+4][y+4].color == 2:
112 | return 2;
113 |
114 | else:
115 | return 0;
116 |
117 | def check_down(self, x, y):
118 | '''
119 | 检测\方向是否有连续的子
120 | :param x:
121 | :param y:
122 | :return:
123 | '''
124 | if self.has_record(x, y) and self.has_record(x+1, y-1) and self.has_record(x+2, y-2) and self.has_record(x+3, y-3) and self.has_record(x+4, y-4):
125 |
126 | if self.records[x][y].color == 1 and self.records[x+1][y-1].color == 1 and self.records[x+2][y-2].color == 1 and self.records[x+3][y-3].color == 1 and self.records[x+4][y-4].color == 1:
127 | return 1;
128 |
129 | elif self.records[x][y].color == 2 and self.records[x+1][y-1].color == 2 and self.records[x+2][y-2].color == 2 and self.records[x+3][y-3].color == 2 and self.records[x+4][y-4].color == 2:
130 | return 2;
131 |
132 | else:
133 | return 0;
134 |
135 |
136 | def check(self):
137 | '''
138 | 遍历棋盘,检测是否是全部有子
139 | 这里每次都是全面扫描棋盘,实际上可以优化
140 | 初期有很多列是没有落子的所以不必扫描
141 | :return:
142 | '''
143 | for i in range(15):
144 | for j in range(11): #没有必要到15,否则会报错的
145 | result = self.check_row(i, j)
146 | if result != 0:
147 | return result
148 |
149 | for i in range(11):
150 | for j in range(15):
151 | result = self.check_col(i, j)
152 | if result != 0:
153 | return result
154 |
155 | for i in range(11):
156 | for j in range(11):
157 | result = self.check_up(i, j)
158 | if result != 0:
159 | return result
160 |
161 | for i in range(11):
162 | for j in range(4, 15):
163 | result = self.check_down(i, j)
164 | if result != 0:
165 | return result
166 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #-*- coding: utf-8 -*-
3 |
4 | import GUI
5 | import Tkinter
6 |
7 | if __name__ == '__main__':
8 | window = Tkinter.Tk()
9 | gui_chess_board = GUI.Chess_Board_Frame(window)
10 | gui_chess_board.pack()
11 | window.mainloop()
12 |
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jamesxu182/Gomoku/daa6ca1fef4147f614f36c70285def70463c7463/screenshot.png
--------------------------------------------------------------------------------