阿福:小美,听说你学过海龟绘图,能帮我用turtle 来画一张棋谱吗?
小美:什么棋谱?
阿福:就是一张9路围棋盘的棋谱,它的样子如图1所示:
知识小贴士:
turtle (海龟绘图)很适合用来引导孩子学习编程。最初来自于Wally Feurzig 和 Seymour Papert 于1966 年所创造的 Logo 编程语言。它在绘图区设置了一只想象中的小海龟(画面显示一个箭头代表小海龟的头),起始位置在 x-y 平面的 (0, 0) 点,面向x轴正方向。小海龟根据一组函数指令的控制,在这个平面坐标系中移动,从而在它爬行的路径上绘制了图形。
小美:这种棋谱啊,小菜一碟!只要先画横竖各9条线,再画上9个星位圆点,棋盘就画好了。接下来把黑白棋子画上去就行了。
阿福:说得简单,有这么容易吗?我也不让你画棋子,你先把棋盘画出来给我看看?
小美:这有什么难的。我不仅可以画出9路棋盘,还能把棋盘上的横纵坐标标记也画出来,甚至推广到13路、19路棋盘上去,你只需修改棋盘路数和星位坐标就行了。
import turtle astt
'''
函数功能:根据输入的棋盘的路数,格子宽度和左上角坐标,画一个围棋盘
函数名:draw_go_board(n,s, x0, y0, point)
参数表:n -- 棋盘的路数;s -- 棋盘格子宽度;
x0, y0 --棋盘左上角坐标;point -- 存储了星位坐标的元组。
返回值:没有返回值。
'''
defdraw_go_board(n, s, x0, y0, point):
for command in ('写字母', '写数字'):
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分别存储了棋盘的路数,格子宽度和左上角坐标
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()
阿福:你怎么那么厉害!看来我小瞧你了。那好,你现在把棋子画上去吧。
小美:棋盘画好以后,我们只要另外再写一个画棋子的draw_go_table()函数就行了。但是在调用draw_go_table()之前我们需要先把棋盘上各个交叉点的信息存储起来,我们可以用列表go_table存储这些信息,例如go_table[0] = '空空空空空空空空空'表示第1行上全是空子,go_table[3] = '空白空白白黑黑黑白'表示了第4行上黑白子的分布情况。
阿福:有道理!那具体的程序应该怎样写呢?
小美:我都说这么明白了,你还没反应过来啊?看来“大熊猫”这个标签你还得挂一段时间。看清楚了!
'''
函数功能:在已经画好的棋盘上,按棋盘位置顺序添加棋子信息(隐藏手数编号)
函数名:draw_go_table(n,s, x0, y0, go_table)
参数表:n -- 棋盘的路数;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分别存储了棋盘的路数,格子宽度和左上角坐标
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) #画棋谱(隐藏手数编号)
tt.done()
古老师:小美,又在欺负阿福了啊!你可别小看他,别看他嘴上不说,心里可清楚得很哪。不过小美这段时间进步确实挺大的,不仅能熟练使用各种turtle 方法,连自定义函数也写得很漂亮了呢!但我不得不说的是,你画的图并不是真正的围棋谱,真正的围棋谱上面是要显示手数编号的,就像图4这种样子:
阿福:没错,其实这张图才是我想让你画的。
小美:那你不早说!不过要加上手数编号的话还真有点难度呢。不能简单地用”黑白空”字符来表示了。不仅要包含棋子颜色信息,还要包含手数编号信息,那岂不是要用2个变量来表示同一个交叉点的信息?
阿福:其实一个变量就够了,但是不能用字符,而要用整数,0表示空子,正数表示黑子,负数表示白子,它们的绝对值表示手数编号。
古老师:有道理!阿福,不愧是初中生啊,数学没有白学!小美,你知道负数吗?
小美:知道的,兴趣小组里老师讲过。
古老师:那就好。这样吧,小美,你先用阿福说的方法存储棋盘上各个交叉点的信息,再用你刚才画图3的思路,按照从上到下、从左到右的顺序把棋谱画出来。阿福呢,给你一个更艰巨的任务:按照落子顺序把棋谱画出来。
阿福:古老师你偏心,净挑难题考我。如果按照落子顺序画棋谱的话,那就需要存储棋子的手数编号、颜色和坐标等信息了,原来的经验都没用了,难度不止增大一点点啊。
古老师:谁叫你是高手呢,能者多劳嘛。不过你的思路是正确的,照着这个思路去做肯定能成功。这样吧,今天我有事先走了。棋谱画好了记得告诉我一声哦。拜拜。
有事没事最好拉到文末看看,说不定作者今天提供了彩蛋哦!
需要本文word版的,可以加入“Python算法之旅”知识星球参与讨论和下载文件,“Python算法之旅”知识星球汇集了数量众多的同好,更多有趣的话题在这里讨论,更多有用的资料在这里分享。
我们专注Python算法,感兴趣就一起来!
彩蛋
小美:阿福,古老师很器重你啊!对了,画那个带手数编号的棋子,是不是要先把棋子画好,再写编号啊?
阿福:古老师就是嘴巴甜!你不也经常被夸吗?没错,如果先写编号的话,填充棋子颜色的时候就会把编号覆盖掉。好了,我们都抓紧时间行动吧,早点给古老师看结果。
小美:嗯。。。。。。我好了。
'''
函数功能:在已经画好的棋盘上,按棋盘位置顺序添加棋子信息(显示手数编号)
函数名:draw_go_table2(n,s, x0, y0, go_table)
参数表:n -- 棋盘的路数;s -- 棋盘格子宽度;x0, y0
-- 棋盘左上角坐标;
go_table -- 存储各交叉点信息的列表,0、正数和负数分别代表空、黑子和白子,其绝对值为手数编号。
返回值:没有返回值。
'''
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()
#显示手数编号
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分别存储了棋盘的路数,格子宽度和左上角坐标
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) #画棋谱(显示手数编号)
tt.done()
阿福:动作挺快啊!我也好了。
'''
函数功能:在已经画好的棋盘上,添加棋子信息(按落子顺序显示手数编号)
函数名:draw_go_table3(n,s, x0, y0, go_table)
参数表:n -- 棋盘的路数;s -- 棋盘格子宽度;x0, y0
-- 棋盘左上角坐标;
go_table --存储了各交叉点信息的列表,其元素值为(手数编号,棋子颜色,横坐标,纵坐标)。
返回值:没有返回值。
'''
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()
#显示手数编号
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分别存储了棋盘的路数,格子宽度和左上角坐标
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 = [(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) #画棋谱(显示手数编号)
tt.done()