Game Loop for Racket - loops

I am working on a very basic memory game in RACKET that presents the user with 7 random numbers from 1 to 10 and asks them to type in the numbers in the same order. I can get this to work once but I want it to continually run until the user exits out. (Repeat MAIN PROGRAM) Any ideas on how to accomplish this???
(require math/base)
; =======================================
; Functions
; =======================================
; set essentially constants
(define lowerLimit 1)
(define upperLimit 11)
(define amount 7)
; builds a list with random integers between lowerLimit and upperLimit
(define (buildSimon x L)
(cond [(= x 0) L]
[else (buildSimon (- x 1) (cons (random-integer lowerLimit upperLimit) L))]))
; adds element to back of the list
(define (addBack L e)
(if (null? L)
(list e)
(cons (first L) (addBack (rest L) e))))
; gets input from user and builds list
(define (getInput n x L)
(cond [(= n 1) (addBack L x)]
[else (getInput (- n 1) (read) (addBack L x))]))
; =======================================
; Main program below here
; =======================================
; Generate new random number sequence
(printf "Simon says: ")
(define sequence (buildSimon amount (list)))
(display sequence) (newline)
(printf "== Memorize and guess ==\n")
(printf "== Type 'go' and hit enter to guess ==\n")
(read)
; Add spacing to hide numbers
(printf "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n")
(printf "== Type the numbers in order as they appeared. ==\n")
(printf "== Hit ENTER in between each number. ==\n")
; Gather input for comparison
(define answer (getInput amount (read) (list)))
; Do comparison
(if (equal? sequence answer)
(printf "Correct! Congratulations on your perfect memory.\n")
(printf "Wrong! I'm sorry your memory has failed you.\n"))
Thank you in advance.

You can create a function which contains all of your main code, with the last line of the function recursively calling itself.

Related

Lisp loop macro, pop macro and memory

I'm learning lisp and and implemented a nested array parses, so that:
"[1,[2,[3,[4,[5,6,7]]]],8,9]" -> '(1 (2 (3 (4 (5 6 7)))) 8 9)
Online Code snippet here
This was my first implementation of parse-line
(defun parse-line (string)
(loop
:for i = 0 :then (1+ j)
:for stack = (list nil)
:as j = (position-if (lambda (c) (member c '(#\[ #\] #\,))) string :start i)
:as n = (parse-integer string :start i :end j :junk-allowed t)
:when n :do (push n (car stack))
:while j
:do (cond
((eql #\[ (aref string j)) (push nil stack))
((eql #\] (aref string j)) (push (nreverse (pop stack)) (car stack))))
:finally (return (car (pop stack))))
))
But it crashes on the stack pop.
;test-case
(print (equal '(1 (2 (3 (4 (5 6 7)))) 8 9) (parse-line "[1,[2,[3,[4,[5,6,7]]]],8,9]")))
The value
NIL
is not of type
CONS
I then brute-forced my way into a solution declaring stack with let outside the loop macro
(defun parse-line (string)
(let ((stack (list nil)))
(loop
:for i = 0 :then (1+ j)
:as j = (position-if (lambda (c) (member c '(#\[ #\] #\,))) string :start i)
:as n = (parse-integer string :start i :end j :junk-allowed t)
:when n :do (push n (car stack))
:while j
:do (cond
((eql #\[ (aref string j)) (push nil stack))
((eql #\] (aref string j)) (push (nreverse (pop stack)) (car stack))))
:finally (return (car (pop stack))))
))
But I can't see why the second implementation works.
I also can't see why I need to initialize stack with (list nil). I thought that initializing stack to nil and removing the final car should be equivalent but it crashes with the same error at the same place, ie:
(defun parse-line (string)
(let (stack)
(loop
:for i = 0 :then (1+ j)
:as j = (position-if (lambda (c) (member c '(#\[ #\] #\,))) string :start i)
:as n = (parse-integer string :start i :end j :junk-allowed t)
:when n :do (push n (car stack))
:while j
:do (cond
((eql #\[ (aref string j)) (push nil stack))
((eql #\] (aref string j)) (push (nreverse (pop stack)) (car stack))))
:finally (return (pop stack)))
))
Look at these two lines in your first implementation:
:for i = 0 :then (1+ j)
:for sack = (list nil)
There is a typo (sack -> stack), but even then it doesn't work, because with each new value of i, you will create a brand new stack, losing all previous values. Add some debug print to see, what's going on:
i:0 j:0 n:NIL stack:(NIL NIL)
i:1 j:2 n:1 stack:((1))
i:3 j:3 n:NIL stack:(NIL NIL)
i:4 j:5 n:2 stack:((2))
i:6 j:6 n:NIL stack:(NIL NIL)
i:7 j:8 n:3 stack:((3))
...
If you don't want to use let to initialize stack, you can use keyword :with:
(defun parse-line (string)
(loop
:with stack = (list nil)
:for i = 0 :then (1+ j)
:as j = (position-if (lambda (c) (member c '(#\[ #\] #\,))) string :start i)
:as n = (parse-integer string :start i :end j :junk-allowed t)
:when n :do (push n (car stack))
:while j
:do (cond
((eql #\[ (aref string j)) (push nil stack))
((eql #\] (aref string j)) (push (nreverse (pop stack)) (car stack))))
:finally (return (car (pop stack)))))
You can use a similar debug print to see, why your code crashes with stack initialized to nil. This error can be reproduced with:
> (let ((stack '((9 8 (2 (3 (4 (5 6 7)))) 1))))
(push (nreverse (pop stack)) (car stack)))
Error: NIL (of type NULL) is not of type CONS.
You can find some explanation for this behaviour here: Why I can't (push 3 '()) in Common Lisp's REPL?
I would recommend using a Lisp compiler and using its warnings. SBCL gives this warning on your first form:
; in: DEFUN PARSE-LINE
; (PUSH N (CAR STACK))
;
; caught WARNING:
; undefined variable: COMMON-LISP-USER::STACK
;
; compilation unit finished
; Undefined variable:
; STACK
; caught 1 WARNING condition
That would lead you to investigate why that is: why is STACK undefined?

Common Lisp Loop

In the following loop:
(let ((funs (loop for i upto 3 do (print i) collect #'(lambda () i))))
(loop for fun in funs collect (funcall fun)))
i would intuitively think i would get a list of four closures which return the numbers 0 1 2 and 3 upon being called, but this is what i get:
>> 0
>> 1
>> 2
>> 3
=> (4 4 4 4)
But rebinding the i locally to something else:
(let ((funs (loop for i upto 3 do (print i) collect (let ((x i))
#'(lambda () x)))))
(loop for fun in funs collect (funcall fun)))
works as expected:
>> 0
>> 1
>> 2
>> 3
=> (0 1 2 3)
So each of the functions return 4, why are all return values the same, and why 4?
update
This seems to be a question about lambda actually. See below:
(setq dynamic-var 8
funs ())
(push (lambda () dynamic-var) funs)
(incf dynamic-var)
(push (lambda () dynamic-var) funs)
(mapcar #'funcall funs) ;(9 9)
What does
(let (i ; a counter variable
f) ; a list of functions
(setf i 1)
(push (lambda () i) f)
(setf i 2)
(push (lambda () i) f)
(mapcar #'funcall f))
return?
How about:
(let (i
f)
(setf i 1)
(push (lambda () i) f)
(let (i)
(setf i 2)
(push (lambda () i) f))
(mapcar #'funcall f))
Which is the LOOP model?
See also:
CL-USER 42 > (let (f)
(dotimes (i 10 (mapcar #'funcall (reverse f)))
(push (lambda () i) f)))
(10 10 10 10 10 10 10 10 10 10)
CL-USER 43 > (let (f)
(dotimes (i 10 (mapcar #'funcall (reverse f)))
(push (let ((i i))
(lambda () i))
f)))
(0 1 2 3 4 5 6 7 8 9)
The Common Lisp standard says for DOTIMES:
It is implementation-dependent whether dotimes establishes a new binding of var on each iteration or whether it establishes a binding for var once at the beginning and then assigns it on any subsequent iterations.
you write:
i would intuitively think i would get a list of four closures which return the numbers 0 1 2 and 3 upon being called
This intuition is only partly correct. You get four closures, but in this case they all share one variable binding. Thus they can only see the current binding of this one variable. In Common Lisp this binding is mutable and closures see the current binding, not the one of the initial binding of closure creation time.
Your intuition would be right, when each closure had its own variable binding.
Additional answer: why is this Lisp returning 10 ?
(PROGN
(SETQ I (THE INTEGER (1+ (THE INTEGER I))))
(WHEN (>= (THE INTEGER I)
(THE INTEGER #:|dotimes-count-1075|))
(GO #:|dotimes-end-tag1080|)))
Above is a part of the macro expansion of the dotimes construct. As you can see it first increments the variable and then tests for >=. Thus it exits when I is >= 10. Thus the last value of I is 10. Later after exiting the dotimes you are retrieving the value of I and then it's 10.

Multiplying numbers and outputting result in a file in SCHEME

I am new to the concept of SCHEME and just started learning Scheme (and DrRacket). Started with some online resources including, DrRacket Docs. Following this and some other references online, I am trying to solve a basic problem which involves reading 2 numbers from a file (data.inp), multiplying the numbers and displaying the output in a different file (result.out).
So far, I have been able to come up with following code,
#lang racket
(define (file->char_list path)
(call-with-input-file path
(lambda (input-port)
(let loop ((x (read-char input-port)))
(cond
((eof-object? x) '())
(#t (begin (cons x (loop (read-char input-port))))))))))
(define (yb)
;(call-with-input-file "data.inp"
;(lambda (in) (read-string 14 in)
; ))
;(call-with-output-file "result.out"
;(lambda (output-port)
; (display "(* x x)" output-port)))
; Fill in the blank
;(fprintf (current-output-port) "Done!~n"))
(string->number (apply string (file->char_list "data.inp"))))
(yb)
I am stuck at reading numbers from a file (data.inp) and multiplying them. I have references some previous stackoverflow questions but I am sort of stuck at this point. Any help will be appreciated :)
In Scheme, most of the time you'll probably want to use the default "current" ports for input and output. On most Unix systems, the default current input port is linked to stdin and the default current output port is linked to stdout.
With that in mind, reading in two numbers and writing out their product is basically:
(display (* (read) (read)))
Now, if you want to use actual input and output files, like you mentioned in your question, then you can either wrap with with-input-from-file/with-output-to-file (which temporarily changes the current input and output port):
(with-input-from-file "data.inp"
(lambda ()
(with-output-to-file "result.out"
(lambda ()
(display (* (read) (read)))))))
or you can explicitly specify ports, and leave the current/default input and output ports unchanged:
(call-with-input-file "data.inp"
(lambda (in)
(call-with-output-file "result.out"
(lambda (out)
(display (* (read in) (read in)) out)))))

Difficulty performing actions in a finite loop with user input

I'm using Allegro CL Express on a Mac and I'm not sure if the program is having difficulties, or my code is poorly formed. I'm trying to take 4 user input integers and then add them after the last value is entered
Desired outcome:
(stuff)
Enter a number: 4
Enter a number: 3
Enter a number: 2
Enter a number: 1
10
Here's what I currently have:
(defun stuff ()
(loop repeat 4
sum (format t "Enter a number: ")
(parse-integer (read-line))))
EDIT:
After some great help, here is what I have:
CG-USER(18): (defun stuff ()
(loop repeat 4
sum (progn
(format t "Enter a number: ")
(parse-integer (read-line)))))
STUFF
CG-USER(19): (stuff)
Enter a number: 1
It just hangs after I enter an integer and press return.
Using a compiler helps. Look what SBCL says when evaluating your form:
CL-USER> (defun stuff ()
(loop repeat 4
sum
(format t "Enter a number: ")
(parse-integer (read-line))))
; in: DEFUN STUFF
; (LOOP REPEAT 4
; SUM (FORMAT T "Enter a number: ") (PARSE-INTEGER (READ-LINE)))
;
; caught ERROR:
; during macroexpansion of (LOOP REPEAT 4 ...). Use *BREAK-ON-SIGNALS* to
; intercept.
;
; (PARSE-INTEGER
; (READ-LINE)) found where a LOOP keyword or LOOP type keyword expected
; current LOOP context: SUM (FORMAT T "Enter a number: ") (PARSE-INTEGER
; (READ-LINE)).
;
; compilation unit finished
; caught 1 ERROR condition
STUFF
The most important part there is
; (PARSE-INTEGER
; (READ-LINE)) found where a LOOP keyword or LOOP type keyword expected
; current LOOP context: SUM (FORMAT T "Enter a number: ") (PARSE-INTEGER
; (READ-LINE)).
So it's getting (PARSE-INTEGER (READ-LINE)) where a loop keyword or type is expected. Why's that? The documentation for loop should tell us. sum is a numeric accumulation:
numeric-accumulation::= { count | counting | sum |
summing | maximize | maximizing |
minimize | minimizing }
{form | it}
[into simple-var] [type-spec]
So, after sum, there should be a single form. You'd just need to wrap your prompt and the call to read-line in, e.g., a progn to produce a single form:
(defun stuff ()
(loop repeat 4
sum (progn
(format *query-io* "Enter a number: ")
(parse-integer (read-line *query-io*)))))
Note also that I used the stream *query-io* for input and output. You don't have to do that, but it's probably a bit more robust, since:
The value of *query-io*, called query I/O, is a bidirectional stream
to be used when asking questions of the user. The question should be
output to this stream, and the answer read from it.

for/continue in scheme/lisp

I'm writing a small interpreter for a C-like language in Scheme (R5RS) and trying to convert something like:
for (i = 0; i < 100; i++)
{
if (isprime(i)) continue;
else /* do something with i */
}
to valid Scheme (the isprime function is just an example and not important).
However, after trying for some time, I have not been able to find an efficient/simple way to add the equivalent of a continue statement to a do loop in Scheme. What would be even better would be a "for" macro which allows "continue" and "break" to be used.
I'm considering switching to Common Lisp. Would this sort of thing be any easier in CL?
We can write FOR as a macro. The Common Lisp version:
(defmacro for ((var start end) &body body)
(let ((block-name (gensym "BLOCK")))
`(loop for ,var from ,start below ,end
do (block ,block-name
(flet ((continue ()
(return-from ,block-name)))
,#body)))))
CL-USER 2 > (for (i 10 20)
(if (evenp i) (continue))
(print i))
11
13
15
17
19
CL's tagbody is a convenient target:
(let (i)
(tagbody
(setf i 0)
body
(if (isprime i)
(go increment))
(do-something-with i)
increment
(setf i (1+ i))
(if (< i 100)
(go body))))
I'd go for continuations like in this pseudo-scheme example.
Just store the current point of execution in a continuation and call it when appropriate.
(call/cc (lambda break ; jump outside the for
(for 0 100 (lambda i
(call/cc (lambda continue ; jump to the next iteration
(if (isprime i)
(continue)
(break))))))))
I know this is 8 years late, but I thought it might help someone.
Using the iterate construct in Common Lisp, you could use the next-iteration clause:
(iter (for i from 0 to 100)
(if (isprime i)
(next-iteration)
(do-something-else)))
The straightforward Scheme way to achieve this is just to restructure your code:
for (i = 0; i < 100; i++)
{
if (isprime(i)) continue;
if (is_bad(i)) break;
else /* do something with i */
}
is
(let loop ((i 0))
(cond
((isprime i) ;; continue the loop
(loop (+ i 1)))
((is_bad i)
#f) ;; break from the loop
(else ;; do something with i
....... ;; and then continue the loop
(loop (+ i 1)))))
If your loop body is tangled and you want to (continue) or (break) from deep inside its nested structure, either have your compiler restructure it in the above way, or you could set up exit points with call/cc as e.g.
(call/cc (lambda (break)
(let loop ((i 0))
(call/cc (lambda (continue)
;; your loop logic here,
;; potentially using
;; (continue A) ;; A is ignored
;; or
;; (break B) ;; B is immediately returned as
;; ;; the overall loop's result
))
;; (continue _) continues here:
(loop (+ i 1)))))
Racket has delimited continuations which should be more efficient.
To implement this particular code sample in Scheme, you don't need continue, break or call/cc:
(let loop ((i 0))
(when (< i 100)
(if (prime? i)
(loop (add1 i)))
(do-something-else)))
I think Vijay's answer can be extended in a way that works (sorry for answering my own question, but can't figure out how to format code in a comment):
(let loop ((i 0))
(define (next)
(loop (+ i 1)))
(call/cc
(lambda (break)
(if (< i 100)
(begin
(if (isprime i)
(next)
(begin
(if (isbad i)
(break break))
(do-something)
(next))))))))
It's not a macro, but doubtlessly leads to one that's general enough. I'd be interested to see any improvements. I'm pretty new to Scheme.
You can use throw and catch as well (elisp):
(let ((j 0))
(while (< j 10)
(catch 'continue
(setq j (1+ j))
(if (= j 3) (throw 'continue t))
(prin1 j))))
1245678910nil

Resources