明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 7977|回复: 34

[源码] [活动结束]LISP知识问答第1期--基础篇1(难度指数:★★)

  [复制链接]
发表于 2010-12-20 05:02 | 显示全部楼层 |阅读模式
本帖最后由 caoyin 于 2011-1-22 14:32 编辑

LISP知识问答比赛第一期——基础篇

[活动主题]近来有不少新人活跃在本论坛,为了营造论坛的学习氛围,本版将不定期推出“LISP基础问答”活动,旨在为LISP新手提供一个学习的管道,让老手能够带动新手共同进步。
[参赛时间]2010年12月20日~2011年01月20日
[参赛资格]明经会员
[评审]由明经通道论坛组织评审,并给予文字点评。
[要求]
        1.运行结果错误不得分。
        2.答案具有通用性。程序能够在不加载任何第三方插件的情况下在AutoCAD2004~2011官方标准安装版上测试通过。
        3.以写函数的方式答题,答案必须为源代码且愿意公开。
        4. 代码要求及打分比例
           算法好,执行快 (50%)
           思路新颖、特别 (30%)
           代码精简 (20%)

[奖励]暂不设物质奖励,根据情况由论坛商定酌情加分。
[参赛办法]参赛者将试题答案保存为txt或lsp文件,为了避免相互参照,文件须压缩为zip或rar格式,压缩时应选择6位密码,在上传发帖后通过论坛“提醒”或“短消息”方式将密码发送给ZZXXQQ版主。
发送格式:
                 <会员名>
                 <密码>
如:
                 MCCAD
                 123456
如果你对自己的答案非常自信,你可以在发帖时注明:我要摆擂台
如果评审结果你是最佳答案,则会得到3倍的加分。

---------------------------------------------------------------------------------
(1)本题5分:
        判断表 Lst 是否是点对表
        [格式](consP Lst)
        [测试范例](consP '(0 . "AA"))->T

(2)本题5分:
        判断指定数据是否是点
        [格式](PointP Data)
        [测试范例](PointP '(0  1 2))->T
(3)本题5分:
        写一句代码将变量
         MJTD1,MJTD2,MJTD3,...,MJTD1000
         赋值为
         1,2,3,...,1000
(4)本题5分:
         判断指定数据是否为偶数
         [格式](EvenP DATA)
         [测试范例](EvenP 5)->nil
(5)本题10分:
        截取表的局部
        [格式](ListSub Lst Sta Len)
        [说明]Lst——表
                Sta——开始元素位置(第一个元素位置为 0)
                Len——以 sta 开始的长度,如果为 nil 则获取到最后
        [测试范例](lstsub '(1 2 3 4 5 6 7) 1 5)->(2 3 4 5 6)
(6)本题15分:
         求表中的数字与指定数字之差最大或最小的数字
         [格式](NumExty Num NumLst Mode)
         [说明]Num——数字
                  NumLst——数字列表
                  Mode——为 T 求之差最大,nil 求之差最小
         [测试范例]
                 (NumExty 5.181 '(4.9 5.175 6 9.181 5.182 1.181 5.181 5.1) T)->9.181
参考
12楼、13楼的帖子,3种返回姑且都算对吧
(7)本题15分:
        判断文件名是否合法(不包含无效字符)
                [格式](FileName-Valid FileName)
        [说明]FileName——不包含路径和扩展名的文件(或路径)名。
        [测试范例](FileName-Valid "Auto*Lisp")->nil

(8)本题40分(加难讨论题):
        判断两个文件名是否是同一个文件(或路径)。
       [格式](FileName-Equal FileName1 FileName2)
       [说明]两个参数都是包含绝对路径的文件名(可以理解为文件实际存在),可能各自的大小写不同、\\或/符号不同、长短路径名不同,如何判断两个文件名指向的是不是同一个文件。



————————————————————————————————

补充说明:
第一题中的点对表感念的说明:
如果 object 指定单一原子,则为原子。
如果所有 object 参数都是原子,则为点对。
如果最后一个参数为原子,且不属于前面几种情况,则返回点对表。
如果不属于前面几种情况,则返回表。

上面的话简单的说就是
A            '(0 . 1)-------->点对
B            '(0 1 . 2)------>点对表
C            '(0 1 2)-------->狭义的表
这三种情况也都包含在广义的表的范畴。
因此本题的正确答案是 B 种情况返回T,但在此处 A 种情况返回T也不算错。
第八题难度的说明:
本题难度超出了基础的范围,因此60分就应该是基础部分的满分。



"觉得好,就打赏"
还没有人打赏,支持一下

本帖被以下淘专辑推荐:

发表于 2010-12-20 06:59 | 显示全部楼层
好、好、好
又是一个学习的好机会
愿多组织这种活动
谢谢明经
发表于 2010-12-20 07:13 | 显示全部楼层
“为了营造论坛的学习氛围,本版将不定期推出“LISP基础问答”活动,旨在为LISP新手提供一个学习的管道,让老手能够带动新手共同进步。“
提一个小建议:为了让新手学习领会的更快,是否能在某些语句后面加一些注解?
谢谢

发表于 2010-12-20 20:43 | 显示全部楼层
可以在最后点评时加上。
发表于 2010-12-20 20:55 | 显示全部楼层
有戏看,好。
发表于 2010-12-20 21:22 | 显示全部楼层
本帖最后由 caoyin 于 2011-1-22 22:44 编辑

我来一个试试呢.


-------以下是答题内容--------------
;|(1)本题5分:
        判断表 Lst 是否是点对表
        [格式](consP Lst)
        [测试范例](consP '(0 . "AA"))->T
|;
(defun consp(Lst)
  (if (and (listp Lst)  (atom(cdr Lst)))
                  T   
                 nil
  )
)

此题不得分
扣分原因:返回结果错误,可能答题者未能领会题意
测试:
(consP nil)->T
(consp '(1 2)->T
另外楼主的代码完全可以去掉if语句,改为:
(defun consp(Lst)
  (and (listp Lst)  (atom(cdr Lst)))
)

这样看起来简洁些

;|      
(2)本题5分:
        判断指定数据是否是点
        [格式](PointP Data)
        [测试范例](PointP '(0 1 2))->T
|;
(defun pointp(data)
  (if (vl-catch-all-error-p (vl-catch-all-apply 'distance (list data '(0 0))))
    nil  
    T
  )
)
答案完全正确,此题得5分
另外和第一题一样可以去掉if语句
;|
(3)本题5分:
        写一句代码将变量
         MJTD1,MJTD2,MJTD3,...,MJTD1000
         赋值为
         1,2,3,...,1000
|;
(setq n 1)   
(repeat 1000 (set (read (strcat "MJTD" (itoa n))) n) (setq n (1+ n)))
答案完全正确,此题得5分

         
;|
(4)本题5分:
         判断指定数据是否为偶数
         [格式](EvenP DATA)
         [测试范例](EvenP 5)->nil
|;
(defun EvenP (DATA) (if (= (rem data 2) 0) T nil))
;|
答案完全正确,此题得5分
另外和第一题一样可以去掉if语句

(5)本题10分:
        截取表的局部
        [格式](LstSub Lst Sta Len)
        [说明]Lst——表
                Sta——开始元素位置(第一个元素位置为 0)
                Len——以 sta 开始的长度,如果为 nil 则获取到最后
        [测试范例](lstsub '(1 2 3 4 5 6 7) 1 5)->(2 3 4 5 6)
|;
(defun LstSub (Lst Sta Len / newlst)  
  (if len
    (if (<= sta (length lst))
      (progn
(repeat len  
   (setq newlst (append newlst (list(nth Sta  Lst))))
   (setq Sta (1+ Sta))
)  
newlst
      )
      nil
    )
   (last lst);;这个地方由于出题没有表达清楚,因此不予扣分
              ;;原题的意思是(lstsub '(1 2 3 4 5 6 7) 1 nil)->(2 3 4 5 6 7)

  )
)

此题得7分
扣分原因:返回结果考虑不太完美
测试:
(lstsub '(1 2 3 4 5 6 7) 6 3)->(7 nil nil)
;|
(6)本题15分:
         求表中的数字与指定数字之差最大或最小的数字
         [格式](NumExty Num NumLst Mode)
         [说明]Num——数字
               NumLst——数字列表
               Mode——为 T 求之差最大,nil 求之差最小
         [测试范例]
              (NumExty 5.181 '(4.9 5.175 6 9.181 5.182 1.181 5.181 5.1) T)->9.181
|;     
(defun NumExty (Num NumLst Mode / lst x)
(setq lst (mapcar '(lambda(x)(abs(- num x))) NumLst))
(if mode (+ Num (eval (cons 'max lst)))(+ Num (eval (cons 'min lst))))
)
此题得14分
扣分原因:代码还有精简空间  
;|
(7)本题15分:
        判断文件名是否合法(不包含无效字符)      
        [格式](FileName-Valid FileName)
        [说明]FileName——不包含路径和扩展名的文件(或路径)名。
        [测试范例](FileName-Valid "Auto*Lisp")->nil
|;  
(defun FileName-Valid (FileName / fn fname)
  (if
    (and
      (setq fname (vl-filename-mktemp FileName))
      (setq fn (open filename "w"))
    )  
   (progn
     (close fn)
     (vl-file-delete  fname)
     T
   )
   nil
   )
)
此题得4分
扣分原因:其实只要判断字符串就好了,创建文件再删除感觉有点麻烦
;|
(8)本题40分(加难讨论题):
        判断两个文件名是否是同一个文件(或路径)。
       [格式](FileName-Equal FileName1 FileName2)
       [说明]两个参数都是包含绝对路径的文件名,可能各自的大小写不同、\\或/符号不同、
       长短路径名不同,如何判断两个文件名指向的是不是同一个文件。
|;
(defun FileName-Equal (FileName1 FileName2)
    (while (vl-string-search "\\"  FileName1)
      (setq FileName1 (vl-string-subst "/" "\\" FileName1))
    )
    (while (vl-string-search "\\"  FileName2)
      (setq FileName2 (vl-string-subst "/" "\\" FileName2))
    )
    (if (= (strcase FileName1)(strcase FileName2) )T nil)
)

此题得10分
扣分原因:答案未解决长短路径名不同的问题




--------------------------------------------------------------
总分:50分
基出题部分(满分为60分)40分
点评:
无聊老用户实际的水平是不低的,本来应该答的更好的,可能有些题目没能理解,当然出题也有问题!
望再接再厉,在此感谢无聊老用户的积极参与,祝新年愉快!!(caoyin)




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x

评分

参与人数 1威望 +1 明经币 +2 金钱 +12 收起 理由
caoyin + 1 + 2 + 12

查看全部评分

发表于 2010-12-20 23:34 | 显示全部楼层
哈哈,支持,可以开眼界了
发表于 2010-12-21 00:06 | 显示全部楼层
本帖最后由 nonsmall 于 2010-12-21 00:06 编辑

第二题
(defun PointP (Data)
        (not (vl-catch-all-error-p (vl-catch-all-apply 'angle (list Data Data))))
)
申请最简单奖

凡是简单判断的东西都可以用这种方法(也算是比较通用的判断方法)

评分

参与人数 1明经币 +1 收起 理由
caoyin + 1 angle算法比distance要快

查看全部评分

发表于 2010-12-21 18:36 | 显示全部楼层
本帖最后由 caoyin 于 2011-1-22 23:16 编辑

勉强算是做完了吧,乱来的,哈哈~~


-----------------------------以下为答题内容--------------------------------------
;;;(1)本题5分:
;;;        判断表 Lst 是否是点对表
;;;        [格式](consP Lst)
;;;        [测试范例](consP '(0 . "AA"))->T
(defun consp (lst)
  (setq a (vl-list-length lst))
  (if (= nil a)
    (princ "\n    T")
    (princ "\n    nil")
  )
  (princ)
)

----------------------------------------------
(consP '(0 . "AA"))
(consP '(0 "AA"))
;;;用vl-list-length算不算偷懒啊,呵呵(用vl-list-length是很好的方法,怎么能算偷懒呢


本题得分5分
但如果作为引用的函数,用princ打印信息个人觉得没有必要,只要满足返回值就好了

;;;(2)本题5分:
;;;        判断指定数据是否是点
;;;        [格式](PointP Data)
;;;        [测试范例](PointP '(0  1 2))->T
(defun pointp (data)
  (command "line" '(0 0) '(1 1) "")
  (command "circle" data 1)
  (setq a (cdr (assoc 0 (entget (entlast)))))
  (if (= a "LINE")
    (princ "\n    nil")
    (princ "\n    T")
  )
  (princ)
)
----------------------------------------------
(pointP '(0 1 2))
(pointP '(0 1))
(pointP '(0))

本题不得分
扣分原因:虽然返回的结果有可能是对的,但我觉得还是不能得分,因为我们要体现编程的意义
在这里用command就有点得不偿失了。
1.command不是必用不可的
2.command严重影响速度啊
3.command产生的对象还要删掉

;;;(3)本题5分:
;;;        写一句代码将变量
;;;         MJTD1,MJTD2,MJTD3,...,MJTD1000
;;;         赋值为
;;;         1,2,3,...,1000
(setq a 1)
(repeat 1000
  (setq zf1 (strcat "MJTD" (rtos a 2 0)))
  (set (read zf1) a)
  (setq a (1+ a))
)
----------------------------------------------
MJTD37
MJTD802
;;;“写一句代码将变量赋值”,“一句”真能做到吗?

本题得分4分
扣分原因:rtos应当改为itoa,因为rtos有时候会受到系统变量的影响



;;;(4)本题5分:
;;;         判断指定数据是否为偶数
;;;         [格式](EvenP DATA)
;;;         [测试范例](EvenP 5)->nil
(defun EvenP (data)
  (setq a (type 0));;这句个人感觉有点啰嗦了
  (setq b (type data))
  (if (= a b)
    (if (= (rem data 2) 0)
      (princ "\n    T")
      (princ "\n    nil")
    )
    (princ "\n    nil")
  )
  (princ)
)
------------------------------------------------
(EvenP 5)
(EvenP 4)
(EvenP -4)
(EvenP 4.0)
;;;4.0应该不算是偶数吧,希望我没有理解错...;;偶数首先是实数,你理解的没错

本题得分4.5分
楼主要把局部变量归零哦(所有的答题都好像有这个问题)----〉(defun EvenP (data / a b)

;;;(5)本题10分:
;;;        截取表的局部
;;;        [格式](ListSub Lst Sta Len)
;;;        [说明]Lst——表
;;;                Sta——开始元素位置(第一个元素位置为 0)
;;;                Len——以 sta 开始的长度,如果为 nil 则获取到最后
;;;        [测试范例](lstsub '(1 2 3 4 5 6 7) 1 5)->(2 3 4 5 6)
(defun ListSub (Lst Sta Len)
  (if (= nil Len)
    (setq Len (length Lst))
  )
  (setq a 0)
  (setq Lsts '())
  (repeat (length Lst)
    (setq Lst1 (car Lst))
    (setq Lst (cdr Lst))
    (if (and (>= a Sta) (< a (+ Len Sta)))
      (setq Lsts (cons Lst1 Lsts))
    )
    (setq a (1+ a))
  )
  (setq Lst '())
  (repeat (length Lsts)
    (setq Lst1 (car Lsts))
    (setq Lsts (cdr Lsts))
    (setq Lst (cons Lst1 Lst))
  )
  (princ Lst);;再次提醒,这两行改为 lst 就行了
  (princ)
)
------------------------------------------------
(ListSub '(1 2 3 4 5 6 7) 1 5)
(ListSub '(1 2 3 4 5 6 7) 1 nil)

返回结果完全正确,本题得分8分(鼓励加分: +1分)
代码感觉太冗长,算法还有待改进
注意:(princ)的作用是关闭最后的返回值,这一般用于正式的程序(给人用的程序,如C:开头的函数)的结尾,或者一个lsp文件的结尾


;;;(6)本题15分:
;;;         求表中的数字与指定数字之差最大或最小的数字
;;;         [格式](NumExty Num NumLst Mode)
;;;         [说明]Num——数字
;;;                  NumLst——数字列表
;;;                  Mode——为 T 求之差最大,nil 求之差最小
;;;         [测试范例]
;;;                 (NumExty 5.181 '(4.9 5.175 6 9.181 5.182 1.181 5.181 5.1) T)->9.181
(defun NumExty (Num NumLst Mode)
  (defun lambda1 (x)
    (abs (- Num x))
  )
  (if (= Mode T)
    (setq NumLst
    (vl-sort
      NumLst
      (function (lambda (e1 e2) (> (lambda1 e1) (lambda1 e2))))
    )
    )
    (setq NumLst
    (vl-sort
      NumLst
      (function (lambda (e1 e2) (< (lambda1 e1) (lambda1 e2))))
    )
    )
  )
  (princ "\n    ")
  (princ (car NumLst))
  (setq a (abs (- Num (car NumLst))))
  (setq NumLst (cdr NumLst))
  (while (< (abs (- (abs (- Num (car NumLst))) a)) 0.0001)
    (princ "\n    ")
    (princ (car NumLst))
    (setq NumLst (cdr NumLst))
  )
  (princ)
)
------------------------------------------------
(NumExty 5.181 '(4.9 5.175 6 9.181 5.182 1.181 5.181 5.1) T)
;;;程序求的是表中的数字与指定数字之差的  绝对值  最大或最小的数字,
;;;本人拙见:单纯求差的话Num的值就无意义了,只剩下原表中数字的求最大或最小值。

本题得分13分
代码还有改进空间
vl-sort的两次使用能否改为一次,即把第一次的结果reverse



;;;(7)本题15分:
;;;        判断文件名是否合法(不包含无效字符)
;;;                [格式](FileName-Valid FileName)
;;;        [说明]FileName——不包含路径和扩展名的文件(或路径)名。
;;;        [测试范例](FileName-Valid "Auto*Lisp")->nil
(defun FileName-Valid (FileName)
  (vl-load-com)
  (setq a (strcat "C:\\测试文件" FileName ".txt"))
  (setq b nil)
  (setq b (open a "a"))
  (if (= b nil)
    (princ "\n    nil")
    (progn
      (close b)
      (vl-file-delete a)
      (princ "\n    T")
    )
  )
  (princ)
)
------------------------------------------------
(FileName-Valid "Auto*Lisp")
(FileName-Valid "AutoLisp")

本题得4分
扣分原因:其实只要判断字符串就好了,创建文件再删除感觉有点麻烦


;;;(8)本题40分(加难讨论题):
;;;        判断两个文件名是否是同一个文件(或路径)。
;;;       [格式](FileName-Equal FileName1 FileName2)
;;;       [说明]两个参数都是包含绝对路径的文件名(可以理解为文件实际存在),可能各自的大小
;;;       写不同、\\或/符号不同、长短路径名不同,如何判断两个文件名指向的是不是同一个文件。
    (defun FileName-Equal (FileName1 FileName2)
      (vl-load-com)
      (setq aa (open FileName1 "r"))
      (setq bb (open FileName2 "r"))
      (if (/= aa nil) (close aa))
      (if (/= bb nil) (close bb))
      (setq a (open FileName1 "a"))
      (if (= a nil)
(progn
   (princ "\n    测试文件:")
   (princ FileName1)
   (princ "正在使用,请先关闭文件!")
   (exit)
)
      )
      (close a)
      (setq b (open FileName2 "a"))
      (if (= b nil)
(progn
   (princ "\n    文件")
   (princ FileName1)
   (princ "与文件")
   (princ FileName2)
   (princ "非同一个文件!")
   (if (= aa nil) (vl-file-delete FileName1))
   (exit)
)
        (close b)
      )
      (setq c (vl-file-rename FileName1 "c:\\FileName-Equal函数测试文件1.dwg"))
      (setq d (vl-file-rename FileName2 "c:\\FileName-Equal函数测试文件2.dwg"))
      (if (= d nil)
(progn
   (princ "\n    文件")
   (princ FileName1)
   (princ "与文件")
   (princ FileName2)
   (princ "是同一个文件!")
)
(progn
   (vl-file-rename "c:\\FileName-Equal函数测试文件2.dwg" FileName2)
   (princ "\n    文件")
   (princ FileName1)
   (princ "与文件")
   (princ FileName2)
   (princ "非同一个文件!")
)
      )
      (vl-file-rename "c:\\FileName-Equal函数测试文件1.dwg" FileName1)
      (if (= aa nil) (vl-file-delete FileName1))
      (if (= bb nil) (vl-file-delete FileName2))
      (princ)
    )
------------------------------------------------
    (FileName-Equal "c:\\1.dwg" "c:/1.DWG")
    (FileName-Equal "c:\\1.dwg" "d:/1.dwg")

本题得10分


----------------------------------------------------------------------------------------
总得分47.5(49.5-2,  局部变量未清理及princ原因再扣2分)
基出题部分(满分为60分)39.5分

点评: lixdu对LISP基础有较深的理解,只是编程的一些习惯建议要更加严谨些,程序的算法上还有改进的空间。
十分的感谢参与!期待多参与论坛的活动和讨论。祝你在新的一年里有更大的进步!!





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x

评分

参与人数 1威望 +1 明经币 +2 收起 理由
caoyin + 1 + 2

查看全部评分

发表于 2010-12-21 23:45 | 显示全部楼层
不错的活动
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-5-3 07:14 , Processed in 0.419469 second(s), 31 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表