2
votes

This is a console program in Common Lisp for a Hangman type game. The first player enters a string to be guessed by the second player. My input function is below --- unfortunately the characters typed by the first player remain visible.

With JavaScript it's simple, just use a password text entry box. With VB it's simple using the same sort of facility. Is there any way to do this using a native Common Lisp function?

Thanks, CC.

(defun get-answer ()
  (format t "Enter the word or phrase to be guessed: ~%")
  (coerce (string-upcase (read-line)) 'list))

(defun start-hangman ()
  (setf tries 6)
  (greeting)
  (setf answer (get-answer))
  (setf obscure (get-obscure answer))
  (game-loop answer obscure))
2
Why don't you just print a bunch of new lines after player 1 enters the word so it goes off the screen :Dtsikov

2 Answers

6
votes

Each implementation supports this differently.

You might want to use an auxiliary library like iolib.termios or cl-charms (interface to libcurses) if you want a portability layer above different implementations.

SBCL

I found a discussion thread about it for SBCL, and here is the code for that implementation, from Richard M. Kreuter:

(require :sb-posix)

(defun echo-off ()
  (let ((tm (sb-posix:tcgetattr sb-sys:*tty*)))
    (setf (sb-posix:termios-lflag tm)
      (logandc2 (sb-posix:termios-lflag tm) sb-posix:echo))
    (sb-posix:tcsetattr sb-sys:*tty* sb-posix:tcsanow tm)))

(defun echo-on ()
  (let ((tm (sb-posix:tcgetattr sb-sys:*tty*)))
    (setf (sb-posix:termios-lflag tm)
      (logior (sb-posix:termios-lflag tm) sb-posix:echo))
    (sb-posix:tcsetattr sb-sys:*tty* sb-posix:tcsanow tm)))

And so, here is finally an opportunity to talk about PROG2:

(defun read-silently ()
  (prog2
    (echo-off)
    (read-line sb-sys:*tty*)
    (echo-on)))

However, you might want to ensure that the echo is always reset when unwinding the stack, and clear the input before inputting things:

(defun read-silently ()
  (echo-off)
  (unwind-protect 
      (progn
        (clear-input sb-sys:*tty*)
        (read-line sb-sys:*tty*))  
    (echo-on)))

CL-CHARMS

Here is an alternative using libcurse. The following is sufficient to make a simple test work.

(defun read-silently ()
  (let (input)
    (charms:with-curses ()
      (charms:disable-echoing)
      (charms:enable-raw-input)
      (clear-input *terminal-io*)
      (setf input (read-line *terminal-io*))
      (charms:disable-raw-input)
      (charms:enable-echoing))
    input))

Besides, using libcurse might help you implement a nice-looking hangman console game.

0
votes

Are you printing to a console? That's an inherent limitation of standard consoles.

You'll need to print a ton of newlines to push the text off the screen.

Many consoles aren't capable of fancy things like selectively erasing parts of the screen.