目の視覚化


42

Xウィンドウシステムに付属している(そして、私が知る限り、まだ付属している)デモプログラムであるXeyesを覚えているかもしれません。その目的は、マウスカーソルに追従する目を描くことでした。

Xeyes

あなたの課題は、ASCIIアートでXeyesを再作成することです。ユーザーがクリックするたびに2つのASCIIアートの目(以下で指定)を描画し、カーソルの方向を指すように瞳孔を移動するプログラムまたは関数を記述します。

ターミナルアイズGIF

上記のGIFは、このゴルフ以外のRuby実装の記録であり、Rubyの最新バージョンで実行できます。また、Xterm制御シーケンスのリファレンスとしても役立ちます。

仕様書

これはであるため、バイト数が最も少ないソリューションが優先されます。

これは、プログラムがASCII文字-具体的には、文字使用して描く必要がありますので、挑戦-.|'0、スペース、改行を。1 2

これはチャレンジなので、プログラムは入力を受け入れ、リアルタイムで出力を描画する必要があります。3

プログラムが入力の受け入れを開始する前に、少なくとも20行20列の空白のキャンバスを初期化する必要があります。ユーザーがキャンバスをクリックするまで、何も描画しないでください。

ユーザーがキャンバス上で4をクリックするたびに、プログラムは以前の出力をクリアしてから、マウスカーソルの位置に最も近い文字を中心に、これらのASCIIの目をキャンバス上に描画します。5 6(以下、マウスカーソルを表し、描画しないでください。)

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

生徒がどのようにカーソルを「指す」かに注意してください。

マウスカーソルがキャンバス上を移動するたびに、プログラムは瞳孔を再描画して、カーソルの方向を指し続けるようにします。例:7

             ✧


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

瞳孔ポインティング

次のように、各目の内側の9文字の位置を列挙したとします。

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

瞳孔はいずれかの場所に描かれます1- 9。どちらを決定するかは、キャラクターが正方形で、キャンバスがデカルトグリッドであると仮定し、9キャラクターの中心を(0、0)に、中心を1(1、0)に、などとします。プログラムが入力(クリックまたは移動)を受け取ると、入力位置を最も近いグリッド座標mapにマップする必要があります。𝑀が(0、0)の場合、瞳孔は(0、0)に描画されます。つまり、9ます。それ以外の場合は、以下で説明するように描画する必要があります。

番号デカルト平面グリッド上に重ねて八分円に分割想像1 - 8

𝑀がオクタント1の範囲内にある場合、瞳孔は1上の位置、つまり(1、0)に描かれます。𝑀がオクタント2の場合は、などで描画する必要があります2。説明のために、下の画像は、マウスカーソルが特定の位置にあるときに瞳孔を描画する場所に応じて色分けされたグリッドの一部を示しています。たとえば、カーソルが緑色の座標のいずれかにある場合(グリッド座標は四隅の角ではなく、正方形の中心にあることに注意してください)、瞳孔はに描画され4ます。

2つの目の瞳孔は独立して移動するため、各目について、その目の中心に対してwithでプロセスを繰り返します。

ノート

  1. これは、課題ではありません。出力は文字のグリッドでなければなりません。もちろん、グラフィックルーチンを使用して文字のグリッドを描画することもできます。

  2. 空白は描画されます(または、描画されません)が便利です。グリッド内の空のスポットはスペース文字と同じように見え、同等と見なされます。

  3. ここで「リアルタイム」とは、入力と描画される対応する出力との間の200ミリ秒未満として定義されます。

  4. 入力のために監視されるマウスボタンはどれか、また押すか放すかが「クリック」を構成するかどうかは、ユーザーの裁量です。

  5. キャンバスをクリアするか、視覚的に同等にする必要があります。たとえば、端末ベースのソリューションでは、以前のキャンバスの下に新しいキャンバスを印刷することは同等とは見なされません。

  6. ユーザーがキャンバスの端付近をクリックして、目のキャラクターの一部が端を越えて描画される場合、動作は未定義です。ただし、その後のクリック時にプログラムは正常に実行を継続する必要があります。

  7. マウスカーソルが「キャンバス」から離れると、動作は未定義になりますが、カーソルがキャンバスに再び入っても、プログラムは正常に動作し続ける必要があります。

  8. 出力が不明瞭にならない限り、テキストカーソルがキャンバスに表示される場合があります。

標準的な抜け穴は禁止されています。


2
@Οurousその場合の「数分」はシステムのメモリ量に依存するため、「このソリューションは環境に512GBのRAMがあることを前提としています」という領域につながる可能性があるので、潜在的に無期限に実行する必要があります。
ヨルダン

1
@TaylorScottいや。注#6を参照してください(質問を誤解していない限り)。
ヨルダン

1
@Οurousはい、いいえ。通常、ターゲット環境がデフォルトのフォントが固定幅フォント(ターミナルエミュレーターやコードエディターなど)である場合は、それで問題ありません。その環境で等幅フォントを使用する場合、通常、ブラウザベースのJSソリューションのように追加の設定が必要な場合、その設定はバイトカウントの一部である必要があります(<pre>またはfont-family:monospace)。
ヨルダン

9
素晴らしいタイトル(または、タイトルの取り方によっては悪いタイトル)に+1
FantaC

1
@Οurousいいえ、予期せず終了しない限り。
ヨルダン

回答:


12

HTML + CSS + JavaScript(ES6)、93 + 19 + 278 276 = 388バイト

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


両方とも2バイト節約するためにX||YゴルフすることができX|Yます。
ケビンクルーイッセン

コンテナの下部付近をクリックして下にスクロールする必要がある場合、うまく機能しません。i.stack.imgur.com/s44KU.pngスニペットラッパーに固有かどうかはわかりませんが、言及する価値がありました。
Draco18s

2
@Οurous「マウスカーソルの位置を中心に」というかなり曖昧な言葉です。「場所」は「グリッドセル」を意味しますか、それとも「ピクセル」を意味しますか?私はその意図がおそらく前者であったことに同意しますが、文言は確かに後者を許可するようです。
DLosc

@KevinCruijssen残念ながら、それは機能しません。最終的に|三項式より優先されます。
-darrylyeo

@darrylyeoいいえ、そうではありませんか?:S このJavaScript演算子優先順位テーブルショー|||幾分同じレベルで、上記の両方?:..両方X||Y?w*r(cos(a)):0X||Y?h*r(sin(a)):0形に現在ありますboolean_condition?A:B。そのため、変更X||YするX|Yとビット単位のORが実行され、再びブール条件として解釈されます。((X||Y)?A:Bvs (X|Y)?A:B、ではありませんX|(Y?A:B))。また、「スニペットをコピーして回答」を使用してをに変更し||ても、違いは見られません|。すべてはまだ正確に私が言うことができるようにこれまでと同じように動作します。..
ケビンCruijssen

12

Excel VBA、630バイト

マウスクリックで実行される宣言されたワークシートサブルーチンは、入力を受け取らず、カーソルを追う2つの目を生成します。これは、含まれているヘルパー関数と型宣言に依存しており、通常のモジュールに配置する必要があります。

このバージョンは、デフォルトのズーム100%で実行されるように調整されています。スクロールしようとすると中断します。

注:VBAは新しい行で終端"されていない文字列を自動補完するため、以下のコードでは、強調表示のためだけに端末が含まれている3つのインスタンスがあります-これらはバイトカウントに寄与しません

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

ヘルパー関数と型宣言

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

非ゴルフとコメント

このバージョンは、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

ヘルパー関数と型宣言

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

出力

GIF

Moving_Eyes

高解像度画像

Static_Eyes


これはいくつかの点で仕様と一致しません。1.「文字のグリッド」とは、明確な位置を持つ単一文字を意味します。たとえば、マウスカーソルがオンになっている場合'、出力が右端の文字にあるときとは異なり'ます。2.目の位置は固定されていません。マウスをクリックすると、クリックした位置に移動します。入力方法には柔軟性があります(たとえば、矢印キーで制御される仮想マウスカーソルを受け入れます)が、異なる動作を持つ2つの異なる入力イベントがあります:マウスの動きとマウスクリック。
ヨルダン

@Jordanポイント1の意味がよくわかりませんが、詳しく説明してください。点2については、目は静的ではなく、サブルーチンが置かれているシート上の任意のセルをクリックするとトリガしなければならないWorksheet_SelectionChangeイベントと(発呼範囲を通過させるTargetか、Tこの場合において) -目及び再描画した*呼び出しにセル
テイラースコット

1
@Jordan -私はそうすることで、私は64ビットExcelに私の解決策を制限しなければならなかったと私はこの瞬間ungolfedとコメントしたバージョンに取り組んでいますが、私はあなたの懸念の任意およびすべてに対処していると信じている
テイラー・スコット

1
@Jordanこれは、32ビットと64ビットのWindows API宣言が異なるためです。VBAは連結と累乗の仕様が異なり、32ビットはほとんど常に短いため、32ビットバージョンのOffice:Pにアクセスできません。
テイラースコット

3
たぶん、2つのスクリーンショットをscreen-to-gifに変更しますか?
ケビンクルイッセン

7

QBasicを(QB64)、361の 305バイト

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

左クリックすると目が配置されます。目の配置により、目の一部が範囲外になる場合、プログラムは有効な配置が行われるまで「フリーズ」します。

主なトリッキーな部分は、生徒を配置することです。ほとんどの場合、瞳孔の座標は目の中心にプラス(sign(Δx)、sign(Δy))を加えたものです。ただし、オクタント1および5では、y座標はy中心に等しく、オクタントでは3および7では、x座標はx中心に等しくなります。オクタント境界mは、目の中心からマウス座標までの線の勾配を使用して計算できます。便利なことに、勾配の計算時にゼロで除算すると、エラーではなく浮動小数点の無限大(+/-)が得られます。

QB64の視覚的な目

非ゴルフ

' 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

QBを使用してから10〜2年が経ちましたが、?0代わりに使用できませんでした?"0"か?これは、文字列だけでなく数値式も使用できることを示唆しています。
ジョーイ

@Joeyうーん。それを数字として印刷すると、その前後にスペースも印刷されます...しかし、考えてみると、最初に生徒を印刷することができ、それは問題ではないでしょう。それ以外は、asの代わりに左右の境界線を別々に印刷する必要があります"| |"。したがって、おそらく何も保存されません。"0"2バイトだけ長くなります。
DLosc

7

6502マシンコード(C64 + 1351マウス)、630バイト

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

動作中:

デモ

オンラインデモありません。申し訳ありません。マウスをサポートするjs C64エミュレータはありません。自分で試してみたい場合は、VICEを入手してバイナリ実行可能ファイルをダウンロードし、C64エミュレーターで起動します。

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

実行中のエミュレータでマウス入力を取得/取得するにはctrl+m、Unix / Linuxおよびctrl+qWindows で使用します。


結局のところ、そこに);はい、これが行われなければならなかったです C64の元コモドールのマウスが、私が最初にすでに230のバイトを取ったマウスドライバを、(必要なので、もちろん、組み込みオペレーティングシステムは、それをサポートしていません。マウスカーソル型のハードウェアスプライトと、画面領域のコードをチェックする境界を含みますが、ポインター座標をテキスト画面座標に変換しません)。

  • いくつかのバイトを保護するために、OSのIRQを機能させ、可能な場合はいくつかのKernalルーチンを使用することにしました(画面をクリアし、テキスト画面行のベースポインターを取得します)。
  • また、コードはすべての変数をゼロページに配置するため、さらにバイトを節約できますが、BASICで使用される浮動小数点値は破棄されます。プログラムはとにかく終了しないので、これは問題ではありません。
  • サイズを小さくする3番目のトリックは、自己修正です。瞳孔を目の左側に配置するためにチェックするコードのみがあります。右側の命令をインクリメントするためにいくつかのデクリメント命令をパッチした後、同じコードが再利用されます。

興味がある場合は、ここでアセンブリソースとしてコード読むことができます :)


ここでC64コードと時々競い合うのは私だけのようです。好き C64のマウスは「エキゾチック」なものであるので、この挑戦を!なぜ最近私があまり活気がないのか不思議に思っているなら、これが理由です:csdb.dk/release/?id = 161435-最終的にC64向けのフル機能のゲームをやろうとしている:)
Felix Palmen

1
ただの楽しみのために、「デラックスバージョン」を作成しました。csdb.dk
Felix

7

クリーン1014 904 892 884 840 814 782 772 769バイト

目がグリッドにスナップする必要がない場合は-6バイト

これは簡単ではありませんでした。関数型言語のUIはめったにありません。

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

iTasks Cleanを使用していること、Courierフォントがインストールされていること、およびモジュール検索パスのStdLibサブフォルダーの前にあることを確認してくださいObjectIO

コンパイル(例、異なる場合があります): clm -IL StdLib -IL ObjectIO -IL "ObjectIO/OS <YOUR_OS_HERE>" -IL Dynamics -IL Generics -IL Platform -nci <MODULE_NAME_HERE>

Cleanを実行したことがない場合は、このプロジェクトのコンパイルに5分以上かかると予想してください。

ゴルフをしていない:

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

ungolfedバージョンからわかるように、ほとんどのコードは、「モノスペースフォント」と「マウスに応答する」の組み合わせを設定しているだけです。またCourier、わかりやすくはありませんが、実際には.sと'sを描画しています。のようなものに交換Consolasすると、より明確になります。

ここに画像の説明を入力してください


1
Cleanがまったくわからないので、何か変なことを言っているかもしれませんが、に変更(abs m)<9&&(abs n)<w='9'することは可能(abs m)<9&(abs n)<w='9'ですか?また、スクリーンショットの代わりにscreen-to-gifを追加することをお勧めします
ケビンCruijssen

1
@KevinCruijssenこれは複数の理由で機能しませんが、同じ式で括弧を削除して4バイト節約したので、ありがとう!スクリーンgifも追加しました!
18年

1

ルビー、335 + 13 = 348バイト

-rio/consoleフラグを有効にするための+13バイトIO#getch

次の0x1bように、リテラルESC()文字が含まれています。xxdダンプが続きます。

注意:これは、終了時に自動的にクリーンアップされません。以下のxxdダンプの下の注を参照してください。

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

非ゴルフ

これは、元の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ダンプ

このプログラムは、xterm制御シーケンスでマウストラッキングを\e[?1003hオンにしますが、終了時にオフにしません。オフにするには、制御シーケンスを使用します\e[?1003l。例:

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

プログラムはすべての入力を消費するため、終了するのは困難です。Ctrl + Cを押して終了できるようにするには、次の行を追加します(s<<STDIN.getch

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

難しい話は抜きにして:

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.