Visualisieren Sie visuelle Augen


42

Sie können sich vielleicht an Xeyes erinnern, ein Demo-Programm, das mit dem X-Window-System geliefert wurde (und meines Wissens immer noch mitgeliefert wird). Sein Zweck war es, ein Paar Augen zu zeichnen, die Ihrem Mauszeiger folgten:

Xeyes

Ihre Herausforderung ist es, Xeyes mit ASCII-Kunst neu zu erstellen. Schreiben Sie ein Programm oder eine Funktion, die zwei (unten angegebene) ASCII-Kunstaugen zeichnet, wo immer der Benutzer klickt, und bewegen Sie dann die Pupillen, um in Richtung des Cursors zu zeigen.

Terminal Eyes GIF

Das obige GIF ist eine Aufzeichnung dieser Ruby-Implementierung ohne Golf , die mit jeder neueren Version von Ruby ausgeführt werden kann. Sie können es auch als Referenz für Xterm-Steuersequenzen verwenden.

Spezifikationen

Das ist , also gewinnt die Lösung mit den wenigsten Bytes.

Dies ist eine Herausforderung, so dass Ihr Programm ziehen muß ASCII - Zeichen mit spezifisch, die Zeichen -, ., |, ', 0, Raum und Newline. 1 2

Dies ist eine Herausforderung, daher muss Ihr Programm Eingaben akzeptieren und die Ausgabe in Echtzeit zeichnen. 3

Bevor Ihr Programm Eingaben akzeptiert, sollte es eine leere Zeichenfläche von mindestens 20 Zeilen und 20 Spalten initialisieren. Es sollte nichts gezeichnet werden, bis der Benutzer auf die Zeichenfläche klickt.

Jedes Mal , wenn der Benutzer klickt auf 4 auf der Leinwand, sollte das Programm löscht alle vorherige Ausgabe und dann diese ASCII Augen auf der Leinwand zeichnen, zentrierte auf dem Charakter am nächsten an der Position des Mauszeigers. 5 6 (Stellt den Mauszeiger dar und sollte nicht gezeichnet werden.)

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

Beachten Sie, wie die Pupillen auf den Cursor "zeigen".

Jedes Mal, wenn sich der Mauszeiger auf der Zeichenfläche bewegt, sollte das Programm die Pupillen neu zeichnen, so dass sie weiterhin auf den Cursor zeigen, 7 zB:




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

Schüler zeigen

Angenommen, wir haben die Positionen der inneren neun Zeichen jedes Auges folgendermaßen aufgelistet:

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

Der Schüler wird an einem der Orte gezogen 1- 9. Stellen Sie sich vor, die Zeichen seien quadratisch und die Zeichenfläche ein kartesisches Gitter mit der Mitte des 9Zeichens bei (0, 0), der Mitte 1bei (1, 0) und so weiter. Wenn das Programm Eingaben erhält - ein Klick oder eine Bewegung -, sollte es die Eingabeposition auf die nächste Gitterkoordinate abbilden 𝑀. Wenn 𝑀 (0, 0) ist, sollte die Pupille bei (0, 0) gezeichnet werden, dh an der Stelle von 9oben. Ansonsten sollte wie unten beschrieben gezeichnet werden.

Stellen Sie sich eine kartesische Ebene vor, die über dem Gitter liegt und in Oktanten mit den Nummern 1 bis 8 unterteilt ist :

Wenn 𝑀 innerhalb von Oktant 1 liegt , sollte die Pupille an der Stelle von 1oben gezeichnet werden , dh bei (1, 0). Wenn 𝑀 in Oktant 2 ist , sollte es um 2- und so weiter gezeichnet werden . Zur Veranschaulichung zeigt das folgende Bild einen Teil des Rasters, der farblich gekennzeichnet ist, je nachdem, wo die Pupille gezeichnet werden soll, wenn sich der Mauszeiger an einer bestimmten Stelle befindet. Befindet sich der Cursor beispielsweise an einer der grünen Koordinaten (wobei zu beachten ist, dass die Gitterkoordinaten in den Mittelpunkten der Quadrate und nicht in ihren Ecken liegen), sollte die Pupille an gezeichnet werden 4.

Die Pupillen der beiden Augen bewegen sich unabhängig voneinander. Wiederholen Sie den Vorgang für jedes Auge mit 𝑀 relativ zur Mitte des Auges.

Anmerkungen

  1. Dies ist keine Herausforderung für die . Die Ausgabe muss ein Zeichenraster sein. Sie können natürlich Grafikroutinen verwenden, um ein Zeichenraster zu zeichnen.

  2. Leerzeichen können gezeichnet werden (oder eher nicht gezeichnet werden), dies ist jedoch zweckmäßig. Eine leere Stelle im Raster entspricht einem Leerzeichen und wird als gleichwertig betrachtet.

  3. "Echtzeit" ist hier definiert als weniger als 200 ms zwischen dem Eingang und dem entsprechenden Ausgang, der gezogen wird.

  4. Es liegt in Ihrem Ermessen, welche Maustasten für die Eingabe verwendet werden und ob ein Drücken oder Loslassen einen "Klick" darstellt.

  5. Die Leinwand muss gelöscht werden, oder das visuelle Äquivalent muss erreicht werden. Bei einer terminalbasierten Lösung wird beispielsweise das Drucken einer neuen Zeichenfläche unter der vorherigen Zeichenfläche nicht als gleichwertig angesehen.

  6. Wenn der Benutzer in der Nähe des Randes der Zeichenfläche klickt, sodass einige der Augenzeichen über den Rand hinaus gezeichnet werden, ist das Verhalten undefiniert. Bei nachfolgenden Klicks muss das Programm jedoch normal weiterlaufen.

  7. Wenn der Mauszeiger die "Zeichenfläche" verlässt, ist das Verhalten undefiniert, das Programm muss jedoch normal weiterlaufen, wenn der Mauszeiger die Zeichenfläche erneut betritt.

  8. Ein Textcursor wird möglicherweise auf der Zeichenfläche angezeigt, solange er die Ausgabe nicht verdeckt.

Standardlücken sind verboten.


2
@ Οurous Da es in diesem Fall darauf ankommt, wie viele Minuten "ein paar" sind, wie viel Arbeitsspeicher das System hat, und dies dazu führen könnte, dass "diese Lösung davon ausgeht, dass die Umgebung über 512 GB RAM verfügt", sage ich Folgendes Es muss möglicherweise auf unbestimmte Zeit ausgeführt werden.
Jordanien

1
@ TaylorScott Nein. Siehe Anmerkung 6 (es sei denn, ich habe Ihre Frage falsch verstanden).
Jordanien

1
@ Οurous Ja und nein. Wenn Ihre Zielumgebung normalerweise eine ist, in der die Standardschriftart Monospace ist (z. B. ein Terminal-Emulator oder ein Code-Editor), ist dies in Ordnung. Wenn die Verwendung einer Monospace-Schriftart in dieser Umgebung normalerweise eine zusätzliche Konfiguration erfordert (wie bei einer browserbasierten JS-Lösung), muss diese Konfiguration Teil Ihrer Byteanzahl sein (z . B. <pre>oder font-family:monospace).
Jordanien

9
+1 für großen Titel (oder schlechten Titel, je nachdem, wie Sie es nehmen)
FantaC

1
@ Οurous Nein, solange es nicht unerwartet beendet wird.
Jordanien

Antworten:


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> |
|   | |   |
'---' '---'


Beide X||Ykönnen gespielt werden X|Y, um 2 Bytes zu sparen.
Kevin Cruijssen

Funktioniert nicht so gut, wenn Sie in der Nähe des Behälterbodens klicken und nach unten scrollen müssen. i.stack.imgur.com/s44KU.png Ich bin mir nicht sicher, ob dies spezifisch für den Snippet-Wrapper ist, war aber erwähnenswert.
Draco18s

2
@ Οurous Es ist ziemlich zweideutig formuliert: "zentriert an der Stelle des Mauszeigers." Bedeutet "Ort" "Gitterzelle" oder kann es "Pixel" bedeuten? Ich bin damit einverstanden, dass die Absicht wahrscheinlich die erstere war, aber der Wortlaut scheint die letztere sicherlich zuzulassen.
DLosc

@ KevinCruijssen Leider funktioniert das nicht - |hat Vorrang vor dem ternären Ausdruck.
darrylyeo

@darrylyeo Nein, nicht wahr? : S Diese JavaScript-Operator-Rangfolge-Tabelle zeigt |und ||auf etwas der gleichen Ebene, und beide oben ?:.. Beide X||Y?w*r(cos(a)):0und X||Y?h*r(sin(a)):0sind derzeit in der Form boolean_condition?A:B. Wenn Sie also darauf umsteigen X||Y, X|Ywird ein bisschen ODER ausgeführt und dann wieder als boolesche Bedingung interpretiert. ( (X||Y)?A:BVs (X|Y)?A:B, nicht X|(Y?A:B)). Auch ich sehe keinen Unterschied , wenn ich „Copy - Snippet zu beantworten“ und ändern Sie das ||zu |. Soweit ich das
beurteilen

12

Excel VBA, 630 Bytes

Deklarierte Arbeitsblatt-Subroutine, die bei einem Mausklick ausgeführt wird, bei dem keine Eingabe erfolgt und ein Augenpaar erzeugt wird, das dem Cursor folgt. Dies hängt von der enthaltenen Hilfsfunktion und der Typdeklaration ab, die in einem normalen Modul abgelegt werden muss.

Diese Version ist so kalibriert, dass sie mit dem Standardzoom von 100% ausgeführt wird. Bricht ab, wenn Sie versuchen, einen Bildlauf durchzuführen.

Hinweis: VBA vervollständigt nicht abgeschlossene Zeichenfolgen automatisch in der neuen Zeile. Daher gibt es im folgenden Code drei Fälle, in denen ein Terminal "nur zu Hervorhebungszwecken eingefügt wurde - diese tragen nicht zum bytecount bei

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

Helferfunktion und Typdeklaration

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

Ungolfed und Kommentiert

Diese Version ist für eine Zoomstufe von 400% kalibriert.

''  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

Helferfunktion und Typdeklaration

''  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

Ausgabe

Gif

Moving_Eyes

Bild mit höherer Auflösung

Static_Eyes


Dies stimmt in einigen Punkten nicht mit der Spezifikation überein. 1. „Zeichenraster“ bezeichnet einzelne Zeichen mit unterschiedlichen Positionen. Wenn der Mauszeiger aktiviert ist, beispielsweise das 'Zeichen ganz rechts, unterscheidet sich die Ausgabe von dem 'Zeichen ganz links . 2. Die Position der Augen ist nicht festgelegt. Ein Mausklick sollte dazu führen, dass sie sich an die angeklickte Position bewegen. Ich bin bei der Eingabemethode flexibel (ich würde beispielsweise einen virtuellen Mauszeiger akzeptieren, der mit den Pfeiltasten gesteuert wird), aber es gibt zwei unterschiedliche Eingabeereignisse mit unterschiedlichem Verhalten: Mausbewegung und Mausklick.
Jordanien

@Jordan Ich bin mir nicht ganz sicher, was Sie unter Punkt 1 verstehen. Könnten Sie das bitte näher erläutern? Was Punkt 2 betrifft, sind die Augen nicht statisch. Wenn Sie auf eine Zelle auf dem Blatt klicken, in dem sich die Unterroutine befindet, wird das Worksheet_SelectionChangeEreignis ausgelöst und der Anrufbereich ( Targetoder Tin diesem Fall) überschritten, wodurch die Augen und a *im Anruf neu gezeichnet werden Zelle
Taylor Scott

1
@Jordan - Ich glaube, ich habe alle Ihre Bedenken ausgeräumt. Dabei musste ich meine Lösung jedoch auf 64-Bit-Excel beschränken und arbeite derzeit an einer ungolften und kommentierten Version
Taylor Scott

1
@Jordan Das liegt daran, dass die Windows-API-Deklarationen für 32 und 64, aber VBA unterschiedlich sind, ebenso wie die Besonderheiten der Verkettung und Potenzierung, bei denen 32-Bit fast immer kürzer ist - und ich derzeit keinen Zugriff auf eine 32-Bit-Version von Office habe: P
Taylor Scott

3
Vielleicht die beiden Screenshots zu einem Screen-to-Gif ändern ?
Kevin Cruijssen

7

QBasic ( QB64 ), 361 305 Bytes

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

Linksklick platziert die Augen. Wenn die Platzierung der Augen dazu führen würde, dass ein Teil der Augen außerhalb der Grenzen liegt, "friert" das Programm ein, bis eine gültige Platzierung vorgenommen wurde.

Der schwierigste Teil ist das Platzieren der Schüler. Meistens sind die Koordinaten der Pupille nur der Mittelpunkt des Auges plus (Vorzeichen (Δx), Vorzeichen (Δy)), außer dass in den Oktanten 1 und 5 die y-Koordinate gleich dem y-Zentrum ist und in den Oktanten In 3 und 7 ist die x-Koordinate gleich der x-Mitte. Oktantengrenzen können anhand der Neigung mder Linie vom Mittelpunkt des Auges zu den Mauskoordinaten berechnet werden . Wenn Sie bei der Berechnung der Steigung durch Null dividieren, erhalten Sie günstigerweise eine Gleitkomma-Unendlichkeit (+/-) und keinen Fehler.

Visuelle Augen 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

Es ist ein oder zwei Jahrzehnte her, dass ich QB verwendet habe, aber könntest du nicht ?0stattdessen verwenden ?"0"? Dies legt nahe, dass Sie sowohl einen numerischen Ausdruck als auch Zeichenfolgen verwenden können.
Joey

@ Joey Hmm. Wenn Sie es als Zahl drucken, wird auch ein Leerzeichen davor und danach gedruckt. Aber wenn Sie sich das überlegen, könnte ich die Schüler zuerst drucken, und dann wäre das kein Problem. Ansonsten müsste ich den linken und den rechten Rand separat statt als drucken "| |". Also würde es wahrscheinlich nichts retten. "0"ist nur 2 Bytes länger.
DLosc

7

6502 Maschinencode (C64 + 1351 Maus ), 630 Bytes

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 Aktion:

Demo

Keine Online-Demo , sorry, da es AFAIK no js C64 Emulator gibt, der eine Maus unterstützt. Wenn Sie es selbst ausprobieren möchten, greifen Sie zu VICE , laden Sie die ausführbare Binärdatei herunter und starten Sie sie im C64-Emulator:

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

Unter ctrl+mUnix / Linux und ctrl+qunter Windows können Sie die Mauseingabe im laufenden Emulator abrufen / entfernen .


Ja, das musste gemacht werden;) Immerhin gibt es eine originale Commodore-Maus für den C64, aber das eingebaute Betriebssystem unterstützt sie natürlich nicht, so dass ich zuerst einen Maustreiber brauchte, der bereits 230 Bytes benötigte ( einschließlich eines Hardware-Sprites in Form eines Mauszeigers, der den Code für den Bildschirmbereich überprüft, ohne jedoch die Zeigerkoordinaten in Text-Bildschirmkoordinaten zu übersetzen).

  • Um einige Bytes zu sparen, habe ich mich entschlossen, den IRQ des Betriebssystems am Laufen zu halten und nach Möglichkeit ein paar Kernal-Routinen zu verwenden (den Bildschirm zu leeren und einen Basiszeiger für eine Textbildschirmzeile zu erhalten).
  • Der Code fügt auch alle Variablen in die Nullseite ein, wodurch zwar mehr Bytes gespart werden, jedoch die von BASIC verwendeten Gleitkommawerte zerstört werden. Da das Programm sowieso nie beendet wird, spielt dies keine Rolle.
  • Der dritte Trick, um die Größe zu reduzieren, ist die Selbstmodifikation: Es muss nur geprüft werden, ob sich die Pupille auf der linken Seite des Auges befindet. Derselbe Code wird nach dem Patchen einiger Dekrementierungsanweisungen erneut verwendet, um die Anweisungen für die rechte Seite zu erhöhen.

Wenn Sie interessiert sind, können Sie den Code als Assembly-Quelle hier lesen :)


Ich scheine der einzige zu sein, der hier von Zeit zu Zeit versucht, mit C64-Code zu konkurrieren. Liebte diese Herausforderung, denn eine Maus auf dem C64 ist etwas "Exotisches"! Wenn jemand fragt mich, warum bin ich weniger in letzter Zeit aktiv, das ist der Grund: csdb.dk/release/?id=161435 - endlich ein voll funktionsfähiges Spiel für den C64 zu tun versuchen :)
Felix Palmen

1
Nur zum Spaß habe ich eine "Deluxe-Version" erstellt: csdb.dk/release/?id=161762
Felix Palmen

7

Sauber , 1014 904 892 884 840 814 782 772 769 Bytes

-6 Byte, wenn die Augen nicht an einem Raster ausgerichtet werden müssen

Das war nicht einfach. Benutzeroberflächen in funktionalen Sprachen sind selten.

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

Stellen Sie sicher, dass Sie iTasks Clean verwenden, die CourierSchriftart installiert haben und StdLibVOR allen Unterordnern ObjectIOim Modul-Suchpfad.

Kompilieren mit (Beispiel kann abweichen): clm -IL StdLib -IL ObjectIO -IL "ObjectIO/OS <YOUR_OS_HERE>" -IL Dynamics -IL Generics -IL Platform -nci <MODULE_NAME_HERE>

Wenn Sie Clean noch nie zuvor ausgeführt haben, kann das Kompilieren dieses Projekts mehr als 5 Minuten dauern.

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

Wie Sie aus der ungolften Version ersehen können, besteht der größte Teil des Codes lediglich aus der Kombination von "monospaced font" und "reply to the mouse". Und obwohl Courieres nicht leicht zu sagen ist, zeichnet es tatsächlich das .s und 's. Das Wechseln zu so etwas Consolasmacht es klarer.

Bildbeschreibung hier eingeben


1
Ich weiß nicht , Sauber überhaupt, so vielleicht etwas seltsam ich sage, aber ist es möglich , sich ändern (abs m)<9&&(abs n)<w='9'zu (abs m)<9&(abs n)<w='9'? Außerdem schlage ich vor, anstelle des Screenshots ein Screen-to-Gif hinzuzufügen .
Kevin Cruijssen

1
@KevinCruijssen Das würde aus mehreren Gründen nicht funktionieren, aber ich habe 4 Bytes gespart, indem ich die Klammern im selben Ausdruck abgelegt habe, also danke! Ich habe auch ein Bildschirm-GIF hinzugefügt!
Οurous

1

Ruby, 335 + 13 = 348 Bytes

+13 Bytes für das -rio/consolezu aktivierende Flag IO#getch.

Enthält die unten 0x1bgezeigten wörtlichen ESC ( ) -Zeichen . xxd dump folgt.

Achtung: Dies räumt beim Beenden nicht von selbst auf. Siehe Hinweis unter xxd dump unten.

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

Dies ist ein ziemlich naiver Golf meiner ursprünglichen Ruby-Implementierung .

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

xxd dump

Dieses Programm aktiviert die Mausverfolgung mit der xterm-Steuersequenz, schaltet \e[?1003hsie jedoch beim Beenden nicht aus. Verwenden Sie zum Ausschalten die Steuersequenz \e[?1003l, z.

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

Da das Programm alle Eingaben aufnimmt, ist das Beenden schwierig. Wenn Sie den Vorgang mit Strg + C beenden möchten, fügen Sie die folgende Zeile hinzu (s<<STDIN.getch:

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

Ohne weiteres:

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.