You may or may not remember Xeyes, a demo program that came with (and, as far as I know, still comes with) the X window system. Its purpose was to draw a pair of eyes that followed your mouse cursor:
Your challenge is to recreate Xeyes with ASCII art. Write a program or function that draws two ASCII art eyes (specified below) wherever the user clicks and then moves their pupils to point in the direction of the cursor.
The above GIF is a recording of this non-golfed Ruby implementation, which can be run with any recent version of Ruby. You may also find it useful as reference for Xterm control sequences.
Specifications
This is code-golf, so the solution with the fewest bytes wins.
This is an ascii-art challenge, so your program must draw using ASCII characters—specifically, the characters -
, .
, |
, '
, 0
, space, and newline.1 2
This is an interactive challenge, so your program must accept input and draw its output in realtime.3
Before your program begins accepting input, it should initialize a blank canvas of at least 20 rows and 20 columns. It should not draw anything until the user clicks on the canvas.
Any time the user clicks4 on the canvas, the program should clear any previous output and then draw these ASCII eyes on the canvas, centered on the character nearest the location of the mouse cursor.5 6 (Below, ✧
represents the mouse cursor and should not be drawn.)
.---. .---.
| | | |
| 0|✧|0 |
| | | |
'---' '---'
Note how the pupils "point" toward the cursor.
Any time the mouse cursor moves on the canvas, the program should re-draw the pupils so that they continue pointing toward the cursor,7 e.g.:
✧
.---. .---.
| 0| | 0|
| | | |
| | | |
'---' '---'
Pupil pointing
Suppose we enumerated the positions of the inner nine characters of each eye like so:
.---.
|678|
|591|
|432|
'---'
The pupil will be drawn at one of the locations 1
-9
. To decide which one, pretend the characters are square and that the canvas is a Cartesian grid, with the center of the 9
character at (0, 0), the center of 1
at (1, 0), and so on. When the program receives input—a click or movement—it should map the input location to the nearest grid coordinate 𝑀. If 𝑀 is (0, 0), the pupil should be drawn at (0, 0), i.e. the location of the 9
above. Otherwise, it should be drawn as described below.
Imagine a Cartesian plane superimposed on the grid and divided into octants numbered 1–8:
If 𝑀 lies within octant 1, then the pupil should be drawn at the location of 1
above, i.e. at (1, 0). If 𝑀 is in octant 2 it should be drawn at 2
—and so on. To illustrate, the below image shows part of the grid color-coded according to where the pupil should be drawn when the mouse cursor is at a particular location. When, for example, the cursor is at any of the green coordinates (keeping in mind that the grid coordinates lie at the squares' centers, not their corners), the pupil should be drawn at 4
.
The two eyes' pupils move independently, so for each eye repeat the process with 𝑀 relative to that eye's center.
Notes
This isn't a graphical-output challenge. The output must be a grid of characters. You may, of course, use graphics routines to draw a grid of characters.
Whitespace may be drawn (or, rather, not drawn) however is convenient. An empty spot in the grid looks the same as a space character and will be considered equivalent.
"Real-time" is defined here as fewer than 200ms between input and the corresponding output being drawn.
It is at your discretion which mouse button(s) are observed for input, and whether a press or release constitutes a "click."
The canvas must be cleared, or the visual equivalent must be achieved. With a terminal-based solution, for example, printing a new canvas below the previous canvas is not considered equivalent.
When the user clicks near the edge of the canvas such that some of the eye characters would be drawn beyond its edge, the behavior is undefined. However, the program must continue running normally upon subsequent clicks.
When the mouse cursor leaves the "canvas," the behavior is undefined, but the program must continue running normally when the cursor re-enters the canvas.
A text cursor may appear on the canvas, as long as it does not obscure the output.
Standard loopholes are forbidden.
<pre>
orfont-family:monospace
). \$\endgroup\$