Function 在循环中调用函数(通用Lisp)
我正在制作一个控制台Lisp生存游戏,我正在尝试添加一个函数,在a=b之前,每秒显示“.”。然后,当a=b时,将一个“hurt”变量设置为true,如果该变量为true,则将“health”减去1,直到用户调用“use medkit”函数且“hurt”变量设置为false,然后退出两个循环 我遇到的问题是,当我被提示使用“use medkit”功能并输入时,它不会计算我输入的任何内容,并不断从“health”中减去1。循环运行时,如何调用用户输入的函数 这是我的密码:Function 在循环中调用函数(通用Lisp),function,loops,common-lisp,clisp,Function,Loops,Common Lisp,Clisp,我正在制作一个控制台Lisp生存游戏,我正在尝试添加一个函数,在a=b之前,每秒显示“.”。然后,当a=b时,将一个“hurt”变量设置为true,如果该变量为true,则将“health”减去1,直到用户调用“use medkit”函数且“hurt”变量设置为false,然后退出两个循环 我遇到的问题是,当我被提示使用“use medkit”功能并输入时,它不会计算我输入的任何内容,并不断从“health”中减去1。循环运行时,如何调用用户输入的函数 这是我的密码: (setq a (rand
(setq a (random 11)) ; Random from 0 - 10
(setq b (random 11)) ; ^^^^^^^^^^^^^^^^^^
(setq hurt 0)
(setq repair 0)
(setq health 999)
(defun use-medkit ()
(setq repair 1))
(defun get-hurt ()
(loop
(progn
(setq a (random 11))
(setq b (random 11))
(progn
(princ ".")
(sleep 1)))
(if (eq a b) (progn
(setq hurt 1)
(when (eq hurt 1) (progn
(format t "~%You are hurt!~%You will lose 1 hp every 10 seconds~%~%Type use-medkit to stop the bleeding~%")
(loop
(progn
(- 1 health)
(sleep 10))
;(format t "health: ~A~%" health)
(when (eq repair 1) (progn
(return "You stopped the bleeding") (setq hurt 0) (setq repair 0))))))))))
所以一个程序不能同时做两件事。特别是,如果您正忙于打印点、睡眠和从999中减去1,那么您就不会停下来查看是否有另一个命令来了 不幸的是,解决这个问题很难。终端中最好的解决方案可能是使用类似ncurses的东西。此外,没有控制输入缓冲的标准方法。作为替代,这里有一个简单的方法,您可以执行一些并发和一些提示。您可能希望使用适当的异步库
(defun maybe-read (input-stream recording-stream)
(when (listen input-stream)
(let ((char (read-char input-stream)))
(if (char= char #\Newline)
t
(progn (write-char char recording-stream) (maybe-read))))))
(defun make-partial-reader (input-stream)
(list input-stream (make-string-output-stream)))
(defun partial-read (reader)
(when (apply #'maybe-read reader)
(get-output-stream-string (second reader))))
(defun how-long-until (time)
(let ((gap
(/ (- time (get-internal-run-time)) internal-time-units-per-second)))
(cond ((< gap 0) (values 0 :late))
((<= gap 0.001) (values 0 :now))
(T (values (- gap 0.001) :soon)))))
(defun sleep-until (time)
(multiple-value-bind (span type)
(how-long-until time)
(when (> span 60) (warn “long wait!”)
(case type
(:late nil)
(:now t)
(:soon
(sleep span)
(unless (sleep-until time) (warn “poor timekeeping”))
t))))
(defmacro with-prompt-and-scheduler ((schedule) (line &optional (input *standard-input*)) &body handle-line-input)
(let ((reader (gensym)) (insched (gensym)))
`(let ((,reader (make-partial-reader ,input) (,insched)))
(flet ((,schedule (in fun &aux (at (+ (get-internal-run-time) (* in internal-time-units-per-second))))
(if (null ,insched) (push (cons at fun) schedule)
(loop for s on ,insched
for ((at2) . y) = s
if (< at at2)
do (psetf (car s) (cons at fun)
(cdr s) (cons (car s) (cdr s)))
(finish-loop)
unless y do (setf (cdr s) (acons at fun nil)) (finish-loop)))))
(loop
(if ,insched
(let ((,insched (pop ,insched)))
(when (sleep-until (car ,insched))
(let ((,line (partial-read ,reader)))
(when ,line ,@handle-line-input)))
(funcall (cdr ,insched)))
(let ((,line (concatenate 'string (get-output-stream-string (second ,reader)) (read-line (first ,reader)))))
,@handle-line))))))))
在运行输入10之后,下一行是5。如果您快速完成,您将获得:
Ding 2 2
Ding 1 2
第一行在5秒后出现,第二行在10秒后出现。如果你速度慢,你应该得到:
Ding 1 1
Ding 2 2
第一行在输入10后10秒出现,第二行在输入5后5秒出现
希望这能让你了解如何让一个程序看起来同时做两件事。所以一个程序不能同时做两件事。特别是,如果您正忙于打印点、睡眠和从999中减去1,那么您就不会停下来查看是否有另一个命令来了 不幸的是,解决这个问题很难。终端中最好的解决方案可能是使用类似ncurses的东西。此外,没有控制输入缓冲的标准方法。作为替代,这里有一个简单的方法,您可以执行一些并发和一些提示。您可能希望使用适当的异步库
(defun maybe-read (input-stream recording-stream)
(when (listen input-stream)
(let ((char (read-char input-stream)))
(if (char= char #\Newline)
t
(progn (write-char char recording-stream) (maybe-read))))))
(defun make-partial-reader (input-stream)
(list input-stream (make-string-output-stream)))
(defun partial-read (reader)
(when (apply #'maybe-read reader)
(get-output-stream-string (second reader))))
(defun how-long-until (time)
(let ((gap
(/ (- time (get-internal-run-time)) internal-time-units-per-second)))
(cond ((< gap 0) (values 0 :late))
((<= gap 0.001) (values 0 :now))
(T (values (- gap 0.001) :soon)))))
(defun sleep-until (time)
(multiple-value-bind (span type)
(how-long-until time)
(when (> span 60) (warn “long wait!”)
(case type
(:late nil)
(:now t)
(:soon
(sleep span)
(unless (sleep-until time) (warn “poor timekeeping”))
t))))
(defmacro with-prompt-and-scheduler ((schedule) (line &optional (input *standard-input*)) &body handle-line-input)
(let ((reader (gensym)) (insched (gensym)))
`(let ((,reader (make-partial-reader ,input) (,insched)))
(flet ((,schedule (in fun &aux (at (+ (get-internal-run-time) (* in internal-time-units-per-second))))
(if (null ,insched) (push (cons at fun) schedule)
(loop for s on ,insched
for ((at2) . y) = s
if (< at at2)
do (psetf (car s) (cons at fun)
(cdr s) (cons (car s) (cdr s)))
(finish-loop)
unless y do (setf (cdr s) (acons at fun nil)) (finish-loop)))))
(loop
(if ,insched
(let ((,insched (pop ,insched)))
(when (sleep-until (car ,insched))
(let ((,line (partial-read ,reader)))
(when ,line ,@handle-line-input)))
(funcall (cdr ,insched)))
(let ((,line (concatenate 'string (get-output-stream-string (second ,reader)) (read-line (first ,reader)))))
,@handle-line))))))))
在运行输入10之后,下一行是5。如果您快速完成,您将获得:
Ding 2 2
Ding 1 2
第一行在5秒后出现,第二行在10秒后出现。如果你速度慢,你应该得到:
Ding 1 1
Ding 2 2
第一行在输入10后10秒出现,第二行在输入5后5秒出现
希望这能让您了解如何让程序看起来同时做两件事。一个好的开始是将代码格式化为人类可读的格式。目前它很难阅读。代码实际上表明,您仍然难以使用基本的Lisp编程。这里有一本很好的介绍性书籍,可以免费下载PDF或作为印刷本:这个错误在某种意义上是直接的,在另一种意义上有点微妙。Lisp是单线程的(严格地说,有些含义支持多线程,但我认为您不希望这样)。你们的程序把所有的时间都花在做一些事情上,比如做随机数,打印或者睡觉。它不会停下来让其他任何东西运行。在该功能完成之前,您无法运行
使用medkit
,此时为时已晚。Lisp默认情况下没有事件循环。要知道,在CLsetq
中没有定义变量,因此如果a
不存在,将会发生什么是未定义的。使用defparameter
或defvar
并利用*耳罩*
约定,以避免出现不可能的情况。一个好的开始是以人类可读的方式格式化代码。目前它很难阅读。代码实际上表明,您仍然难以使用基本的Lisp编程。这里有一本很好的介绍性书籍,可以免费下载PDF或作为印刷本:这个错误在某种意义上是直接的,在另一种意义上有点微妙。Lisp是单线程的(严格地说,有些含义支持多线程,但我认为您不希望这样)。你们的程序把所有的时间都花在做一些事情上,比如做随机数,打印或者睡觉。它不会停下来让其他任何东西运行。在该功能完成之前,您无法运行使用medkit
,此时为时已晚。Lisp默认情况下没有事件循环。要知道,在CLsetq
中没有定义变量,因此如果a
不存在,将会发生什么是未定义的。使用defparameter
或defvar
并利用*耳罩*
惯例以避免出现不可能的情况。谢谢!我想让它变得更简单,从不同的角度来处理它,但这真的很有帮助!我建议您首先学习更多的Lisp,然后使用类似cl async和ncurses的东西。或者你只是试图避免多件事情同时发生。谢谢!我想让它变得更简单,从不同的角度来处理它,但这真的很有帮助!我建议您首先学习更多的Lisp,然后使用类似cl async和ncurses的东西。或者你只是试图避免多件事情同时发生。