Visualizza Visual Eyes


42

Potresti ricordare Xeyes, un programma demo fornito (e, per quanto ne so, ancora) con il sistema X Window. Il suo scopo era quello di disegnare un paio di occhi che seguivano il cursore del mouse:

xeyes

La tua sfida è ricreare Xeyes con l'arte ASCII. Scrivi un programma o una funzione che disegna due occhi artistici ASCII (specificati di seguito) ovunque l'utente faccia clic e quindi sposta le proprie pupille verso la direzione del cursore.

GIF di Terminal Eyes

La GIF sopra è una registrazione di questa implementazione Ruby non giocata a golf , che può essere eseguita con qualsiasi versione recente di Ruby. Potresti anche trovarlo utile come riferimento per le sequenze di controllo Xterm.

specificazioni

Questo è , quindi vince la soluzione con il minor numero di byte.

Si tratta di un sfida, in modo che il programma deve disegnare utilizzando caratteri ASCII-specificamente, i personaggi -, ., |, ', 0, spazio, e ritorno a capo. 1 2

Questa è una sfida , quindi il tuo programma deve accettare input e disegnare i suoi output in tempo reale. 3

Prima che il programma inizi ad accettare l'input, dovrebbe inizializzare un'area vuota di almeno 20 righe e 20 colonne. Non dovrebbe disegnare nulla fino a quando l'utente non fa clic sulla tela.

Ogni volta che l'utente fa clic su 4 nell'area di disegno, il programma dovrebbe cancellare qualsiasi output precedente e quindi disegnare questi occhi ASCII sull'area di disegno, centrati sul carattere più vicino alla posizione del cursore del mouse. 5 6 (Sotto, rappresenta il cursore del mouse e non deve essere disegnato.)

.---. .---.
|   | |   |
|  0|✧|0  |
|   | |   |
'---' '---'

Nota come gli alunni "puntano" verso il cursore.

Ogni volta che il cursore del mouse si sposta sulla tela, il programma dovrebbe ridisegnare le pupille in modo da continuare punta verso il cursore, 7 ad esempio:




.---. .---.
|  0| |  0|
|   | |   |
|   | |   |
'---' '---'

Pupilla che punta

Supponiamo di aver elencato le posizioni dei nove personaggi interni di ciascun occhio in questo modo:

.---.
|678|
|591|
|432|
'---'

L'allievo verrà disegnato in una delle posizioni 1- 9. Per decidere quale, fingere che i caratteri siano quadrati e che la tela sia una griglia cartesiana, con il centro del 9personaggio in (0, 0), il centro di 1in (1, 0) e così via. Quando il programma riceve input - un clic o un movimento - dovrebbe mappare la posizione di input alla coordinata della griglia più vicina 𝑀. Se 𝑀 è (0, 0), l'alunno deve essere disegnato su (0, 0), ovvero la posizione di cui 9sopra. Altrimenti, dovrebbe essere disegnato come descritto di seguito.

Immagina un piano cartesiano sovrapposto alla griglia e diviso in ottanti numerati 1 - 8 :

Se 𝑀 si trova all'interno dell'ottante 1 , la pupilla deve essere disegnata nella posizione 1sopra, cioè in (1, 0). Se 𝑀 è nell'ottante 2 , dovrebbe essere disegnato su 2—e così via. Per illustrare, l'immagine seguente mostra parte della griglia codificata a colori in base a dove deve essere disegnata la pupilla quando il cursore del mouse si trova in una posizione particolare. Quando, ad esempio, il cursore si trova su una delle coordinate verdi (tenendo presente che le coordinate della griglia si trovano nei centri dei quadrati, non nei loro angoli), si deve disegnare la pupilla 4.

Le pupille dei due occhi si muovono indipendentemente, quindi per ciascun occhio ripetere il processo con 𝑀 rispetto al centro di quell'occhio.

Gli appunti

  1. Questa non è una sfida di . L'output deve essere una griglia di caratteri. Ovviamente puoi usare le routine grafiche per disegnare una griglia di caratteri.

  2. Gli spazi bianchi possono essere disegnati (o, piuttosto, non disegnati) tuttavia è conveniente. Un punto vuoto nella griglia ha lo stesso aspetto di uno spazio e sarà considerato equivalente.

  3. "Tempo reale" è definito qui come meno di 200 ms tra l'ingresso e l'uscita corrispondente che viene disegnata.

  4. È a tua discrezione quali pulsanti del mouse vengono osservati per l'input e se una pressione o un rilascio costituisce un "clic".

  5. La tela deve essere cancellata o l'equivalente visivo deve essere raggiunto. Con una soluzione basata su terminali, ad esempio, la stampa di una nuova tela sotto la tela precedente non è considerata equivalente.

  6. Quando l'utente fa clic vicino al bordo della tela in modo tale che alcuni dei personaggi dell'occhio vengano disegnati oltre il bordo, il comportamento non è definito. Tuttavia, il programma deve continuare a funzionare normalmente dopo i clic successivi.

  7. Quando il cursore del mouse lascia la "tela", il comportamento non è definito, ma il programma deve continuare a funzionare normalmente quando il cursore rientra nella tela.

  8. Un cursore di testo può apparire sulla tela, purché non oscuri l'output.

Sono vietate le scappatoie standard.


2
@ Οurous Dato che quanti minuti sono "pochi" in quel caso dipenderebbe da quanta memoria ha il sistema e che potrebbe portarci nel territorio "questa soluzione presuppone che l'ambiente abbia 512 GB di RAM", dirò che deve potenzialmente funzionare a tempo indeterminato.
Giordania,

1
@TaylorScott Nope. Vedi nota n. 6 (a meno che non abbia frainteso la tua domanda).
Giordania,

1
@ Οurous Sì, e no. Se l'ambiente di destinazione è in genere uno in cui il carattere predefinito è monospace (ad esempio, un emulatore di terminale o un editor di codice), allora va bene. Se l'utilizzo di un carattere monospace in quell'ambiente richiede in genere una configurazione aggiuntiva (come in una soluzione JS basata su browser), tale configurazione deve far parte del conteggio dei byte (ad es. <pre>O font-family:monospace).
Giordania,

9
+1 per un ottimo titolo (o titolo negativo, a seconda di come lo prendi)
FantaC,

1
@ Οurous No, purché non si interrompa in modo imprevisto.
Giordania,

Risposte:


12

HTML + CSS + JavaScript (ES6), 93 + 19 + 278 276 = 388 byte

w=7.8125
h=15
with(Math)r=round,
(onclick=e=>F.style=`margin:-3.5em -6.5ch;left:${x=r(e.x/w)*w}px;top:${y=r(e.y/h)*h}px`)({y:-40}),onmousemove=e=>(s=($,o)=>$.style=`left:${a=atan2(Y=r((e.y-y)/h),X=r((e.x-x)/w+o)),X|Y?w*r(cos(a)):0}px;top:${X|Y?h*r(sin(a)):0}px`)(L,3)&&s(R,-3)
*{position:relative
<pre id=F>.---. .---.
|   | |   |
| <a id=L>0</a> | | <a id=R>0</a> |
|   | |   |
'---' '---'


Entrambi X||Ypossono essere giocati a golf X|Yper salvare 2 byte.
Kevin Cruijssen il

Non funziona così bene quando fai clic vicino al fondo del contenitore e devi scorrere verso il basso. i.stack.imgur.com/s44KU.png Non sono sicuro se specifico del wrapper dello snippet, ma vale la pena menzionarlo.
Draco18s

2
@ Οurous È formulato in modo piuttosto ambiguo: "centrato nella posizione del cursore del mouse". "Posizione" significa "cella griglia" o può significare "pixel"? Concordo sul fatto che l'intento era probabilmente il primo, ma la formulazione sembra certamente consentire il secondo.
DLosc,

@KevinCruijssen Sfortunatamente, ciò non funziona - |finisce per avere la precedenza sull'espressione ternaria.
darrylyeo,

@darrylyeo No, non è così? : S Questa tabella di precedenza dell'operatore JavaScript mostra |e ||allo stesso modo allo stesso livello, e entrambi sopra ?:. Entrambi X||Y?w*r(cos(a)):0e X||Y?h*r(sin(a)):0sono attualmente nel modulo boolean_condition?A:B. Così, quando si cambia X||Yad X|Yesso farà un bit per bit OR e quindi di interpretare come una condizione booleana di nuovo. ( (X||Y)?A:Bvs (X|Y)?A:B, non X|(Y?A:B)). Inoltre, non vedo alcuna differenza quando uso "Copia snippet per rispondere" e cambio ||a |. Tutto funziona ancora esattamente allo stesso modo per quanto posso dire ...
Kevin Cruijssen,

12

Excel VBA, 630 byte

Sottoprogramma del foglio di lavoro dichiarato che viene eseguito con un clic del mouse che non accetta input e produce un paio di occhi che seguono il cursore. Ciò dipende dalla funzione di supporto inclusa e dalla dichiarazione del tipo, che deve essere inserita in un modulo normale.

Questa versione è calibrata per funzionare con lo zoom predefinito del 100%. Si interrompe se si tenta di scorrere.

Nota: VBA completa automaticamente la stringa non terminata nella nuova riga, quindi nel codice seguente ci sono tre casi in cui un terminale "è stato incluso solo a scopo di evidenziazione - questi non contribuiscono al byte by

Sub Worksheet_SelectionChange(ByVal t As Range)
With Cells
.Clear
.Font.Name="Courier"'<--- `"` included only for highlighting
.ColumnWidth=1.3
.RowHeight=15
End With
[A1]=" "'<--------------- `"` included only for highlighting
Dim l As p,p As p
GetCursorPos l
While[A1]=" "'<---------- `"` included only for highlighting
DoEvents
GetCursorPos p
For i=0To 1
x=l.x+IIf(i,-56,56)
n=Evaluate("=-Int(-8/Pi()*ATan2("& x-p.x &","& l.y-p.y+0.1 &"))")
n=Asc(-Int(-IIf(Abs(p.x-x)<7And Abs(p.y-l.y)<10,9,IIf(n<-6,8,n)-1)/2)+4)
j=1
For Each c In t.Offset(-2,IIf(i,-5,1)).Resize(5,5)
d=Mid(".---.|567||498||321|'---'",j,1)
c.Value=IIf(d Like"[0-9]",IIf(Asc(d)=n,0," "),"'"&d)
j=j+1
Next c,i
Wend
End Sub

Funzione di supporto e dichiarazione del tipo

Declare Sub GetCursorPos Lib"user32"(l As p)
Type p
x As Long
y As Long
End Type

Ungolfed e commentato

Questa versione è calibrata per essere eseguita con un livello di zoom del 400%.

''  must be placed in a worksheet code module

''  define this module to run whenever the user either clicks
''  or moves the selection with the arrow keys
Private Sub Worksheet_SelectionChange(ByVal T As Range)

    ''  Declare vars
    Dim refPos  As POSITION, _
        curPos  As POSITION, _
        c       As Range, _
        d       As String, _
        i       As Integer, _
        j       As Integer, _
        n       As Integer, _
        x       As Integer

    ''  Explicitly state that this works only on the
    ''  Worksheet for which this code has been defined
    With Application.ActiveSheet

        ''  Clear eyes and escape var
        Call .Cells.ClearContents

        ''  Define escape var
        Let .[A1] = " "

        ''  Define reference position
        Call GetCursorPos(refPos)

        ''  While not escaped
        Do While [A1] = " "

            ''  Prevent Excel from appearing to freeze
            Call VBA.DoEvents

            ''  Check where the cursor is
            Call GetCursorPos(curPos)

            ''  Iterate over the eyes' indexes
            For i = 0 To 1 Step 1

                ''  Define the reference center of the eye, left first
                Let x = refPos.x + IIf(i, -168, 168)

                '' figure out which of the directions to point the eye and assign that value to `n`
                Let n = Evaluate("=-Int(-8/Pi()*ATan2(" & x - curPos.x & "," & refPos.y - curPos.y + 0.1 & "))")
                Let n = Asc(-Int(-IIf(Abs(curPos.x - x) < 28 And Abs(curPos.y - refPos.y) < 40, 9, IIf(n < -6, 8, n) - 1) / 2) + 4)

                ''  define character index
                Let j = 1

                ''  Iterate over the range in which the eye is to be drawn
                For Each c In T.Offset(-2, IIf(i, -5, 1)).Resize(5, 5)

                    ''  get correct char from the reference data
                    Let d = Mid(".---.|567||498||321|'---'", j, 1)

                    ''  check if the char is a number, if so only keep it if it matches `n`
                    Let c.Value = IIf(d Like "[0-9]", IIf(Asc(d) = n, 0, " "), "'" & d)

                    '' iterate j
                    j = j + 1
            Next c, i
        Loop
    End With
End Sub

Funzione di supporto e dichiarazione del tipo

''  Declare the 64-Bit Window API function
Declare PtrSafe Function GetCursorPos Lib "user32" (ByRef posObj As POSITION) As LongLong

''  Define the POSITION type; 0,0 is top left of screen
Type POSITION
x As Long
y As Long
End Type

''  Pre-Operations for optimization
Sub Initialize()
    With Cells

        ''  Define the font as being mono-spaced
        .Font.Name = "Lucida Console"

        ''  Define the size of the cells to be tightly bound around a single char
        .ColumnWidth = 1.5
        .RowHeight = 15
    End With
End Sub

Produzione

gif

Moving_Eyes

Immagine ad alta risoluzione

Static_Eyes


Questo non corrisponde alle specifiche in alcuni modi. 1. "Griglia di caratteri" indica singoli personaggi con posizioni distinte. Quando il cursore del mouse è attivo, ad esempio, il 'carattere più a destra l'output sarà diverso da quando si trova sul 'carattere più a sinistra . 2. La posizione degli occhi non è fissa. Un clic del mouse dovrebbe farli spostare nella posizione selezionata. Sono flessibile sul metodo di input (accetterei, per esempio, un cursore del mouse virtuale controllato dai tasti freccia), ma ci sono due eventi di input distinti con comportamento distinto: movimento del mouse e clic del mouse.
Giordania,

@Jordan Non sono del tutto sicuro di cosa intendi per punto 1, potresti per favore elaborare? Per quanto riguarda il punto 2, gli occhi non sono statici e facendo clic su qualsiasi cella sul foglio in cui è collocata la subroutine si innescherà l' Worksheet_SelectionChangeevento e supererà l'intervallo di chiamata ( Targeto Tin questo caso) - che ridisegna gli occhi e a *nella chiamata cell
Taylor Scott

1
@Jordan - Credo di aver affrontato tutte le tue preoccupazioni, anche se, nel farlo, ho dovuto limitare la mia soluzione a Excel a 64 bit e sto lavorando su una versione non controllata e commentata in questo momento
Taylor Scott

1
@Jordan Questo perché le dichiarazioni API di Windows per 32 e 64 ma VBA sono diverse, così come le specifiche di concatenazione ed esponenziazione, dove 32 bit è quasi sempre più breve - e al momento non ho accesso a una versione di Office a 32 bit: P
Taylor Scott

3
Forse cambiare i due screenshot in uno screen-to-gif ?
Kevin Cruijssen il

7

QBasic ( QB64 ), 361 305 byte

DO
WHILE _MOUSEINPUT
x=CINT(_MOUSEX)
y=CINT(_MOUSEY)
IF _MOUSEBUTTON(1)THEN l=x-3:k=y
IF(2<l)*(73>l)*(2<k)*(22>k)THEN CLS:FOR i=0TO 1:h=l+6*i:LOCATE k-2,h-2:?".---.":FOR j=1TO 3:LOCATE,h-2:?"|   |":NEXT:LOCATE,h-2:?"'---'":d=x-h:e=y-k:m=ABS(e/d):LOCATE k-SGN(e)*(m>=.5),h-SGN(d)*(m<=2):?"0":NEXT
WEND
LOOP

Il clic sinistro posiziona gli occhi. Se il posizionamento degli occhi comporterebbe una parte degli occhi fuori limite, il programma "si blocca" fino a quando non viene effettuato un posizionamento valido.

La parte più difficile è posizionare gli alunni. Il più delle volte, le coordinate della pupilla sono solo il centro dell'occhio più (segno (Δx), segno (Δy)), tranne che negli ottanti 1 e 5, la coordinata y equivale al centro y, e negli ottanti 3 e 7, la coordinata x equivale al centro x. I confini degli ottanti possono essere calcolati usando la pendenza mdella linea dal centro dell'occhio alle coordinate del mouse. Convenientemente, dividendo per zero quando si calcola la pendenza si ottiene l'infinito in virgola mobile (+/-) anziché un errore.

Occhi visivi in ​​QB64

Ungolfed

' Loop forever
DO
    ' Do stuff if there is new mouse data (movement or click)
    IF _MOUSEINPUT THEN
        ' Store the mouse coords rounded to the nearest integer
        mouse_x = CINT(_MOUSEX)
        mouse_y = CINT(_MOUSEY)
        ' If left mouse button was clicked, change location of eyes
        IF _MOUSEBUTTON(1) THEN
            ' Store center coordinates of left eye
            left_center_x = mouse_x - 3
            center_y = mouse_y
        END IF
        ' If eye location is in bounds, print the eyes and pupils
        x_in_bounds = left_center_x > 2 AND left_center_x < 73
        y_in_bounds = center_y > 2 AND center_y < 22
        IF x_in_bounds AND y_in_bounds THEN
            CLS
            FOR eye = 1 TO 2
                ' eye = 1 for left eye, eye = 2 for right eye
                IF eye = 1 THEN center_x = left_center_x
                IF eye = 2 THEN center_x = left_center_x + 6
                ' Print eye borders
                LOCATE center_y - 2, center_x - 2
                PRINT ".---."
                FOR row = 1 TO 3
                    LOCATE , center_x - 2
                    PRINT "|   |"
                NEXT row
                LOCATE , center_x - 2
                PRINT "'---'"
                ' Calculate coordinates of pupil
                xdiff = mouse_x - center_x
                ydiff = mouse_y - center_y
                slope = ydiff / xdiff
                ' For most cases, adding the sign of the diff to the center
                ' coordinate is sufficient
                pupil_x = center_x + SGN(xdiff)
                pupil_y = center_y + SGN(ydiff)
                ' But in octants 3 and 7, the x-coordinate is centered
                IF ABS(slope) > 2 THEN pupil_x = center_x
                ' And in octants 1 and 5, the y-coordinate is centered
                IF ABS(slope) < 0.5 THEN pupil_y = center_y
                LOCATE pupil_y, pupil_x
                PRINT "0"
            NEXT eye
        END IF   ' in bounds
    END IF   ' mouse data
LOOP   ' forever

Sono passati un decennio o due da quando ho usato il QB, ma non potevi usarlo al ?0posto di ?"0"? Questo suggerisce è possibile utilizzare un'espressione numerica così come stringhe.
Joey,

@Joey Hmm. Stampa di come un numero stampa anche uno spazio prima e dopo di esso ... ma vieni a pensarci bene, scommetto ho potuto stampare gli alunni prima e poi che non sarebbe un problema. Tranne allora dovrei stampare i bordi sinistro e destro separatamente anziché come "| |". Quindi probabilmente non salverebbe nulla. "0"è solo 2 byte più lungo.
DLosc,

7

6502 codice macchina ( mouse C64 + 1351 ), 630 byte

00 C0 20 44 E5 A9 FF 85 5E A2 3F A9 00 8D 10 D0 8D 1B D0 9D C0 02 CA 10 FA A0
0A A2 1E B9 5A C2 9D C0 02 CA CA CA 88 10 F4 A9 0B 8D F8 07 A9 18 8D 00 D0 A9
32 8D 01 D0 A9 0D 8D 27 D0 A9 01 8D 15 D0 78 A9 60 8D 14 03 A9 C1 8D 15 03 58
D0 FE 84 FD 85 FE A8 38 E5 FD 29 7F C9 40 B0 04 4A F0 0A 60 09 C0 C9 FF F0 03
38 6A 60 A9 00 60 20 44 E5 A5 69 38 E9 05 B0 02 A9 00 C9 1E 90 02 A9 1D 85 FD
18 69 02 85 5C 69 06 85 5D A5 6A 38 E9 02 B0 02 A9 00 C9 15 90 02 A9 14 85 FE
18 69 02 85 5E A9 65 8D BB C0 A9 C2 8D BC C0 A9 04 85 02 A6 FE 20 F0 E9 A9 02
85 5F A4 FD A2 00 BD FF FF 91 D1 C8 E8 E0 05 D0 F5 C8 C6 5F D0 EE E6 FE A9 6A
8D BB C0 A9 C2 8D BC C0 C6 02 30 0E D0 D1 A9 6F 8D BB C0 A9 C2 8D BC C0 D0 C5
60 C5 69 90 0A F0 5D E5 69 85 5F A9 C6 D0 09 49 FF 38 65 69 85 5F A9 E6 8D 1C
C1 8D 23 C1 8D 3E C1 A5 6A C5 5E 90 21 F0 12 E5 5E C5 5F 90 12 4A C5 5F B0 02
C6 FD A6 5E E8 D0 33 C6 FD A6 5E D0 2D 0A C5 5F B0 EE 90 F3 49 FF 38 65 5E C5
5F 90 0C 4A C5 5F B0 02 C6 FD A6 5E CA D0 11 0A C5 5F B0 F4 90 D7 A5 6A C5 5E
90 EE F0 D1 B0 C8 20 F0 E9 A9 30 A4 FD 91 D1 60 AD 19 D4 A4 FB 20 4E C0 84 FB
85 5F 18 6D 00 D0 8D 00 D0 6A 45 5F 10 08 A9 01 4D 10 D0 8D 10 D0 AD 10 D0 4A
AD 00 D0 B0 08 C9 18 B0 16 A9 18 D0 0F C9 58 90 0E 24 5F 10 05 CE 10 D0 B0 EF
A9 57 8D 00 D0 AD 1A D4 A4 FC 20 4E C0 84 FC 49 FF 85 5F 38 6D 01 D0 8D 01 D0
6A 45 5F 10 06 24 5F 10 11 30 07 AD 01 D0 C9 32 B0 04 A9 32 D0 06 C9 FA 90 05
A9 F9 8D 01 D0 A5 69 85 6B A5 6A 85 6C AD 10 D0 4A AD 00 D0 6A 38 E9 0C 4A 4A
85 69 AD 01 D0 38 E9 32 4A 4A 4A 85 6A AD 01 DC 29 10 C5 6D F0 0B 85 6D 29 10
D0 05 20 6C C0 30 10 A5 5E 30 46 A5 69 C5 6B D0 06 A5 6A C5 6C F0 3A A6 5E CA
86 5F A9 03 85 02 A6 5F 20 F0 E9 A9 20 A2 03 A4 5C 88 91 D1 C8 CA D0 FA A2 03
A4 5D 88 91 D1 C8 CA D0 FA E6 5F C6 02 D0 DD A5 5C 85 FD 20 E9 C0 A5 5D 85 FD
20 E9 C0 4C 31 EA 80 C0 E0 F0 F8 FC F0 D8 18 0C 0C 2E 2D 2D 2D 2E 5D 20 20 20
5D 27 2D 2D 2D 27

In azione:

dimostrazione

Nessuna demo online , scusate, perché c'è un emulatore AFAIK no js C64 che supporta un mouse. Se vuoi provarlo tu stesso, prendi VICE , scarica l'eseguibile binario e avvialo nell'emulatore C64:

x64sc -autoload xeyes.prg -controlport1device 3 -keybuf 'sys49152\n'

Per afferrare / decomprimere l'input del mouse nell'emulatore in esecuzione, utilizzare ctrl+msu Unix / Linux e ctrl+qsu Windows.


Sì, questo doveva essere fatto;) Dopo tutto, non è un Commodoro del mouse originale per il C64, ma naturalmente, il sistema operativo integrato non lo supporta, quindi ho bisogno di un driver del mouse, che già ha avuto 230 byte ( incluso uno sprite hardware a forma di cursore del mouse e limiti che controllano il codice per l'area dello schermo, ma senza tradurre le coordinate del puntatore in coordinate dello schermo del testo).

  • Per proteggere alcuni byte, ho deciso di far funzionare l'IRQ del sistema operativo e di utilizzare alcune routine Kernal ove possibile (svuotare lo schermo e ottenere un puntatore di base per una riga dello schermo di testo).
  • Il codice mette anche tutte le variabili in zeropage, che salva alcuni byte in più, ma distrugge i valori in virgola mobile usati da BASIC. Dato che il programma non esce mai, non importa.
  • Il terzo trucco per ridurre le dimensioni è l'auto-modifica: c'è solo il codice per verificare se la pupilla è posizionata sul lato sinistro dell'occhio. Lo stesso codice viene riutilizzato dopo aver corretto alcune istruzioni di decremento per incrementare le istruzioni per il lato destro.

Se sei interessato, puoi leggere il codice come sorgente dell'assembly qui :)


Mi sembra di essere l'unico a provare a competere qui di volta in volta con il codice C64. Ho adorato questa sfida, perché un mouse sul C64 è qualcosa di "esotico"! Se qualcuno si chiede perché ultimamente sono meno attivo, questo è il motivo: csdb.dk/release/?id=161435 - finalmente cercando di fare un gioco completo per il C64 :)
Felix Palmen,

1
Solo per divertimento, ho realizzato una "versione deluxe": csdb.dk/release/?id=161762
Felix Palmen,

7

Pulito , 1014 904 892 884 840 814 782 772 769 byte

-6 byte se gli occhi non hanno bisogno di agganciarsi a una griglia

Non è stato facile Le UI nei linguaggi funzionali raramente lo sono.

import StdEnv,StdIO,osfont,ostoolbox
a=toReal
c=1>0
Start w#(d,w)=openId w
#(t,w)=worldGetToolbox w
#(_,f,_)=osSelectfont("Courier",[],9)t
=let$p#(s,p)=accPIO getProcessWindowSize p
    =snd(openWindow NilLS(Window""NilLS[WindowId d,WindowMouse(\_=c)Able(noLS1@),WindowViewSize s,WindowPen[PenFont f]])p);@(MouseUp p _)s={s&ls=p};@(MouseMove p _)s=:{ls={x,y},io}={s&io=setWindowLook d c(c,(\_{newFrame}i#(w,i)=getFontCharWidth f' '(unfill newFrame i)
    =let g v=let m=y-p.y;n=p.x-x-v*w;s=abs(a m/a n);k|abs m<9&&abs n<w=5|s<0.4142=if(n>0)6 4=sign if(s>2.4143)0n+if(m>0)2 8in[".---.":["|"+++{if(k==e)'0'' '\\e<-[j..j+2]}+++"|"\\j<-[1,4,7]]]++["'---'"]in foldr(\e=drawAt{x=(x/w-5)*w,y=(y/9+e-2)*9}([a+++" "+++b\\a<-g -3&b<-g 3]!!e))i[0..4]))io};@_ s=s
in startIO SDI zero$[]w

Assicurati di utilizzare iTasks Clean, di aver Courierinstallato il font e StdLibPRIMA di avere qualsiasi sottocartella ObjectIOnel percorso di ricerca del modulo.

Compila con (esempio, potrebbe essere diverso): clm -IL StdLib -IL ObjectIO -IL "ObjectIO/OS <YOUR_OS_HERE>" -IL Dynamics -IL Generics -IL Platform -nci <MODULE_NAME_HERE>

Se non hai mai eseguito Clean prima, aspetta che questo progetto impieghi 5+ minuti per essere compilato.

Ungolfed:

module main
import StdEnv,StdIO,osfont,ostoolbox
height=9
SlopeFor225 :== 0.4142

StartSize :== 8

Universe :== {corner1={x=0,y=0},corner2={x=1,y=1}}

Start :: *World -> *World
Start world = startConsole (openIds 1 world)

startConsole :: ([Id],*World) -> *World
startConsole ([windowID],world)
    # (toolbox,world) = worldGetToolbox world
    # (_,font,toolbox) = osSelectfont ("Consolas",[],height) toolbox
    = startIO SDI {x=0,y=0} (initialise font) [ProcessClose closeProcess] world
where
    initialise font pst
        # (size,pst) = accPIO getProcessWindowSize pst
        # (error,pst) = openWindow undef (window font size) pst
        | error<>NoError = abort "bad window"
        = pst

    window font size
        = Window "Xeyes" NilLS
            [WindowId           windowID
            ,WindowClose        (noLS closeProcess)
            ,WindowMouse        mouseFilter Able (noLS1 track)
            ,WindowViewDomain   Universe//(getViewDomain StartSize)
            ,WindowViewSize     size
            ,WindowPen          [PenFont font]
            ]

    track (MouseDown pos _ _) state=:{ls=point=:{x,y},io}
        # point = pos
        // move to mouse position
        = {state & ls=pos}

    track (MouseMove pos _) state=:{ls=point=:{x,y},io}
        //redraw to point at mouse
        # io = setWindowLook windowID True (True, look) io
        = {state & ls=point,io=io}
    where
        look _ {newFrame} picture
            # picture = unfill newFrame picture
            # (width,picture) = getPenFontCharWidth' 'picture
            = let
                determineSector u
                    # yDist = (y - pos.y)
                    # xDist = (pos.x - u)
                    # slope = abs(toReal yDist / toReal xDist)
                    | (abs yDist) < height && (abs xDist) < width = '9'
                    | slope < SlopeFor225 = if(xDist > 0) '1' '5'
                    | yDist > 0
                        | slope > (2.0+SlopeFor225) = '7'
                        = if(xDist > 0) '8' '6'
                    | slope > (2.0+SlopeFor225) = '3'
                    = if(xDist > 0) '2' '4'
                getEye u=map(map(\e|isDigit e=if(e==determineSector(x+u*width))'0'' '=e))[['.---.'],['|678|'],['|591|'],['|432|'],['\'---\'']]
            in foldr(\i pic=drawAt{x=(x/width-5)*width,y=(y/height+i-2)*height}([toString(a++[' ':b])\\a<-getEye -3&b<-getEye 3]!!i)pic)picture[0..4]

    mouseFilter (MouseDown _ _ _) = True
    mouseFilter (MouseMove _ _) = True
    mouseFilter _ = False

Come puoi vedere dalla versione non golfata, la maggior parte del codice sta semplicemente impostando la combinazione di "carattere a spaziatura fissa" con "rispondi al mouse". E anche se Couriernon lo rende facile da dire, in realtà sta disegnando la .s e la 's. Lo scambio con qualcosa di simile lo Consolasrende più chiaro.

inserisci qui la descrizione dell'immagine


1
Non conosco affatto Clean, quindi forse sto dicendo qualcosa di strano, ma è possibile passare (abs m)<9&&(abs n)<w='9'a (abs m)<9&(abs n)<w='9'? Inoltre, suggerisco di aggiungere uno screen-to-gif invece di screenshot.
Kevin Cruijssen il

1
@KevinCruijssen Questo non avrebbe funzionato per diversi motivi, ma ho salvato 4 byte lasciando cadere le parentesi nella stessa espressione, quindi grazie! Ho anche aggiunto una schermata gif!
Οuroso

1

Rubino, 335 + 13 = 348 byte

+13 byte per il -rio/consoleflag da abilitare IO#getch.

Contiene caratteri ESC ( 0x1b) letterali , mostrati come di seguito. segue il dump xxd.

Attenzione: questo non ripulisce dopo se stesso all'uscita. Vedi la nota sotto discarica xxd di seguito.

include Math
$><<"␛[?1003h"
s=""
(s<<STDIN.getch
($><<"␛[2J"
x,y=$3.ord-32,$4.ord-32
u,v=x,y if$2
u&&[x-u+3,x-u-3].map{|a|b=y-v
e=4*asin(b/sqrt(a**2+b**2))/PI
printf"␛[%d;%dH.---.@|567|@|480|@|321|@'---'".gsub(/(#{(a<0?4-e:b<0?8+e:e).round%8rescue 8})|([0-8])|@/){$1?0:$2?" ":"␛[5D␛[1B"},v-2,x-a-2}
s="")if /M(C|(#))(.)(.)$/=~s)while 1

Ungolfed

Questo è un golf piuttosto ingenuo della mia implementazione Ruby originale .

include Math       # Saves a few bytes for asin, sqrt, and PI
$> << "␛[?1003h"   # Print xterm control sequence to start mouse tracking
s = ""             # Variable to hold input-so-far
(
  s << STDIN.getch   # Read a character from STDIN
  (
    $> << "␛[2J"                     # Clear terminal
    x, y = $3.ord - 32, $4.ord - 32  # Get cursor x and y from last match
    u, v = x, y if $2                # Update eye position if last matched control sequence was click ("#")

    u && [x-u+3, x-u-3].map {|a|     # For each eye's x-position
      b = y - v                                       # Eye's y position
      e = 4 * asin(b / sqrt(a**2 + b**2)) / PI        # Convert cursor (x,y) to angle w/ x-axis as 1/8 turns

      printf "␛[%d;%dH.---.@|567|@|480|@|321|@'---'"  # Control code to move text cursor, followed by template for eye
        .gsub(
          /(#{
            (a < 0 ? 4-e : b < 0 ? 8+e : e).round % 8 rescue 8  # Octant number 0-7 or 8 for center
          })|([0-8])|@/
        ){ $1 ? 0 : $2 ? " " : "␛[5D␛[1B" },            # Replace octant number with pupil; other digits with space; and @s with code to move cursor left and down for next line of eye
        v-2, x-a-2                                      # (y, x) position of top left corner of eye
    }
    s = ""                           # Clear input-so-far
  ) if /M(C|(#))(.)(.)$/ =~ s      # ...when input-so-far matches a movement ("C") or click ("#") control sequence
) while 1                        # ...forever

discarica xxd

Questo programma attiva il tracciamento del mouse con la sequenza di controllo xterm \e[?1003hma non lo disattiva all'uscita. Per disattivarlo, utilizzare la sequenza di controllo \e[?1003l, ad esempio:

ruby -rio/console visual_eyes.rb; printf '\e[1003l'

Poiché il programma mangia tutti gli input, è difficile uscire. Se vuoi essere in grado di uscire premendo Ctrl + C, aggiungi la seguente riga di seguito (s<<STDIN.getch:

exit 130 if s.end_with?(?\003)

Senza ulteriori indugi:

00000000: 696e 636c 7564 6520 4d61 7468 0a24 3e3c  include Math.$><
00000010: 3c22 1b5b 3f31 3030 3368 220a 733d 2222  <".[?1003h".s=""
00000020: 0a28 733c 3c53 5444 494e 2e67 6574 6368  .(s<<STDIN.getch
00000030: 0a28 243e 3c3c 221b 5b32 4a22 0a78 2c79  .($><<".[2J".x,y
00000040: 3d24 332e 6f72 642d 3332 2c24 342e 6f72  =$3.ord-32,$4.or
00000050: 642d 3332 0a75 2c76 3d78 2c79 2069 6624  d-32.u,v=x,y if$
00000060: 320a 7526 265b 782d 752b 332c 782d 752d  2.u&&[x-u+3,x-u-
00000070: 335d 2e6d 6170 7b7c 617c 623d 792d 760a  3].map{|a|b=y-v.
00000080: 653d 342a 6173 696e 2862 2f73 7172 7428  e=4*asin(b/sqrt(
00000090: 612a 2a32 2b62 2a2a 3229 292f 5049 0a70  a**2+b**2))/PI.p
000000a0: 7269 6e74 6622 1b5b 2564 3b25 6448 2e2d  rintf".[%d;%dH.-
000000b0: 2d2d 2e40 7c35 3637 7c40 7c34 3830 7c40  --.@|567|@|480|@
000000c0: 7c33 3231 7c40 272d 2d2d 2722 2e67 7375  |321|@'---'".gsu
000000d0: 6228 2f28 237b 2861 3c30 3f34 2d65 3a62  b(/(#{(a<0?4-e:b
000000e0: 3c30 3f38 2b65 3a65 292e 726f 756e 6425  <0?8+e:e).round%
000000f0: 3872 6573 6375 6520 387d 297c 285b 302d  8rescue 8})|([0-
00000100: 385d 297c 402f 297b 2431 3f30 3a24 323f  8])|@/){$1?0:$2?
00000110: 2220 223a 221b 5b35 441b 5b31 4222 7d2c  " ":".[5D.[1B"},
00000120: 762d 322c 782d 612d 327d 0a73 3d22 2229  v-2,x-a-2}.s="")
00000130: 6966 202f 4d28 437c 2823 2929 282e 2928  if /M(C|(#))(.)(
00000140: 2e29 242f 3d7e 7329 7768 696c 6520 31    .)$/=~s)while 1
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.