阿福:小美,聽說你學過海龜繪圖,能幫我用turtle?來畫一張棋譜嗎?
小美:什么棋譜?
阿福:就是一張9路圍棋盤的棋譜,它的樣子如圖1所示:
知識小貼士:
turtle?(海龜繪圖)很適合用來引導孩子學習編程。最初來自于Wally Feurzig 和 Seymour Papert 于1966 年所創(chuàng)造的 Logo 編程語言。它在繪圖區(qū)設置了一只想象中的小海龜(畫面顯示一個箭頭代表小海龜?shù)念^),起始位置在 x-y 平面的 (0, 0) 點,面向x軸正方向。小海龜根據(jù)一組函數(shù)指令的控制,在這個平面坐標系中移動,從而在它爬行的路徑上繪制了圖形。
小美:這種棋譜啊,小菜一碟!只要先畫橫豎各9條線,再畫上9個星位圓點,棋盤就畫好了。接下來把黑白棋子畫上去就行了。
阿福:說得簡單,有這么容易嗎?我也不讓你畫棋子,你先把棋盤畫出來給我看看?
小美:這有什么難的。我不僅可以畫出9路棋盤,還能把棋盤上的橫縱坐標標記也畫出來,甚至推廣到13路、19路棋盤上去,你只需修改棋盤路數(shù)和星位坐標就行了。
import turtle astt
'''
函數(shù)功能:根據(jù)輸入的棋盤的路數(shù),格子寬度和左上角坐標,畫一個圍棋盤
函數(shù)名:draw_go_board(n,s, x0, y0, point)
參數(shù)表:n -- 棋盤的路數(shù);s -- 棋盤格子寬度;
?????? x0, y0 --棋盤左上角坐標;point -- 存儲了星位坐標的元組。
返回值:沒有返回值。
'''
defdraw_go_board(n, s, x0, y0, point):
??? for command in ('寫字母', '寫數(shù)字'):
??????? if command == '寫字母':
??????????? x, y = x0, y0 + s * 2 / 3
??????????? a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
??????? else:
??????????? x, y = x0 - s * 2 / 3, y0 - s / 5
??????????? a = list(range(1,27))
??????? for c in a[:n]:
??????????? tt.penup()
??????????? tt.goto(x, y)
??????????? tt.pendown()
??????????? tt.write(c,align="center", font=("Arial", 16, "normal"))
??????????? if command == '寫字母':
??????????????? x += s
??????????? else:
??????????????? y -= s
??? forcommand in ('畫橫線', '畫豎線'):
??????? x, y = x0, y0
??????? for i in range(n):
??????????? tt.penup()
??????????? tt.goto(x, y)
??????????? tt.pendown()
??????????? tt.forward(s*(n-1))
??????????? if command == '畫橫線':
??????????????? y -= s
??????????? else:
??????????????? x += s
??????? tt.right(90)
??? for x, y in point: #畫星位
??????? tt.penup()
??????? tt.goto(x, y)
??????? tt.pendown()
??????? tt.dot(12)
tt.TurtleScreen._RUNNING= True? #啟動繪圖,在IDE中運行加這句可避免報錯
tt.speed(0)
tt.ht()#隱藏筆頭
#n, s, (x, y), s分別存儲了棋盤的路數(shù),格子寬度和左上角坐標
n, s, x, y = 9,60, -240, 240
#星位坐標
point =((-120,120),(0,120),(120,120),
???????? (-120,0),(0,0),(120,0),
???????? (-120,-120),(0,-120),(120,-120))
draw_go_board(n,
s, x, y, point) #畫n路棋盤
tt.done()
?阿福:你怎么那么厲害!看來我小瞧你了。那好,你現(xiàn)在把棋子畫上去吧。
小美:棋盤畫好以后,我們只要另外再寫一個畫棋子的draw_go_table()函數(shù)就行了。但是在調(diào)用draw_go_table()之前我們需要先把棋盤上各個交叉點的信息存儲起來,我們可以用列表go_table存儲這些信息,例如go_table[0] = '空空空空空空空空空'表示第1行上全是空子,go_table[3] = '空白空白白黑黑黑白'表示了第4行上黑白子的分布情況。
阿福:有道理!那具體的程序應該怎樣寫呢?
小美:我都說這么明白了,你還沒反應過來啊?看來“大熊貓”這個標簽你還得掛一段時間。看清楚了!
'''
函數(shù)功能:在已經(jīng)畫好的棋盤上,按棋盤位置順序添加棋子信息(隱藏手數(shù)編號)
函數(shù)名:draw_go_table(n,s, x0, y0, go_table)
參數(shù)表:n -- 棋盤的路數(shù);s -- 棋盤格子寬度;
?????? x0, y0 --棋盤左上角坐標;go_table-- 存儲了各交叉點信息的列表。
返回值:沒有返回值。
'''
def draw_go_table(n, s, x0, y0, go_table):
??? for i in range(n):
??????? x, y = x0, y0 - i * s+ s / 2
??????? for j in range(n):
??????????? if go_table[i][j]== '空': #跳過空子
??????????????? x += s
??????????????? continue
??????????? if go_table[i][j]== '黑': #畫黑子
???????????????tt.color('white', 'black')
??????????? else:????????????????????? #畫白子
??????????????? tt.color('black','white')
??????????? tt.penup()
??????????? tt.goto(x, y)
??????????? tt.pendown()
??????????? tt.begin_fill()
??????????? tt.circle(s*5/12)
??????????? tt.end_fill()
??????????? x += s
tt.TurtleScreen._RUNNING = True?#啟動繪圖,在IDE中運行加這句可避免報錯
tt.speed(0)
tt.ht()#隱藏筆頭
#n, s, (x, y), s分別存儲了棋盤的路數(shù),格子寬度和左上角坐標
n, s, x, y = 9, 60, -240, 240
#星位坐標
point = ((-120,120),(0,120),(120,120),
????????(-120,0),(0,0),(120,0),
????????(-120,-120),(0,-120),(120,-120))
draw_go_board(n, s, x, y, point) #畫n路棋盤
go_table = ['空空空空空空空空空','空空空空空空空空空','空空白空空白白白空',
??????????? '空白空白白黑黑黑白','空黑白白黑黑空黑空','空黑黑黑空空空空空',
??????????? '空空空空空空空空空','空空空空空空空空空','空空空空空空空空空']
draw_go_table(n, s, x, y, go_table) #畫棋譜(隱藏手數(shù)編號)
tt.done()
古老師:小美,又在欺負阿福了啊!你可別小看他,別看他嘴上不說,心里可清楚得很哪。不過小美這段時間進步確實挺大的,不僅能熟練使用各種turtle?方法,連自定義函數(shù)也寫得很漂亮了呢!但我不得不說的是,你畫的圖并不是真正的圍棋譜,真正的圍棋譜上面是要顯示手數(shù)編號的,就像圖4這種樣子:
阿福:沒錯,其實這張圖才是我想讓你畫的。
小美:那你不早說!不過要加上手數(shù)編號的話還真有點難度呢。不能簡單地用”黑白空”字符來表示了。不僅要包含棋子顏色信息,還要包含手數(shù)編號信息,那豈不是要用2個變量來表示同一個交叉點的信息?
阿福:其實一個變量就夠了,但是不能用字符,而要用整數(shù),0表示空子,正數(shù)表示黑子,負數(shù)表示白子,它們的絕對值表示手數(shù)編號。
古老師:有道理!阿福,不愧是初中生啊,數(shù)學沒有白學!小美,你知道負數(shù)嗎?
小美:知道的,興趣小組里老師講過。
古老師:那就好。這樣吧,小美,你先用阿福說的方法存儲棋盤上各個交叉點的信息,再用你剛才畫圖3的思路,按照從上到下、從左到右的順序把棋譜畫出來。阿福呢,給你一個更艱巨的任務:按照落子順序把棋譜畫出來。
阿福:古老師你偏心,凈挑難題考我。如果按照落子順序畫棋譜的話,那就需要存儲棋子的手數(shù)編號、顏色和坐標等信息了,原來的經(jīng)驗都沒用了,難度不止增大一點點啊。
古老師:誰叫你是高手呢,能者多勞嘛。不過你的思路是正確的,照著這個思路去做肯定能成功。這樣吧,今天我有事先走了。棋譜畫好了記得告訴我一聲哦。拜拜。
有事沒事最好拉到文末看看,說不定作者今天提供了彩蛋哦!
需要本文word版的,可以加入“Python算法之旅”知識星球參與討論和下載文件,“Python算法之旅”知識星球匯集了數(shù)量眾多的同好,更多有趣的話題在這里討論,更多有用的資料在這里分享。
我們專注Python算法,感興趣就一起來!
?彩蛋
小美:阿福,古老師很器重你啊!對了,畫那個帶手數(shù)編號的棋子,是不是要先把棋子畫好,再寫編號啊?
阿福:古老師就是嘴巴甜!你不也經(jīng)常被夸嗎?沒錯,如果先寫編號的話,填充棋子顏色的時候就會把編號覆蓋掉。好了,我們都抓緊時間行動吧,早點給古老師看結(jié)果。
小美:嗯。。。。。。我好了。
'''
函數(shù)功能:在已經(jīng)畫好的棋盤上,按棋盤位置順序添加棋子信息(顯示手數(shù)編號)
函數(shù)名:draw_go_table2(n,s, x0, y0, go_table)
參數(shù)表:n -- 棋盤的路數(shù);s -- 棋盤格子寬度;x0, y0
-- 棋盤左上角坐標;
go_table -- 存儲各交叉點信息的列表,0、正數(shù)和負數(shù)分別代表空、黑子和白子,其絕對值為手數(shù)編號。
返回值:沒有返回值。
'''?????
defdraw_go_table2(n, s, x0, y0, go_table):
??? for i in range(n):
??????? x, y = x0, y0 - i * s + s / 2
??????? for j in range(n):
??????????? if go_table[i][j] == 0: #跳過空子
??????????????? x += s
??????????????? continue
??????????? if go_table[i][j] > 0: #畫黑子
??????????????? tt.color('white', 'black')
??????????????? num = go_table[i][j]
??????????? else:????????????????? #畫白子
??????????????? tt.color('black', 'white')
??????????????? num = -go_table[i][j]
??????????? #畫棋子
??????????? tt.penup()
??????????? tt.goto(x, y)
??????????? tt.pendown()
??????????? tt.begin_fill()
??????????? tt.circle(s*5/12)
??????????? tt.end_fill()
??????????? #顯示手數(shù)編號
??????????? tt.penup()
??????????? tt.goto(x, y - s * 3 / 5)
??????????? tt.pendown()
??????????? tt.write(num,align="center", font=("Arial", 16, "normal"))
??????????? x += s
tt.TurtleScreen._RUNNING= True? #啟動繪圖,在IDE中運行加這句可避免報錯
tt.speed(0)
tt.ht()#隱藏筆頭
#n, s, (x, y), s分別存儲了棋盤的路數(shù),格子寬度和左上角坐標
n, s, x, y = 9,60, -240, 240
#星位坐標
point =((-120,120),(0,120),(120,120),
???????? (-120,0),(0,0),(120,0),
???????? (-120,-120),(0,-120),(120,-120))
draw_go_board(n,
s, x, y, point) #畫n路棋盤
go_table =[[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,-18,0,0,-14,-8,-12,0],
??????????? [0,-10,0,-4,-6,13,11,19,-20],[0,15,-16,-2,1,7,0,9,0],[0,17,5,3,0,0,0,0,0],
???????????[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0]]
draw_go_table2(n,
s, x, y, go_table) #畫棋譜(顯示手數(shù)編號)
tt.done()
阿福:動作挺快啊!我也好了。
'''
函數(shù)功能:在已經(jīng)畫好的棋盤上,添加棋子信息(按落子順序顯示手數(shù)編號)
函數(shù)名:draw_go_table3(n,s, x0, y0, go_table)
參數(shù)表:n -- 棋盤的路數(shù);s -- 棋盤格子寬度;x0, y0
-- 棋盤左上角坐標;
?????? go_table --存儲了各交叉點信息的列表,其元素值為(手數(shù)編號,棋子顏色,橫坐標,縱坐標)。
返回值:沒有返回值。
'''?????
def draw_go_table3(n,s, x0, y0, go_table):
??? for go in go_table:
??????? num = go[0]
??????? x, y = x0+(ord(go[2])-ord('A'))*s,y0-(go[3]-1)*s+s/2
??????? if go[1] == '黑': #畫黑子
??????????? tt.color('white', 'black')
??????? else:???????????? #畫白子
??????????? tt.color('black', 'white')
??????? #畫棋子
??????? tt.penup()
??????? tt.goto(x, y)
??????? tt.pendown()
??????? tt.begin_fill()
??????? tt.circle(s*5/12)
??????? tt.end_fill()
??????? #顯示手數(shù)編號
??????? tt.penup()
??????? tt.goto(x, y - s * 3 / 5)
??????? tt.pendown()
??????? tt.write(num, align="center",font=("Arial", 16, "normal"))
tt.TurtleScreen._RUNNING= True? #啟動繪圖,在IDE中運行加這句可避免報錯
tt.speed(0)
tt.ht()#隱藏筆頭
#n, s, (x, y), s分別存儲了棋盤的路數(shù),格子寬度和左上角坐標
n, s, x, y = 9,60, -240, 240
#星位坐標
point =((-120,120),(0,120),(120,120),
???????? (-120,0),(0,0),(120,0),
???????? (-120,-120),(0,-120),(120,-120))
draw_go_board(n,
s, x, y, point) #畫n路棋盤
#棋譜(按落子順序顯示手數(shù)編號)?
go_table = [(1,'黑','E',5),(2,'白','D',5),(3,'黑','D',6),(4,'白','D',4),(5,'黑','C',6),
??????????? (6,'白','E',4),(7,'黑','F',5),(8,'白','G',3),(9,'黑','H',5),(10,'白','B',4),
??????????? (11,'黑','G',4),(12,'白','H',3),(13,'黑','F',4),(14,'白','F',3),(15,'黑','B',5),
??????????? (16,'白','C',5),(17,'黑','B',6),(18,'白','C',3),(19,'黑','H',4),(20,'白','I',4)]
draw_go_table3(n,
s, x, y, go_table) #畫棋譜(顯示手數(shù)編號)?
tt.done()