For...Next loops in TI-BASIC - calculator

I wrote a program (on my TI-84 calculator) to satisfy the following exercise:
Write a program that will print all solutions of the inequality ax + b < c, where a, b, and c are entered by the user. In this program the domain of x will be a set of consecutive integers, where the smallest and largest members of the set will also be entered by the user. (Hint: Use a FOR . . . NEXT loop to test each integer from smallest to largest.)
This is the code I have:
:Input "A=",A
:Input "B=",B
:Input "C=",C
:Disp "DOMAIN FOR X"
:Input "MIN=",D
:Input "MAX=",E
:For(X,D,E,1)
:If AX+B<C
:Disp X
:End
I sort of figured it out by chance; I don't really know how 'If' works inside 'For.' I wanted to have it tell me if there is no solution, though, so I tried:
:Input "A=",A
:Input "B=",B
:Input "C=",C
:Disp "DOMAIN FOR X"
:Input "MIN=",D
:Input "MAX=",E
:For(X,D,E,1)
:If AX+B<C
:Then
:Disp X
:Else
:Disp "NO SOLUTION"
:End
But this returns the value for "MIN=" Why is this? Can anyone help me understand these work?

Perhaps try adding an additional End at the end of the program? As far as I know, you need to have a corresponding End for each For or If, etc.

:Input "A=",A
:Input "B=",B
:Input "C=",C
:Disp "DOMAIN FOR X"
:Input "MIN=",D
:Input "MAX=",E
:For(X,D,E,1)
:If AX+B<C
:Then
:Disp X
:Else
:Disp "NO SOLUTION"
:Stop
:End
Basically, by putting in Stop it will stop the loop as soon as there is no solution.

When the variable you're asking for has the same name as the question, you can use ":Prompt" instead of ":Input". Also, ":Prompt" allows for multiple variables.
For example, instead of
:Input "A=",A
:Input "B=",B
:Input "C=",C
use
:Prompt A,B,C
In TI BASIC, every :If, :For, :While, and :Repeat requires an :End; otherwise, it won't work at all.
This is how to use :If and :For
:If condition
:Then:commands(condition=True)
[:Else:commands(condition=False)]
:End
:For(var,start,end[,interval])
:commands
:End
If the interval=1, you don't need to put it there.
To use :If inside of :For, just make sure your :End's are in the right places. You may also wish to use the ":" character to condense multiple commands on to one line.
As for GDund's answer, that sort of works if you want to end the program there, but if you want to simply leave the loop, what you can do is change the value of the counter variable to the end value, like this:
:For(X,D,E)
:If AX+B<C:Then
:commands:Else
:E-->X:End
:End
Where "-->" is the STO arrow.
If you do want the program to stop right there, you can use :Stop in place of :E --> X.
If you're using this program inside of another program, you can use :Return, instead.
So your code should look like this:
:Prompt A,B,C
:Disp "DOM. FOR X"
:Input "MIN=",D
:Input "MAX=",E
:For(X,D,E)
:If AX+B<C:Then:Disp X
:Else:Disp "NO SOL.":E-->X:End
:End

Have a variable to see whether or not there was a solution.
:Input "A=",A
:Input "B=",B
:Input "C=",C
:Disp "DOMAIN FOR X"
:Input "MIN=",D
:Input "MAX=",E
:0->Q
:For(X,D,E,1)
: If AX+B<C
: Then
: Disp X
: 1->Q
: End
:End
:If Q=0
: Disp "NO SOLUTION"
The variable Q is a boolean to see whether or not there is a solution. If there is, Q is set to true(1). If not, Q remains false(0).

Related

Tycoon script for TI-84 Calculator

I made a Tycoon script for TI-84 Plus CE and I don't think it's really good.
I'm not that good at calculator programming and I don't know much. I just learned some from a friend and a couple YouTube videos.
I was wondering, does anyone know how I can improve this script to make it better?
Here's what I have:
Btw the -> is the STO key.
:ClrHome
:13->S
:5->T
:13->X
:5->Y
:0->B
:5->C
:1->D
:Output(T,S,"CASH:"
:Output(Y,X,"M"
:getkey->A
:X->S
:Y->T
:If A=26
:Then
:X+1->X
:If X=27
:26->x
:End
:If A=34
:Then
:Y+1->Y
:If Y=11
:10->Y
:End
:If A=25
:Then
:Y-1->Y
:If Y=1
:2->Y
:End
:If A=11
:Then
:Stop
:End
:If X=D and Y=C
:Then
:B+1->B
:Output(1,6,B
:End
:If B≥200
:Then
:6->E
:1->F
:Output(E,F,"5"
:End
:If X=F and Y=E and B≥200
:Then
:B+5->B
:Output(1,6,B
:End
:If B≥1500
:Then
:7->G
:1->H
:Output(G,H,"10"
:End
:If X=H and Y=G and B≥1500
:Then
:B+10->B
:Output(1,6,B
:End
:End
Future questions of this nature should be asked at codereview.SE, but I'll take a look at some optimizations for you anyway.
I will only be looking for optimizations in size, not speed (although they may make your program faster). Here are some:
First off, four of these lines can have their end quotes removed (-4)
0->B:5->C can be DelVar B5->C (you can remove the following colon) (-1)
You don't need a Then or End with your If statement if the condition is one line. So, :If A=11:Then:Stop:End can just be :If A=11:Stop (-4)
Now for the major optimizations I see:
First, and perhaps more obvious, is the fact that you call :Output(1,6,B a lot. It looks like you can just move this outside your If block, and remove the Then and End for -4 bytes each
Second, which you may not have known about, are the min( and max( commands, which return the smaller or larger of two values or of a list, respectively. Here's an example:
:If A=26
:Then
:X+1->X
:If X=27
:26->X
:End
The above code is equivalent to:
:If A=26
:min(26,X+1->X
It looks like you can use this optimization four times, which is significant because it makes the program smaller, faster, and more readable.
Overall, I hope I was able to help you. If you have any questions at all, please ask :)

How to remove the brackets from this text

So I have been given the task by my tutor to make a small function that returns a description of your zodiac sign but I"m having problems with the final output of the sign description, the output is still in brackets and I don't know how to get them out.
(defparameter *month-signs* '((January Capricorn Aquarius 19 nil)
(February Aquarius Pisces 18 nil)
....)))
(defparameter *sign-traits* '((Capricorn (You are a goat be happy!))
....)))
(defun cookie (month-signs sign-traits)
(format t "Please input your month of birth followed by return, and then your day of birth.
e.g january <ret> 22 <ret> Thank You. ~%")
(let* ((month (read t));reads in month of birth
(day (read t));reads in day of birth
(month-assoc (assoc month month-signs)))
(cond
((>=(cadddr month-assoc)day);checks if your sign is the first part of the month
(format t "You are ~D~%" (cadr month-assoc));if it is, prints your sign and signs description
(format t "Your sign description is: ~D~%" (cadr(assoc(cadr month-assoc) sign-traits))))
((< (cadddr month-assoc)22);same as above but for the other sign
(format t "You are ~D~%" (caddr month-assoc))
(format t "Your sign description is: ~D~%" (cadr(assoc(caddr month-assoc) sign-traits)))))))
It all works dandy except this bit "(cadr(assoc(caddr month-assoc) sign-traits)" which returns what I want but in brackets and all caps.
CL-USER> (cookie *month-signs* *sign-traits*)
Please input your month of birth followed by return, and then your day of birth.
e.g january <ret> 22 <ret> Thank You.
january
12
You are CAPRICORN
Your sign description is: (YOU ARE A GOAT BE HAPPY)
I'm really struggling to work out what I need to get rid of the (YOU ARE A GOAT BE HAPPY) on the last bit, I'd like it to just print "Your sign description is: You are a goat be happy." it's probably something obvious that I've missed :\
One more thing the .... are just for your sake as the variable is large and would take up a large amount of page space, I slimmed it down as they are all laid out the same way.
In the list '(January Capricorn Aquarius 19 nil), the first three elements are symbols, which are printed out by the REPL in UPPERCASE. Symbols are different from strings. When you quote a list like this, the literals are treated as symbols, not strings.
Similarly, '(You are a goat be happy!) is a list of six symbols. It gets printed out as a list (enclosed in parentheses) of uppercase symbols.
If you replace the symbols and lists with strings:
(defparameter *month-signs* '((January "Capricorn" "Aquarius" 19 nil)...
(defparameter *sign-traits* '((Capricorn "You are a goat be happy!")...
you should get the output you want.
read takes the input as a symbol, so you want to leave the association key (January) as a symbol.
Printing a list with symbols
Common Lisp can print symbols in many ways. The function WRITE gives a basic interface to the printer. We don't want to print string quotes and we want to control how a word gets capitalized.
(defun write-sentence (sentence
&aux ; local variable bindings
(*print-escape* nil) ; no escaping
(*print-readably* nil)) ; we don't print for the reader
(write (first sentence) :case :capitalize)
(dolist (word (rest sentence))
(write " ")
(write word :case :downcase))
(write ".")
(values)) ; return no values
CL-USER 94 > (write-sentence '(YOU ARE A GOAT BE HAPPY))
You are a goat be happy.
PRINC
The standard function to print in a human readable form is PRINC. It does not provide options, other than to optionally specify the output stream. Those need to be bound in the printer control variables. Here we need to tell PRINC which case to use:
(defun write-sentence (sentence)
(let ((*print-case* :capitalize))
(princ (first sentence)))
(dolist (word (rest sentence))
(princ " ")
(let ((*print-case* :downcase))
(princ word)))
(princ ".")
(values))
Format
Similar functionality can be written in a more compact way using the function FORMAT, which includes features to iterate over lists. This example is left as an exercise to decipher:
CL-USER 115 > (format t
"~{~#(~A~)~#{ ~(~A~)~}~}."
'(YOU ARE A GOAT BE HAPPY))
You are a goat be happy.
Case in symbols
It's also possible to specify symbols with case. They need to be escaped in the source code:
|This is a single symbol in Common Lisp!|

Suppress output from print function in Lisp

I'm fairly new to Lisp, and I've run into a printing issue. I have one function which does printing to the standard output (among other things). I want to then run this function through another function where it still runs the same but instead nothing gets printed to the standard output.
Here is a simple example of what I mean. I have the following two functions described:
(defun does-printing()
(print "This goes to standard output."))
(defun run-other-function (function)
(funcall function)
(values))
Here's a dribble of what happens when I run this,
;; Dribble of #<IO TERMINAL-STREAM> started on 2014-10-05 21:49:49.
#<OUTPUT BUFFERED FILE-STREAM CHARACTER #P"example.out">
[7]> (run-other-function #'does-printing)
"This goes to standard output."
[8]> (dribble)
;; Dribble of #<IO TERMINAL-STREAM> finished on 2014-10-05 21:50:09.
Note that the printing function still prints to the standard output. It'd like to be able to suppress this printing somehow when running does-printing through run-other-function. I have tried many different variations of phrasing of my problem when searching for solutions, but nothing is getting at what I would like to do.
The simplest solution is to create an empty broadcast stream.
(with-open-stream (*standard-output* (make-broadcast-stream))
(call-some-function-1)
...
(call-some-function-n))
If a broadcast stream has no component stream all output will be discarded. Above binds the *standard-output* to such a stream. This does not cons up any data and it is portable.
You can just redirect your standard-output to some place. For example into /dev/null if you have one in your operating system. It looks like very idiomatic UNIX-way output suppressing.
Note, that you shouldn't set it to NIL, because print will signal type error in this case.
(defun does-printing()
(print "This goes to standard output."))
(defun run-other-function (function)
(with-open-file (*standard-output*
"/dev/null"
:direction :output
:if-exists :supersede)
(funcall function)
(values)))
CL-USER> (run-other-function #'does-printing)
; No value
Other option (and it may be better) is to use with-output-to-string, so you can capture this output value or just ignore it. Is think it's better, because why to do IO if we don't need it, and also it must work on any OS.
(defun run-other-function (function)
(with-output-to-string (*standard-output*
(make-array '(0)
:element-type 'base-char
:fill-pointer 0 :adjustable t))
(funcall function)
(values)))
If you doing it a lot, you can wrap it into macro or even function, to use in place of funcall.
(defun does-printing()
(print "This goes to standard output.")
"My result")
(defun funcall-with-no-output (fn)
(with-output-to-string (*standard-output*
(make-array '(0)
:element-type 'base-char
:fill-pointer 0 :adjustable t))
(funcall fn)))
CL-USER> (funcall-with-no-output #'does-printing)
"My result"
But i think macro will be more general and idiomatic for this case (may be I'm wrong).
(defmacro with-suppressed-output (&body body)
`(with-output-to-string (*standard-output*
(make-array '(0)
:element-type 'base-char
:fill-pointer 0 :adjustable t))
,#body))
So you can call many forms in with-suppressed-output.

How can I add a format specifier to `format-time-string`?

I have the following function definition:
(defun nth (n)
(format
(concat
"%d"
(if (memq n '(11 12 13)) "th"
(let ((last-digit (% n 10)))
(case last-digit
(1 "st")
(2 "nd")
(3 "rd")
(otherwise "th"))))) n))
and I'd like to be able to use it in format-time-string.
Normally, I would look at the source of the function, but this one is defined in the C source code. (I would presume this precludes hooking something onto it, but I stand to be corrected.)
How can I add another format specifier (say, %o) that will apply nth to the appropriate argument?
Desired usage:
(format-time-string "%A, %B %o, %T (%z)" (seconds-to-time 1250553600))
=> "Monday, August 17th, 20:00:00 (-0400)"
Here is what you want to do. Stefan and Drew already gave some important remarks (don't overwrite nth and look at the info-files of emacs-lisp/advising functions).
(defun ordinal (n)
"Special day of month format."
(format
(concat
"%d"
(if (memq n '(11 12 13)) "th"
(let ((last-digit (% n 10)))
(case last-digit
(1 "st")
(2 "nd")
(3 "rd")
(otherwise "th"))))) n))
(defadvice format-time-string (before ordinal activate)
"Add ordinal to %d."
(let ((day (nth 3 (decode-time (or time (current-time))))))
(setq format-string
(replace-regexp-in-string "%o"
(ordinal day)
format-string))))
Notes:
I did not handle the UNIVERSAL argument
The hack does not work when format-time-string is called from C (as you can read in the manual).
AFAIK you're out of luck: format-time-string does not offer any way to do that.
You might be able to work around this by using something like:
(let ((ti (seconds-to-time 1250553600)))
(format-time-string (concat "%A, %B " (my-nth (format-time-string "%d" ti)) ", %T (%z)") ti))
This said, I've always been told that "August 17th" is wrong: you're supposed to write "August 17" which is pronounced "August the seventheenth".
One more thing: nth is a predefined core function. Better not overwrite it with your own completely different definition.
To add to what Stefan said ("You're out of luck") --
format-time-string is a built-in, but you can advise built-ins too. However, since the kind of surgery you want to do would dig into the bowels of the definition (which you cannot do), you would need to in fact replace the definition of format-time-string in the defadvice, i.e., not use ad-do-it at all.
In other words, one way or the other (defun or defadvice) you would need to completely redefine the function, in Lisp. Which is about the same as saying "You're out of luck."

with-open-file explanation in layman terms

I'm learning CL, and I have minimal experience in other languages. Could someone explain to me in layman terms what this means, especially what "out" here represents, and how it all fits together:
(defun save-db (filename)
(with-open-file (out filename
:direction :output
:if-exists :supersede)
(with-standard-io-syntax
(print *db* out))))
Mostly, the bit I don't understand is "out", but an explanation of the whole thing would be nice.
Thanks
out is the stream variable bound to the open file.
with-open-file guarantees that the file is open inside the scope, and closed
outside the scope, no matter how you exit.
As an addition to ddyer, you can also use MACROEXPAND or MACROEXPAND-1 to see what WITH-OPEN-FILE does:
(macroexpand '(with-open-file (out filename
:direction :output
:if-exists :supersede)
(with-standard-io-syntax
(print *db* out))))
tells us
(LET ((OUT (OPEN FILENAME :DIRECTION :OUTPUT :IF-EXISTS :SUPERSEDE)) (#:G748 T))
(UNWIND-PROTECT
(MULTIPLE-VALUE-PROG1 (PROGN (WITH-STANDARD-IO-SYNTAX (PRINT *DB* OUT)))
(SETQ #:G748 NIL))
(WHEN OUT (CLOSE OUT :ABORT #:G748))))
We can see that we open the file called filename and assign that open file stream to out , and do something. Should something bad happen, UNWIND-PROTECT will CLOSE the stream, should it be non-nil.
The #:G748 variable is a GENSYMed symbol (so it's a fresh, uninterned, symbol). If nothing goes wrong writing the file, we set #:G748 to nil.
Thus, when we CLOSE the stream, if something went wrong #:G748 will be T, so CLOSE will attempt to clean up any side effects of having created the stream.