可视化眼睛


42

您可能记得也可能不会记得Xeyes,它是X窗口系统附带的演示程序(据我所知,仍然附带)。其目的是在鼠标光标后画一双眼睛:

Xeyes

您的挑战是用ASCII艺术重新创建Xeyes。编写一个程序或函数,无论用户单击什么,它都会画出两只ASCII艺术眼(在下面指定),然后移动他们的瞳孔以指向光标的方向。

终端眼GIF

上面的GIF记录了这种非Golf的Ruby实现,可以与任何最新版本的Ruby一起运行。您可能还会发现它对于Xterm控制序列很有用。

技术指标

这是,因此以字节数最少的解决方案为准。

这是一个的挑战,让你的程序必须提醒使用ASCII字符特异性,人物-.|'0,空间和换行符。1 2

这是一个挑战,因此您的程序必须接受输入并实时绘制其输出。3

在程序开始接受输入之前,它应初始化至少20行20列的空白画布。除非用户单击画布,否则它不应绘制任何内容。

每当用户在画布上单击4时,程序应清除任何先前的输出,然后在画布上以最靠近鼠标光标位置的字符为中心绘制这些ASCII眼睛。5 6(以下表示鼠标光标,不应绘制。)

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

注意瞳孔如何“指向”光标。

每当鼠标光标在画布上移动时,程序应重新绘制瞳孔,使它们继续指向光标,例如7




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

学生指点

假设我们枚举每只眼睛的内部九个字符的位置,如下所示:

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

将在以下位置之一吸引学生:1- 9。要确定是哪个字符,请假装字符为正方形,并且画布为笛卡尔网格,9字符的中心为(0,0),中心为1(1,0),依此类推。程序收到输入(单击或移动)后,应将输入位置映射到最近的网格坐标𝑀。如果𝑀是(0,0),则应在(0,0)处画出瞳孔,即9上面的位置。否则,应按如下所述绘制。

想象叠加在网格并分成八分圆笛卡尔平面编号1 - 8

如果𝑀位于八分圆1内,则应在1上方的位置(即(1,0))处绘制瞳孔。如果in在八分圆2中,则应在2-处绘制,依此类推。为了说明这一点,下图显示了根据鼠标光标在特定位置时应在哪里绘制瞳孔而进行颜色编码的部分网格。例如,当光标位于任何绿色坐标上时(请记住,网格坐标位于正方形的中心,而不是正方形的角),则应在处绘制瞳孔4

两只眼睛的瞳孔独立移动,因此对于每只眼睛,相对于其眼睛中心以𝑀重复该过程。

笔记

  1. 这不是挑战。输出必须是字符网格。当然,您可以使用图形例程来绘制字符网格。

  2. 可以绘制(或改为不绘制)空白,但是很方便。网格中的空白点看起来与空格字符相同,将被视为等效。

  3. 此处,“实时”定义为输入与绘制的相应输出之间的间隔小于200ms。

  4. 您可以自行决定观察哪个鼠标按钮进行输入,以及按下还是释放构成“单击”。

  5. 必须清除画布,或者必须达到视觉上的等效效果。例如,使用基于终端的解决方案,将新的画布打印在先前的画布下方不被视为等效。

  6. 当用户在画布的边缘附近单击以使一些眼睛角色超出其边缘时,行为是不确定的。但是,该程序必须在随后的单击中继续正常运行。

  7. 当鼠标光标离开“画布”时,行为是不确定的,但是当光标重新进入画布时,程序必须继续正常运行。

  8. 文本光标可能会出现在画布上,只要它不会遮挡输出即可。

禁止出现标准漏洞。


2
@ourous因为在这种情况下,“几分钟”是多少分钟取决于系统拥有多少内存,并且这可能导致我们进入“此解决方案假定环境具有512GB RAM”的区域,所以我要说的是它必须无限期地运行。
约旦

1
@TaylorScott Nope。请参阅注释6(除非我误解了您的问题)。
约旦

1
@否urous是的,不是。如果您的目标环境通常是默认字体为等宽字体的环境(例如,终端仿真器或代码编辑器),那很好。如果在该环境中使用等宽字体通常需要额外的配置(例如在基于浏览器的JS解决方案中),则该配置必须是字节数的一部分(例如<pre>font-family:monospace)。
约旦

9
+1为大标题(或坏标题,取决于您的接受方式)
FantaC

1
@否urpe,只要它不会意外终止。
乔丹

Answers:


12

HTML + CSS + JavaScript(ES6),93 + 19 + 278276 = 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> |
|   | |   |
'---' '---'


两者X||Y均可打高尔夫球X|Y以节省2个字节。
凯文·克鲁伊森

当您单击容器底部附近并向下滚动时,效果不佳。i.stack.imgur.com/s44KU.png不确定是否特定于代码片段包装程序,但值得一提。
Draco18s

2
@OOurous的措辞很含糊:“以鼠标光标的位置为中心。” “位置”是指“网格”还是“像素”?我同意,意图可能是前者,但措辞显然允许后者。
DLosc

@KevinCruijssen不幸的是,这不起作用– |最终优先于三元表达式。
darrylyeo '18

@darrylyeo不,不是吗?:S 此JavaScript运算符优先级表|||上有些相同的水平,并且两个以上?:..两者X||Y?w*r(cos(a)):0X||Y?h*r(sin(a)):0目前在形式boolean_condition?A:B。因此,当您更改X||YX|Y它时,将按位进行“或”运算,然后再次将其解释为布尔条件。((X||Y)?A:Bvs (X|Y)?A:B,不是X|(Y?A:B))。另外,我看不出有什么区别,当我使用“复制片段来回答”,并更改|||。一切仍然工作完全一样,据我可以告诉..
凯文Cruijssen

12

Excel VBA,630字节

声明的工作表子例程,通过鼠标单击运行,不输入任何内容,并产生跟随光标的一对眼睛。这取决于所包含的辅助函数和类型声明,必须将其放在常规模块中。

此版本已校准为以默认缩放100%运行。尝试滚动时中断。

注意:VBA在新行自动完成未终止的字符串,因此在下面的代码中,在三个实例中,"仅出于突出显示目的而包含了一个终端-这些不影响字节数

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

高分辨率图像

静电眼


这在某些方面与规范不符。1.“字符格”是指位置不同的单个字符。例如,当鼠标光标打开时,最右边的'字符输出将不同于最左边的'字符。2.眼睛的位置不固定。鼠标单击应使它们移动到单击位置。我在输入方法上比较灵活(例如,我接受由箭头键控制的虚拟鼠标光标),但是有两个具有不同行为的不同输入事件:鼠标移动和鼠标单击。
乔丹

@乔丹我不太确定您所说的第1点是什么意思,请您详细说明一下?对于第2点,眼睛不是一成不变的,单击子程序所在工作表上的任何单元格都将触发该Worksheet_SelectionChange事件并通过调用范围(TargetT在这种情况下)-这会*在调用中重画眼睛和a 细胞
泰勒·斯科特

1
@Jordan-我相信我已经解决了您的所有问题,尽管这样做,我不得不将解决方案限制为64位Excel,并且目前我正在开发一个未发表评论的版本
Taylor Scott

1
@Jordan那是因为Windows API声明32和64,但是VBA是不同的,如级联和幂运算的细节,其中32位几乎总是更短-我目前无法访问Office:P的32位版本
泰勒·斯科特

3
也许将两个屏幕截图更改为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

左键单击放置眼睛。如果放置眼睛会导致部分眼睛超出范围,则程序将“冻结”,直到进行有效放置为止。

棘手的主要部分是放置学生。在大多数情况下,瞳孔的坐标只是眼睛的中心加上(符号(Δx),符号(Δy)),除了在八分之一和五分之一中,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

自从我使用质量检查以来已经过去了一两年,但是您不能使用?0而不是?"0"建议您可以使用数字表达式以及字符串。
乔伊

@Joey Hmm。打印出来的号码之前和之后还打印出空间......但细想起来,我打赌我能打印学生第一,然后这不会是一个问题。否则我将不得不分别打印左右边框而不是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

实际上:

演示

抱歉,没有在线演示,因为AFAIK没有支持鼠标的js C64仿真器。如果要自己尝试,请抓住VICE,下载二进制可执行文件,然后在C64仿真器中启动它:

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

要在运行的模拟器中捕获/取消鼠标输入,请ctrl+m在Unix / Linux和ctrl+qWindows上使用。


是的,这还需要努力;)毕竟,一个原始的Commodore鼠标为C64,当然,内置的操作系统不支持它,所以我首先需要一个鼠标驱动程序,它已经花了230个字节(包括鼠标光标形状的硬件精灵和屏幕区域的边界检查代码,但不将指针坐标转换为文本屏幕坐标)。

  • 为了保护一些字节,我决定保持操作系统的IRQ正常运行,并在可能的情况下使用一些Kernal例程(清除屏幕并获取文本屏幕行的基本指针)。
  • 该代码还将所有变量都置于零页中,这节省了更多字节,但破坏了BASIC使用的浮点值。由于该程序永远不会退出,因此这无关紧要。
  • 减小尺寸的第三个技巧是自我修改:只有代码可以检查是否将瞳孔放在眼睛的左侧。在修补一些递减指令以增加右侧的递增指令后,可以重复使用相同的代码。

如果您有兴趣,可以在此处将代码作为汇编源阅读:)


我似乎是唯一不时尝试与C64代码竞争的人。喜欢这个挑战,因为C64上的鼠标有些“异国情调”!如果有人想知道为什么我最近不那么活跃,这就是原因:csdb.dk/release/?id=161435-最终试图为C64做一个全功能的游戏:)
Felix Palmen

1
只是为了好玩,我做了一个“豪华版”:csdb.dk/release/?id=161762
Felix Palmen

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

从非高尔夫版本中可以看到,大多数代码只是设置“等宽字体”和“响应鼠标”的组合。尽管Courier很难说清楚,但实际上是在绘制.s和's。交换到类似的东西Consolas可以使它更清晰。

在此处输入图片说明


1
我一点都不了解Clean,所以也许我说的很奇怪,但是可以更改(abs m)<9&&(abs n)<w='9'(abs m)<9&(abs n)<w='9'吗?另外,我建议添加一个屏幕到gif而不是屏幕截图。
凯文·克鲁伊森

1
@KevinCruijssen出于多种原因,该方法不起作用,但我确实节省了4个字节,将括号放在同一表达式中,所以谢谢!我还添加了屏幕gif!
世纪

1

Ruby,335 + 13 = 348字节

+13个字节-rio/console来启用标志IO#getch

包含文字ESC(0x1b)字符,如下所示。xxd转储如下。

注意:此操作在退出后无法自行清除。请参阅下面的xxd dump下的注释。

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.