Visualiser les yeux visuels


42

Vous pouvez vous souvenir ou non de Xeyes, un programme de démonstration fourni avec (et, autant que je sache, toujours livré avec) le système de fenêtre X. Son but était de dessiner une paire d'yeux qui suivaient le curseur de votre souris:

Xeyes

Votre défi est de recréer Xeyes avec de l'art ASCII. Ecrivez un programme ou une fonction qui dessine deux yeux de dessin ASCII (spécifiés ci-dessous) lorsque l'utilisateur clique dessus, puis déplace leurs élèves vers la direction du curseur.

Yeux terminaux GIF

Le fichier GIF ci-dessus est un enregistrement de cette implémentation de Ruby sans jeu , qui peut être exécutée avec n’importe quelle version récente de Ruby. Vous pouvez également le trouver utile comme référence pour les séquences de contrôle Xterm.

Caractéristiques

C'est du , donc la solution avec le moins d'octets gagne.

Ceci est un défi, de sorte que votre programme doit dessiner en utilisant ASCII des caractères spécifiquement, les personnages -, ., |, ', 0, l' espace, et retour à la ligne. 1 2

Il s’agit d’un défi , votre programme doit donc accepter les entrées et en tirer les sorties en temps réel. 3

Avant que votre programme ne commence à accepter les entrées, il doit initialiser un canevas vierge d'au moins 20 lignes et 20 colonnes. Il ne faut rien dessiner tant que l'utilisateur n'a pas cliqué sur la toile.

Chaque fois que l'utilisateur clique sur 4 sur le canevas, le programme doit effacer toute sortie précédente, puis dessiner ces yeux ASCII sur le canevas, centrés sur le caractère le plus proche de l'emplacement du curseur de la souris. 5 6 (Ci-dessous, représente le curseur de la souris et ne doit pas être tracé.)

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

Notez comment les élèves "pointent" vers le curseur.

Chaque fois que le curseur de la souris se déplace sur le canevas, le programme doit redessiner les pupilles pour qu’elles continuent de pointer vers le curseur, 7 par exemple:




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

Élève pointant

Supposons que nous énumérions les positions des neuf caractères internes de chaque œil comme ceci:

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

L'élève sera tiré à l'un des emplacements 1- 9. Pour décider lequel, supposez que les caractères sont carrés et que le canevas est une grille cartésienne, avec le centre du 9caractère à (0, 0), le centre de 1à (1, 0), etc. Lorsque le programme reçoit une entrée (un clic ou un mouvement), il doit mapper l'emplacement de l'entrée sur la coordonnée de grille la plus proche. Si 𝑀 est égal à (0, 0), l'élève doit être tracé à (0, 0), c'est-à-dire l'emplacement de ce qui 9précède. Sinon, dessinez comme décrit ci-dessous.

Imaginons un plan cartésien superposé sur la grille et divisée en octants numérotée une - huit :

Si 𝑀 se situe dans l’octant 1 , la pupille doit être dessinée à l’emplacement 1ci-dessus, c’est-à-dire à (1, 0). Si 𝑀 est en octant 2, il devrait être tracé à 2- et ainsi de suite. Pour illustrer, l'image ci-dessous montre une partie de la grille codée par couleur en fonction du lieu où la pupille doit être dessinée lorsque le curseur de la souris se trouve à un emplacement particulier. Lorsque, par exemple, le curseur se trouve sur l’une des coordonnées vertes (en gardant à l’esprit que les coordonnées de la grille se situent au centre des carrés, et non à leurs angles), l’élève doit être tracé à 4.

Les pupilles des deux yeux se déplacent indépendamment. Pour chaque œil, répétez le processus avec par rapport au centre de cet œil.

Remarques

  1. Ce n'est pas un défi de . La sortie doit être une grille de caractères. Vous pouvez bien sûr utiliser des routines graphiques pour dessiner une grille de caractères.

  2. Les espaces peuvent être dessinés (ou plutôt non dessinés) mais cela convient. Une place vide dans la grille ressemble à un caractère d'espacement et sera considérée comme équivalente.

  3. "Temps réel" est défini ici comme moins de 200 ms entre l'entrée et la sortie correspondante en cours d'affichage.

  4. Il est à votre discrétion de savoir quel (s) bouton (s) de souris sont observés pour la saisie et si appuyer ou relâcher constitue un "clic".

  5. La toile doit être nettoyée ou l’équivalent visuel doit être atteint. Avec une solution basée sur un terminal, par exemple, imprimer une nouvelle toile en dessous de la toile précédente n'est pas considéré comme équivalent.

  6. Lorsque l'utilisateur clique près du bord de la toile de sorte que certains des caractères oculaires soient dessinés au-delà de son bord, le comportement n'est pas défini. Toutefois, le programme doit continuer à s'exécuter normalement lors de clics ultérieurs.

  7. Lorsque le curseur de la souris quitte le "canevas", le comportement n'est pas défini, mais le programme doit continuer à s'exécuter normalement lorsque le curseur entre à nouveau dans le canevas.

  8. Un curseur de texte peut apparaître sur la toile tant qu'il n'obscurcit pas la sortie.

Les failles standard sont interdites.


2
@ Οurous Depuis combien de minutes "quelques" dans ce cas dépendent de la quantité de mémoire dont dispose le système, et cela pourrait nous conduire à "cette solution suppose que l'environnement dispose de 512 Go de RAM", je vais dire que il doit potentiellement fonctionner indéfiniment.
Jordanie

1
@TaylorScott Nope. Voir la note n ° 6 (sauf si j'ai mal compris votre question).
Jordanie

1
@ Οurous Oui et non. Si votre environnement cible est généralement un environnement dans lequel la police par défaut est monospace (par exemple, un émulateur de terminal ou un éditeur de code), c'est très bien. Si l'utilisation d'une police monospace dans cet environnement requiert généralement une configuration supplémentaire (comme dans une solution JS basée sur un navigateur), cette configuration doit faire partie de votre nombre d'octets (par exemple <pre>ou font-family:monospace).
Jordanie

9
+1 pour un excellent titre (ou un mauvais titre, selon la façon dont vous le prenez)
FantaC

1
@ Οurous Nope, tant qu'il ne se termine pas de manière inattendue.
Jordanie

Réponses:


12

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

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


Les deux X||Ypeuvent être joués X|Ypour économiser 2 octets.
Kevin Cruijssen

Ne fonctionne pas si bien lorsque vous cliquez près du bas du conteneur et que vous devez faire défiler l'écran. i.stack.imgur.com/s44KU.png Je ne suis pas sûr que ce soit spécifique à l'encapsuleur d' extraits de code , mais cela mérite d'être mentionné.
Draco18s

2
@ Οurous Son libellé est plutôt ambigu: "centré à l'emplacement du curseur de la souris". Est-ce que "emplacement" signifie "cellule de grille" ou peut-il dire "pixel"? Je conviens que l’intention était probablement le premier, mais le libellé semble certainement permettre le dernier.
DLosc

@KevinCruijssen Malheureusement, cela ne fonctionne pas - |finit par prévaloir sur l'expression ternaire.
darrylyeo

@darrylyeo Non, ce n'est pas le cas? : S Cette JavaScript tableau priorité de l' opérateur montre |et ||sur un peu au même niveau, et au - dessus ?:.. Les deux X||Y?w*r(cos(a)):0et X||Y?h*r(sin(a)):0sont actuellement sous forme boolean_condition?A:B. Alors , quand vous changez X||Yde X|Ycela fera un sage bits ou puis interpréter comme une condition booléenne à nouveau. ( (X||Y)?A:Bvs (X|Y)?A:B, pas X|(Y?A:B)). De plus, je ne vois aucune différence lorsque j'utilise "Copier un extrait de code pour répondre" et que je change ||en |. Tout fonctionne toujours exactement de la même manière, pour autant que je
sache

12

Excel VBA, 630 octets

Sous-routine déclarée de la feuille de calcul s’appuyant sur un clic de souris, qui ne prend aucune entrée et produit une paire d’œil qui suivent le curseur. Cela dépend de la fonction d'assistance incluse et de la déclaration de type, qui doivent être placées dans un module normal.

Cette version est calibrée pour fonctionner au zoom par défaut de 100%. Pause si vous essayez de faire défiler.

Remarque: VBA complète automatiquement la chaîne non terminée à la nouvelle ligne. Par conséquent, dans le code ci-dessous, il existe trois instances dans lesquelles un terminal "a été inclus uniquement à des fins de mise en surbrillance - celles-ci ne contribuent pas au compte intermédiaire.

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

Fonction d'assistance et déclaration de type

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

Ungolfed and Commented

Cette version est calibrée pour fonctionner à un niveau de zoom de 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

Fonction d'assistance et déclaration de type

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

Sortie

Gif

Moving_Eyes

Image de plus haute résolution

Static_Eyes


Cela ne correspond pas à la spécification de plusieurs manières. 1. "Grille de caractères" signifie caractères uniques avec des positions distinctes. Par exemple, lorsque le curseur de la souris est activé, le 'caractère le plus à droite de la sortie sera différent de celui qui se trouve sur le 'caractère le plus à gauche . 2. La position des yeux n'est pas fixe. Un clic de souris devrait entraîner leur déplacement à la position cliquée. Je suis flexible sur la méthode de saisie (j'accepterais, par exemple, un curseur de souris virtuel contrôlé par les touches fléchées), mais il existe deux événements d'entrée distincts avec un comportement distinct: le mouvement et le clic de la souris.
Jordanie

@ Jordan Je ne suis pas tout à fait sûr de ce que vous entendez par le point 1, pourriez-vous s'il vous plaît élaborer? En ce qui concerne le point 2, les yeux ne sont pas statiques. Un clic sur une cellule de la feuille dans laquelle le sous-programme est placé déclenchera l’ Worksheet_SelectionChangeévénement et passera la plage d’appel ( Targetou Tdans ce cas) - ce qui redessine les yeux et un *appel. cellulaire
Taylor Scott

1
@ Jordan - Je crois avoir répondu à toutes vos préoccupations, même si, ce faisant, j'ai dû limiter ma solution à Excel 64 bits et je travaille actuellement sur une version non golfée et commentée
Taylor Scott

1
@ Jordan C'est parce que les déclarations d'API Windows pour 32 et 64, mais VBA, sont différentes, de même que les spécificités de la concaténation et de l'exponentiation, où 32 bits est presque toujours plus court - et je n'ai actuellement pas accès à une version 32 bits d'Office: P
Taylor Scott

3
Peut-être changer les deux captures d'écran en un écran à gif ?
Kevin Cruijssen le

7

QBasic ( QB64 ), 361 305 octets

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

Un clic gauche place les yeux. Si le placement des yeux entraîne une partie des yeux hors des limites, le programme "se fige" jusqu'à ce qu'un placement valide soit effectué.

La principale difficulté consiste à placer les élèves. La plupart du temps, les coordonnées de la pupille ne sont que le centre de l'œil plus (signe (Δx), signe (Δy)), sauf que dans les octants 1 et 5, la coordonnée y est égale au centre y, et en octants 3 et 7, la coordonnée x est égale au centre x. Les limites d'octant peuvent être calculées en utilisant la pente mde la ligne allant du centre de l'œil aux coordonnées de la souris. En divisant par zéro lors du calcul de la pente, l’infini en virgule flottante (+/-) est préférable à une erreur.

Yeux visuels dans 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

Cela fait une décennie ou deux que j'ai utilisé QB, mais pourriez-vous utiliser à la ?0place de ?"0"? Cela suggère que vous pouvez utiliser une expression numérique ainsi que des chaînes.
Joey

@ Joey Hmm. Impression comme un numéro imprime également un espace avant et après ... mais viennent à penser, je parie que je pourrais imprimer les élèves d' abord , puis ce ne serait pas un problème. Sauf que je devrais alors imprimer les bordures gauche et droite séparément au lieu de "| |". Donc, cela ne sauverait probablement rien. "0"est seulement 2 octets de plus.
DLosc

7

6502 code machine ( souris C64 + 1351 ), 630 octets

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

En action:

démo

Pas de démonstration en ligne , désolée, car il existe AFAIK aucun émulateur js C64 prenant en charge une souris. Si vous voulez l'essayer vous-même, prenez VICE , téléchargez le fichier exécutable binaire et démarrez-le dans l'émulateur C64:

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

Pour saisir / dé-saisir l’entrée de la souris dans l’émulateur en cours, utilisez ctrl+msous Unix / Linux et ctrl+qWindows.


Oui, cela devait être fait;) Après tout, il existe une souris Commodore originale pour le C64, mais bien sûr, le système d’exploitation intégré ne le supporte pas. J’avais donc besoin d’un pilote de souris, qui prenait déjà 230 octets ( y compris un sprite matériel en forme de curseur de souris et un code de vérification des limites pour la zone d’écran, mais sans traduire les coordonnées du pointeur en coordonnées d’écran de texte).

  • Pour protéger quelques octets, j'ai décidé de laisser l'IRQ du système d'exploitation actif et d'utiliser quelques routines Kernal autant que possible (effacer l'écran et obtenir un pointeur de base pour une ligne d'écran texte).
  • Le code met également toutes les variables en zeropage, ce qui enregistre quelques octets supplémentaires, mais détruit les valeurs à virgule flottante utilisées par BASIC. Comme le programme ne se termine jamais, cela n'a pas d'importance.
  • Le troisième truc pour réduire la taille est l'auto-modification: il n'y a que du code à vérifier pour placer l'élève du côté gauche de l'œil. Le même code est réutilisé après avoir corrigé certaines instructions de décrémentation afin d'incrémenter les instructions pour le côté droit.

Si cela vous intéresse, vous pouvez lire le code en tant que source d'assemblage ici :)


Il semble que je sois le seul à vouloir concurrencer ici de temps en temps le code C64. Aimé ce défi, car une souris sur le C64 est quelque chose "exotique"! Si quelqu'un se demande pourquoi je suis moins actif ces derniers temps, voici la raison: csdb.dk/release/?id=161435 - essayez enfin de créer un jeu complet pour le C64 :)
Felix Palmen le

1
Juste pour le plaisir, j'ai fait une "version de luxe": csdb.dk/release/?id=161762
Felix Palmen

7

Propre , 1014 904 892 884 840 814 782 772 769 octets

-6 octets si les yeux n'ont pas besoin de se caler sur une grille

Ce n'était pas facile. Les interfaces dans les langages fonctionnels le sont rarement.

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

Assurez-vous que vous utilisez iTasks Clean, que la Courierpolice est installée et StdLibqu'AVANT tous les sous-dossiers de ObjectIOdans le chemin de recherche du module.

Compiler avec (exemple, peut différer): clm -IL StdLib -IL ObjectIO -IL "ObjectIO/OS <YOUR_OS_HERE>" -IL Dynamics -IL Generics -IL Platform -nci <MODULE_NAME_HERE>

Si vous n'avez jamais exécuté Clean auparavant, attendez-vous à ce que la compilation du projet dure plus de 5 minutes.

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

Comme vous pouvez le constater à partir de la version non-lue, la majeure partie du code ne fait que configurer la combinaison de "police mono-espacée" avec "répondre à la souris". Et même si Couriercela ne facilite pas la tâche, cela dessine les .s et 's. Changer pour quelque chose comme Consolasça rend les choses plus claires.

entrez la description de l'image ici


1
Je ne sais pas propre du tout, alors peut - être que je dis quelque chose de bizarre, mais est - il possible de changer (abs m)<9&&(abs n)<w='9'de (abs m)<9&(abs n)<w='9'? Aussi, je suggère d'ajouter un écran à gif au lieu d'une capture d'écran.
Kevin Cruijssen

1
@KevinCruijssen Cela ne fonctionnerait pas pour plusieurs raisons, mais j'ai économisé 4 octets en supprimant les crochets dans la même expression, alors merci! J'ai aussi ajouté un gif d'écran!
urous

1

Ruby, 335 + 13 = 348 octets

+13 octets pour le -rio/consoledrapeau à activer IO#getch.

Contient les caractères ESC ( 0x1b) littéraux , illustrés ci-dessous. xxd dump suit.

Attention: Cela ne nettoie pas après la sortie. Voir la note sous xxd dump ci-dessous.

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

C'est un golf assez naïf de mon implémentation originale de Ruby .

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

Ce programme active le suivi de la souris avec la séquence de contrôle xterm \e[?1003hmais ne l'éteint pas à la sortie. Pour l'éteindre, utilisez la séquence de contrôle \e[?1003l, par exemple:

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

Comme le programme mange toutes les entrées, il est difficile de sortir. Si vous voulez pouvoir quitter en appuyant sur Ctrl + C, ajoutez la ligne suivante ci (s<<STDIN.getch- dessous :

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

Sans plus tarder:

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.