“路面覆盖”智慧型编程

“路面覆盖”LOGO语言“智慧”型编程,可能是近几年来厦门市教育局-科 协官方联办的小学生信息技术上机复赛命题中最难的一道题(当然也是2024 年
试卷中最难的一道题)。在已知编程成功的源程序中,竟然使用了9重递归命
令。在全部覆盖的木板都成功“入位”后,连常规的stop命令都无法使递归程
序停止,而必须使用MSWLogo-FMSLogo编程中极少使用的“最高终止”命
令halt才能让内部逻辑纷繁复杂的程序停止下来。题头图演示的4组随意输入数据的“路面覆盖”动画,可以看出这个程序只要输入的数据得当,还是相当“聪明”的。
对比起来,回顾前次看到的“顺应”型编程心情一定特别舒畅:“看起来很麻烦的程序,原来找到‘捷径’后能那样简单。”但如果你是想要真正学会编写程序的学习者(即便你是最后一届参赛的小学六年级的复赛选手,到初高中一定不再使用LOGO语言编程了),也仍然必须想方设法看懂林老师编写的程序,并最后自己能够编写出能够处理任意输入数据而自动准确覆盖“坑洼”的“智慧”型LOGO程序。MSWLogo-FMSLogo类型的编程语言虽是简单易学,但结构内涵其实与更为高级的C++、PYTHON语言如出一辙。真正弄通了LOGO语言的编程思路和技巧,用C++、PYTHON语言编程结构和原理也是相类似的。
我们说“智慧”型编程就是要求你所编写的程序能够根据“智慧”表数据自动定位并覆盖木板(像题头的动画所演示的那样)。
为了降低编程难度,我们暂时约定你所提供的“坑洼”位置表数据全部都是合理的(就是符合下面的3条要求),是严格符合题目所限定的约束条件的——这才能体现出你给出的表数据是“智慧”的。
1.
题目规定1个坑洼宽20,那么两个坑洼起点之间的数据差若小于20,这两个坑洼将“混”在一起,“糊”在一起。例如两个相邻坑洼的数据可以是200、230,但是200、210就是错误的,300、315也一定不行,画出来的坑纠缠在一起了。
2.
水泥地的“总宽度”是600,最后1块覆盖上去的木板按道理不应当超出600。那么最后1个坑洼的起点位置最多就是520,以免木板突出到水泥地的右边之外。
3.
1块木板长80、1个坑洼宽20,1块木板可能覆盖1个、2个、3个坑洼。这些坑洼之间的距离要适当,前1个坑洼的起点和后面某一个坑洼(有可能是后面第2个、第3个、甚至是第4个坑洼)起点之间的距离不能在61~79这样的尺寸之间,否则最后面的“坑洼”的一部分会“侵入”到前面已经覆盖的木板引起作图错误。
当那些逻辑上错误的坑洼数据预先在输入表数据前就被人工预先剔除时(就是我们预先暂时约定的“智慧”的数据),编程将会相对简单不少。
如果没有了上面的3条“智慧”数据的暂时限制
可以想象编程将会更加困难
允许没有限制地输入“坑洼”数据的程序是“AI智能”型编程
“路面覆盖”的“AI智能”型编程我们在下次博客中讨论
“面板覆盖”LOGO语言“智慧”编程沿以下思路进行:
1. 在前一次的博客文章中已经掌握并顺利运行通过的“顺应”型编程中
lmfg(路面覆盖)主程序
lm
(画路面) 子程序
mb (画面板) 子程序
这3段程序已经被证明是思路清晰可行的。这些程序段保留延续使用(主程序需要略作修改)。
2.
“顺应”型编程所面对的“坑洼”数据是“静态”的,只有一种数据。但是“智慧”型编程应对的是“动态”的,由程序运行者任意输入的符合前面3条“智慧”规定的任意的数据。“面板覆盖”操作最佳的方式就是编写一段递归程序自动反复“扫描”坑洼的位置数据,来确定可以在哪个位置覆盖一块木板、这块木板盖住了几个坑洼。直至对所有的坑洼“扫描”完毕。其中的编程原理说明如下。
递归程序fugai
:n其中:n参数指的是当前坑洼的序号(对应着数据表:kn的数据从头到尾从左到右的排号)。fugai
:n面板覆盖递归是整个程序的核心。
作为递归程序必须有一个收敛终止程序语句
if :n>:kn[halt]
;如果:n多于预设坑洼数:kn就停止覆盖操作
由于前后共有9个递归命令,常用的stop命令在这里已经无效,而必须使用MSWLogo-FMSLogo系统中优先级高于stop的halt“停止程序运行”命令。即便如此,程序内部繁重的递归运算最后都无法立马刹车停止,LOGO编程系统的文本输出窗口会输出显示:
正在停止... in
fugai
[if :n > :kn [halt]]
对于任意一个已经确定序号的坑洼:n,都要计算以下2个数据供递归程序进行判断:
make "qd
item :n :kw ;计算当前坑洼起点
make "fg :qd+80
;从当前起点木板覆盖的最远点
由于1块木板最多可能覆盖1个、2个、3个坑洼。而这些坑洼中的最后1个的后面可能还有坑洼,所以批量的递归按照4个批次进行处理:
最先处理后面还有3个坑的数据值;
接着处理后面还有2个坑的数据值;
然后处理后面还有1个坑的数据值;
如果只剩下最后1个坑的数据值,最后处理。
以上4级是按照“从后面有更多的坑洼向更少的坑洼”逐级处理。
这以上4个批次内部再按照这块木板还可能覆盖了后面若干块木板的顺序逐级处理;
这块板还覆盖了后面2个坑洼
这块板还覆盖了后面1个坑洼
这块板只覆盖了自己这个坑洼
举个例子,怎么才能知道会覆盖后面2块木板?因为:
后面第2个坑的起点在:kw数据表中可以读到:item :n+2
:kw
每个坑洼宽20,后面第2个坑的右边位置是:20+item :n+2
:kw
如果:fg>=20+item :n+2
:kw那么真是覆盖掉了后面第2个坑洼了。
现在赶快画这一块木板:mb :qd
因为后2个坑洼被覆盖了,再下一个需要覆盖的坑洼的序号就必然是:n+3
也就是必须执行fugai
:n+3递归,继续处理后续的坑洼
其他递归程序运算的原理类推。
这样的递归程序要反复执行类似item :n+2
:kw、fugai
:n+3这样的操作。这时:n的值一不小心就会增长到超出数据表:kw实际数据的个数(数据出界)而产生程序系统错误。这是编程中必需避开的难点。
从现有运行的结果来看,这个程序真的能够正常自动处理各种符合“智慧”3要求的坑洼数据。这里提供4组数据供大家参考。
lmfg
[100 130 200 370 430]
lmfg [10
50 100 135 160 200 225 255 370 430
495]
lmfg [20
45 63 200 250 370 520]
lmfg
[100 130 160 330 420]
编程源程序如下:
to lmfg :kw
;路面覆盖主程序 :kw坑洼左边起点数据表
cs ht
make "kn count :kw
;统计坑洼总数:kn这是画路面和覆盖坑洼都需要的数据
lm
;画路面
make "n 1
;起始坑洼序号是1
fugai :n
;转向木板覆盖递归程序
end
to lm ;画路面
pu setx -300 pd
;画图的起点左移使图形居中
for[i 1 :kn][
;逐个读取:kn个坑洼的起点位置数据
make "wz item :i
:kw ;读出当前坑洼左边的位置数据值
setx
:wz-300
;注意!-300使图形居中,总宽度是600
rt 180 fd 10 lt
90 fd 20 lt 90 fd 10] ;画出这个坑洼 每个坑洼都是一样的
setx 300
;补齐到最右边路面的线段
bk 50 setx -300 sety
0 ;画好下面的剩余线段
setfc 15
;对路面涂上灰色
pu setxy -290 -30 pd fill
pu
end
to mb :qd ;画面板子程序
:mbx单块面板左下方X坐标
seth 0 setfc 9
pu setxy :qd-300 3
pd ;每块面板在Y方向上浮3个点
repeat 2[fd 5 rt 90 fd 80 rt 90]
;画木板外框
seth 45 pu fd 3 pd (fill
"true) ;对木板涂色
end
to fugai :n ;面板覆盖递归程序 :n是当前起始覆盖的坑洼编号
if :n > :kn
[halt]
;如果:n多于预设坑洼数:kn就执行halt最高停止操作
make "qd item :n :kw
;计算当前坑洼起点
make "fg :qd+80
;从当前起点木板覆盖的最远点
;=======处理后面还有3个坑的数据值=======
if :kn-:n>=3[
if
:fg>=20+item :n+2 :kw[mb :qd fugai :n+3]]
;这块板还覆盖了后面2个坑洼
if :kn-:n>=3[
if
:fg>=20+item :n+1 :kw[mb :qd fugai :n+2]]
;这块板还覆盖了后面1个坑洼
if :kn-:n>=3[if :fg>=20[mb
:qd fugai :n+1]]
;这块板只覆盖了自己这个坑洼
;=======处理后面还有2个坑的数据值=======
if :kn-:n>=2[
if
:fg>=20+item :n+2 :kw[mb :qd fugai :n+3]]
;这块板还覆盖了后面2个坑洼
if :kn-:n>=2[
if
:fg>=20+item :n+1 :kw[mb :qd fugai :n+2]]
;这块板还覆盖了后面1个坑洼
if :kn-:n>=2[
if :fg>=20[mb
:qd fugai :n+1]]
;这块板只覆盖了自己这个坑洼
;=======处理后面还有1个坑的数据值=======
if :kn-:n>=1[
if
:fg>=20+item :n+1 :kw[mb :qd fugai :n+2]]
;这块板还覆盖了后面1个坑洼
if :kn-:n>=1[
if :fg>=20[mb
:qd fugai :n+1]]
;这块板只覆盖了自己这个坑洼
;=======处理最后1个坑的数据值===========
if :kn-:n>=0[mb :qd fugai
:n+1]
;画最后1个坑上面覆盖的木板
end
大家还可以自己输入其他符合“智慧”要求的数据试运行看看。
如果你能编写出更简捷高效的程序,敬请展示出来供大家学习讨论。
允许没有限制地输入“坑洼”数据的程序是“AI智能”型编程
“路面覆盖”的“AI智能”型编程我们在下次博客中讨论
复赛竞赛题输出的“电梯”动画
加载中,请稍候......