20192305 王梓全Python程序設(shè)計實驗四報告
20192305 王梓全Python程序設(shè)計實驗四報告
課程:《Python程序設(shè)計》
班級: 1923
姓名: 王梓全
學(xué)號:20192305
實驗教師:王志強
實驗日期:2021年6月14日
必修/選修:公選課
1.實驗內(nèi)容
- 1.Python綜合應(yīng)用:爬蟲、數(shù)據(jù)處理、可視化、機器學(xué)習(xí)、神經(jīng)網(wǎng)絡(luò)、游戲、網(wǎng)絡(luò)安全等;
- 2.結(jié)合手頭的python教學(xué)書,我選擇了編寫一個五子棋游戲
2.實驗過程及結(jié)果
- 先設(shè)計一個15x15的標(biāo)準(zhǔn)五子棋棋盤
- 由于四周留下空缺后計算點位時將會更加麻煩,故我的棋盤四周未留下空缺
import random
import pygame
from pygame.locals import MOUSEBUTTONUP
pygame.init()
cell_size = 40
cell_num = 15
grid_size = cell_size * (cell_num - 1)
screencaption = pygame.display.set_caption('五子棋')
screen = pygame.display.set_mode((grid_size, grid_size))
定義一個chess_arr用于儲存棋子的位置,監(jiān)聽鼠標(biāo)彈起的位置后,將該點的坐標(biāo)保存入數(shù)組chess_arr flag = 1
state = 1
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
if state == 1 and event.type == pygame.MOUSEBUTTONUP:
x, y = pygame.mouse.get_pos()
screen.fill((238, 232, 170))
鼠標(biāo)彈起的位置不一定是在縱橫線的交界點,故需要對每個落點xi,yi的位置進行限定,修改如下
xi = int(round((x) * 1.0 / cell_size))
yi = int(round((y) * 1.0 / cell_size))
對重復(fù)落點處進行判斷,若為新點則正常進行落點,否則,落點無效
if xi >= 0 and xi < cell_num and yi >= 0 and yi < cell_num and (xi, yi, 1) not in chess_arr and (
xi, yi, 2) not in chess_arr:
chess_arr.append((xi, yi, flag))
if check_win(chess_arr, flag):
state = 2 if flag == 1 else 3
else:
flag = 2 if flag == 1 else 1
將棋盤線繪制上,同時設(shè)置在落點處畫圓代表落子
for x in range(0, cell_size * cell_num, cell_size):
pygame.draw.line(screen, (200, 200, 200), (x, 0 ),
(x, cell_size * (cell_num - 1)), 1)
for y in range(0, cell_size * cell_num, cell_size):
pygame.draw.line(screen, (200, 200, 200), (0, y),
(cell_size * (cell_num - 1), y), 1)
for x, y, c in chess_arr:
chess_color = (30, 30, 30) if c == 1 else (225, 225, 225)
pygame.draw.circle(screen, chess_color, [x * cell_size, y * cell_size], 16, 16)
定義一個判斷落點位置的函數(shù)
def get_one_dire_num(lx, ly, dx, dy, m):
tx = lx
ty = ly
s = 0
while True:
tx += dx
ty += dy
if tx < 0 or tx >= cell_num or ty < 0 or ty >= cell_num or m[ty][tx] == 0: return s
s += 1
定義一個檢查最終是否勝利的函數(shù),若一點周圍左上兩點中,右上兩點中,左下兩點中,右下兩點中的一點均有同一方的子存在,則判定其為勝利
def check_win(chess_arr, flag):
m = [[0] * cell_num for i in range(cell_num)]
for x, y, c in chess_arr:
if c == flag:
m[y][x] = 1
lx = chess_arr[-1][0]
ly = chess_arr[-1][1]
dire_arr = [[(-1, 0), (1, 0)], [(0, -1), (0, 1)], [(-1, -1), (1, 1)],
[(-1, 1), (1, -1)]]
進行最后的修正,將棋盤顏色設(shè)置為木頭的顏色,將勝利提示設(shè)置為黃色,將所有的更改體現(xiàn)在屏幕上
screen.fill((238, 232, 170))
if state != 1:
myfont = pygame.font.Font(None, 60)
white = 210, 210, 0
win_text = "IS %s" % ('black' if state == 2 else 'white')
textImage = myfont.render(win_text, True, white)
screen.blit(textImage, (260, 320))
pygame.display.update()
最終代碼:
import random
import pygame
from pygame.locals import MOUSEBUTTONUP
pygame.init()
cell_size = 40
cell_num = 15
grid_size = cell_size * (cell_num - 1)
screencaption = pygame.display.set_caption('五子棋')
screen = pygame.display.set_mode((grid_size, grid_size))
chess_arr = []
flag = 1
state = 1
def get_one_dire_num(lx, ly, dx, dy, m):
tx = lx
ty = ly
s = 0
while True:
tx += dx
ty += dy
if tx < 0 or tx >= cell_num or ty < 0 or ty >= cell_num or m[ty][tx] == 0: return s
s += 1
def check_win(chess_arr, flag):
m = [[0] * cell_num for i in range(cell_num)]
for x, y, c in chess_arr:
if c == flag:
m[y][x] = 1
lx = chess_arr[-1][0]
ly = chess_arr[-1][1]
dire_arr = [[(-1, 0), (1, 0)], [(0, -1), (0, 1)], [(-1, -1), (1, 1)],
[(-1, 1), (1, -1)]]
for dire1, dire2 in dire_arr:
dx, dy = dire1
num1 = get_one_dire_num(lx, ly, dx, dy, m)
dx, dy = dire2
num2 = get_one_dire_num(lx, ly, dx, dy, m)
if num1 + num2 + 1 >= 5: return True
return False
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
if state == 1 and event.type == pygame.MOUSEBUTTONUP:
x, y = pygame.mouse.get_pos()
xi = int(round((x) * 1.0 / cell_size))
yi = int(round((y) * 1.0 / cell_size))
if xi >= 0 and xi < cell_num and yi >= 0 and yi < cell_num and (xi, yi, 1) not in chess_arr and (
xi, yi, 2) not in chess_arr:
chess_arr.append((xi, yi, flag))
if check_win(chess_arr, flag):
state = 2 if flag == 1 else 3
else:
flag = 2 if flag == 1 else 1
screen.fill((238, 232, 170))
for x in range(0, cell_size * cell_num, cell_size):
pygame.draw.line(screen, (200, 200, 200), (x, 0 ),
(x, cell_size * (cell_num - 1)), 1)
for y in range(0, cell_size * cell_num, cell_size):
pygame.draw.line(screen, (200, 200, 200), (0, y),
(cell_size * (cell_num - 1), y), 1)
for x, y, c in chess_arr:
chess_color = (30, 30, 30) if c == 1 else (225, 225, 225)
pygame.draw.circle(screen, chess_color, [x * cell_size, y * cell_size], 16, 16)
if state != 1:
myfont = pygame.font.Font(None, 60)
white = 210, 210, 0
win_text = "IS %s" % ('black' if state == 2 else 'white')
textImage = myfont.render(win_text, True, white)
screen.blit(textImage, (260, 320))
pygame.display.update()

3. 實驗過程中遇到的問題和解決過程
- 問題1:下載安裝pygame一晚上都未成功
- 問題1解決方案:放棄使用pip安裝pygame,轉(zhuǎn)而使用pycharm自帶的庫下載,并掛上清華的源
- 問題二:對pygame的使用不熟悉
- 問題二解決方案:參考手上的python教程書中的pygame章節(jié)
- 問題三:不知道如何處理五子棋的落點統(tǒng)計
- 問題三解決方案:參考cnblog上的一篇專欄,使用數(shù)組和上述的get one dire函數(shù)實現(xiàn)對落點的儲存
- 問題四:未判斷是否落點于交界線處導(dǎo)致落子混亂
- 問題四解決方案:參考cnblog上的專欄,用int函數(shù)取整,向上或向下落在最接近的交界線處
其他(感悟、思考等)
本次的實驗完全超脫了平時所學(xué)的內(nèi)容,大部分過程都參考了《python:從入門到實踐》一書中對pygame的講解,對五子棋的具體實現(xiàn)則參考了cnblog上的文章,總體而言,
是目前編寫過的最復(fù)雜的程序,雖然許多內(nèi)容非自己的積累,但在這個過程中切實的提升了我的編程能力以及自學(xué)能力,對他人代碼的揣摩也讓我對程序設(shè)計有了更加全面的認識。
參考資料
- 《python從入門到實踐》

浙公網(wǎng)安備 33010602011771號