经典VCS ASCII Adventure


21

长大后,我的第一个主机游戏系统是Atari 2600,我将永远爱上我小时候喜欢的一些游戏。许多图形仍然令人难忘,甚至具有标志性。

事实证明,这些子画面是非常简单的位图,宽度为8个像素,高度可变,其中二进制表示形式是像素的排列。

例如,十六进制字节0x18、0x24、0x18将绘制一个粗略的圆圈,如下所示:

0x18: 00011000
0x24: 00100100
0x18: 00011000

由于8像素宽可创建相当小的图形(即使按Atari 2600标准),通常也可以将高度,宽度或两者都翻一番或翻两番,以创建同一图像的更大(虽然更块状和失真)的版本。对于玩家精灵和运动场,它们通常也会垂直或水平翻转。游戏《战斗》就是一个很好的例子。

挑战在于,编写代码以将这些精灵显示为ASCII形式的“图形”,包括能够垂直,水平或同时拉伸或翻转它们的能力。它必须采用完整程序或可调用函数的形式。

输入:

  • 字节数组,每个字节代表该行的水平位。
  • 水平和垂直每个方向的非零整数值,代表该尺寸的比例因子。
  • 负值表示尺寸也应沿其轴翻转。

输出:

  • ASCII表示为STDOUT或换行符分隔的字符串,对于黑色(0)像素使用空格字符,对于白色(1)像素使用您选择的任何可打印的非空格字符。

测试数据:

bmp1 = [ 0x06, 0x0F, 0xF3, 0xFE, 0x0E, 0x04, 0x04, 0x1E, 0x3F, 0x7F, 0xE3, 0xC3, 0xC3, 0xC7, 0xFF, 0x3C, 0x08, 0x8F, 0xE1, 0x3F ]
bmp2 = [ 0x07, 0xFD, 0xA7 ]
bmp3 = [ 0x00, 0x8E, 0x84, 0xFF, 0xFF, 0x04, 0x0E, 0x00 ]
bmp4 = [ 0x00, 0xFC, 0xFC, 0x38, 0x3F, 0x38, 0xFC, 0xFC]

注意:上面的示例输入字节数组以十六进制形式提供。如果您的平台不接受十六进制文字作为字节表示形式,则可以将其转换为与本地字节等效的文字。

示例输出:

f( bmp1, 1, 1 ) =>
--------
     XX 
    XXXX
XXXX  XX
XXXXXXX 
    XXX 
     X  
     X  
   XXXX 
  XXXXXX
 XXXXXXX
XXX   XX
XX    XX
XX    XX
XX   XXX
XXXXXXXX
  XXXX  
    X   
X   XXXX
XXX    X
  XXXXXX
--------

f( bmp1, -2, 1 ) =>
----------------
  XXXX          
XXXXXXXX        
XXXX    XXXXXXXX
  XXXXXXXXXXXXXX
  XXXXXX        
    XX          
    XX          
  XXXXXXXX      
XXXXXXXXXXXX    
XXXXXXXXXXXXXX  
XXXX      XXXXXX
XXXX        XXXX
XXXX        XXXX
XXXXXX      XXXX
XXXXXXXXXXXXXXXX
    XXXXXXXX    
      XX        
XXXXXXXX      XX
XX        XXXXXX
XXXXXXXXXXXX    
----------------

f( bmp2, 1, 2 ) =>
--------
     XXX
     XXX
XXXXXX X
XXXXXX X
X X  XXX
X X  XXX
--------

f( bmp2, 2, 1 ) =>
----------------
          XXXXXX
XXXXXXXXXXXX  XX
XX  XX    XXXXXX
----------------

f( bmp2, -2, -2 ) =>
----------------
XXXXXX    XX  XX
XXXXXX    XX  XX
XX  XXXXXXXXXXXX
XX  XXXXXXXXXXXX
XXXXXX          
XXXXXX          
----------------

f( bmp3, 1, -1 ) =>
--------

    XXX 
     X  
XXXXXXXX
XXXXXXXX
X    X  
X   XXX 

--------

f( bmp3, 3, 3 ) =>
------------------------



XXX         XXXXXXXXX   
XXX         XXXXXXXXX   
XXX         XXXXXXXXX   
XXX            XXX      
XXX            XXX      
XXX            XXX      
XXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXX
               XXX      
               XXX      
               XXX      
            XXXXXXXXX   
            XXXXXXXXX   
            XXXXXXXXX   



------------------------

f( bmp4, -1, -1 ) =>
--------
  XXXXXX
  XXXXXX
   XXX  
XXXXXX  
   XXX  
  XXXXXX
  XXXXXX

--------

f( bmp4, 4, 2 ) =>
--------------------------------


XXXXXXXXXXXXXXXXXXXXXXXX        
XXXXXXXXXXXXXXXXXXXXXXXX        
XXXXXXXXXXXXXXXXXXXXXXXX        
XXXXXXXXXXXXXXXXXXXXXXXX        
        XXXXXXXXXXXX            
        XXXXXXXXXXXX            
        XXXXXXXXXXXXXXXXXXXXXXXX
        XXXXXXXXXXXXXXXXXXXXXXXX
        XXXXXXXXXXXX            
        XXXXXXXXXXXX            
XXXXXXXXXXXXXXXXXXXXXXXX        
XXXXXXXXXXXXXXXXXXXXXXXX        
XXXXXXXXXXXXXXXXXXXXXXXX        
XXXXXXXXXXXXXXXXXXXXXXXX        
--------------------------------

注意:上方和下方的水平线表示输出的开始和结束。在输出中不需要它们,但是如图所示,在开始和/或结束处都需要空行(由所有零/空格表示)。

注意2:这些测试位图的灵感来自维基百科上标记为“合理使用”的游戏屏幕截图,并根据它们进行了重新绘制/编码。

获奖标准

  • 这是,因此以每种语言(以字节为单位)的最短代码为准。
  • 禁止出现标准漏洞

6
“有人把这只野鸭从我身边弄走!” - 强坏
AdmBorkBork

7
具有讽刺意味的是,即使这里最聪明的高尔夫运动也可能不如Atari 2600的程序员实际要做的那么聪明,如果他们想要比Pong克隆游戏更有趣的东西-整个屏幕一次渲染一行, CPU花费了大部分时间来执行此操作。仅有128个字节的RAM,就没有像屏幕缓冲区这样的奢侈空间了……您拥有的全部五个精灵就是奢侈的东西。
Jeroen Mostert

我们可以将输入作为8位二进制字符串列表或类似的格式(字节已经解压成位)的列表吗?
Luis Mendo

@LuisMendo“ 如果您的平台不接受十六进制字面量来表示字节,则可以将其转换为等效于本地字节的字面量。
Kevin Cruijssen

@KevinCruijssen这就是重点,我不知道什么是等效的。这是否为直接输入位图打开了大门?
Luis Mendo

Answers:


5

Python 2,117个字节

def f(m,w,h):
 for r in m[::cmp(h,0)]:print(''.join(' X'[1<<i&r>0]*abs(w)for i in range(8)[::cmp(0,w)])+'\n')*abs(h),

在线尝试!


5

05AB1E27 26 字节

εS²Ä×J³Äи²0‹ií]³0‹iR}˜0ð:»

将输入作为8位二进制字符串的列表,并将输出1作为非空格字符。

-1个字节感谢@MagicOctopusUrn

在线尝试验证所有测试用例

说明:

ε         # Map the (implicit) input-list to:
 S        #  Convert the binary-String to a list of characters
  ²Ä      #  Take the absolute value of the second input
    ×     #  And repeat each character that many times
     J    #  And then join it back together to a single string again
 ³Ä       #  Take the absolute value of the third input
   и      #  Repeat that string as a list that many times
 ²0i     #  If the second input is negative:
     í    #   Reverse each string in the list
]         # Close both the if-statement and (outer) map
³0i }    # If the third input is negative:
    R     #  Reverse the list of lists
      ˜   # Flatten the list of lists to a list of strings
0ð:       # Replace all 0s with spaces " "
   »      # And join the strings by newlines (which is output implicitly)

必须有一个2乘以0‹i
魔术

@MagicOctopusUrn 0‹确实应该有一个1字节。.我们确实有一个1字节>=0,即d。但是,我们还应该使用1-byter来检查负imo。现在我只使用0‹d_
凯文·克鲁伊森

我所能想到的是:(„íR³²‚0‹Ï.V完整代码εε²Ä×}J³Äи0ð:}„íR³²‚0‹Ï.V˜»)这不是一个改进,但是确实消除了其中的负面检查之一。
魔术章鱼缸

1
另外,很确定εS²Ä×J³Äи²0‹ií]³0‹iR}˜0ð:»可以节省一个字节。如果可以采用2D数组,则可以将其S全部删除25个字节。
魔术章鱼缸

@MagicOctopusUrn当然是啊,S²Ä×而不是ε²Ä×}。谢谢!嗯,如果允许我们将二进制输入作为0和1的列表,则可以通过省略来节省额外的字节S。会问OP是否允许。„íR³²‚0‹Ï.V在您的其他评论中,我也喜欢您。:)
Kevin Cruijssen

3

MATL24 19字节

B,!i|1&Y"2M0<?XP]Zc

输入是十进制数字,水平刻度,垂直刻度的数组。

在线尝试!

说明

B        % Implicit input: array of numbers. Convert to binary. Gives a zero-one
         % matrix, each row containing the binary expansion of a number
,        % Do twice
  !      %   Transpose
  i      %   Input: number
  |      %   Absolute value
  1&Y"   %   Repeat each row that many times
  2M     %   Push the latest input again
  0<     %   Is it negative?
  ?      %   If so:
    XP   %     Flip vertically
  ]      %   End
  Zc     %   Convert each nonzero into '#'. Zeros are displayed as space
         % Implicit end. Implicit display

3

Dyalog APL,46 42 33字节

' #'[⍉⊃{⊖⍣(0>⍺)⍉⍵/⍨|⍺}/⎕,⊂⎕⊤⍨8/2]

在线尝试!

-9感谢ngn!


每个->减少:{' #'[⊃{⌽⍣(0>⍺)⊢(|⍺)/⍉⍵}/⍺,⊂⍉⍵⊤⍨8/2]}dfn->程序:' #'[⊃{⌽⍣(0>⍺)⊢(|⍺)/⍉⍵}/⎕,⊂⍉⎕⊤⍨8/2]
ngn

较短:' #'[⍉⊃{⊖⍣(0>⍺)⍉⍵/⍨|⍺}/⎕,⊂⎕⊤⍨8/2]。顺便说一句,第二个测试的输出似乎在您原始的解决方案中是相反的
ngn

@ngn谢谢!第二个示例的输入应取反,以匹配问题中的第二个测试用例。
dzaima

3

Prolog(SWI),252字节

N+E+R:-N<1,R=[];N-1+E+S,R=[E|S].
N*E*R:-R=E,E=[];N<0,reverse(E,F),-N*F*R;[H|T]=E,N+H+S,N*T*U,append(S,U,R).
N/E/R:-N<1,R=[];(E<N,D=E,F=32;D=E-N,F=35),N/2/D/C,R=[F|C].
[H|T]^X^Y^R:-128/H/A,X*A*B,Y*[[10|B]]*C,append(C,D),(T=[],R=D;T^X^Y^S,append(D,S,R)).

在线尝试!

说明

N+E+R:-N<1,R=[];N-1+E+S,R=[E|S].   Make `R` a list containing `E` repeated `N` times
       N<1,R=[]                    If `N<1`, let `R` be the empty list
       N-1+E+S                     Else recurse with `N-1`, `E` and `S`
           R=[E|S]                 Let `R` be a new list with `E` as head and `S` as tail
N*E*R:-R=E,E=[];N<0,reverse(E,F),-N*F*R;[H|T]=E,N+H+S,N*T*U,append(S,U,R).
                                   Let `R` be a list
                                   with each element in `E` repeated `N` times
                                   e.g. 2*[3, 6] -> [3, 3, 6, 6]
       R=E,E=[]                    Let `R` be `E` if `E` is the empty list
       N<0,reverse(E,F)            Else if `N<0`, let `F` be the reverse of `E`
           -N*F*R                  Recurse with `-N`, `F` and `R`
       [H|T]=E                     Else let `H` be the head and `T` be the tail of `E`
           N+H+S                   Let `S` be `N+H+S` (our function, not addition)
           N*T*U                   Recurse with `N`, `T` and `U`
           append(S,U,R)           let `R` be the concatenation of `S` and `U`
N/E/R:-N<1,R=[];(E<N,D=E,F=32;D=E-N,F=35),N/2/D/C,R=[F|C].
                                   Make `R` the binary representation of `E`
                                   with `N` as the value of the current bit
                                   where 0 and 1 are space and hash respectively
    N<1,R=[]                       If `N<1` let `R` be the empty list
    (
        E<N,D=E,F=32               If `E<N` the bit isn't set, so `D=E`, `F=space`
        D=E-N,F=35                 Else `D=E-N`, `F=hash`
    )
        N/2/D/C                    Recurse with `N/2`, `D` and `C`
        R=[F|C]                    Let `R` be a new list with `F` as head and `C` as tail
[H|T]^X^Y^R:-128/H/A,X*A*B,Y*[[10|B]]*C,append(C,D),(T=[],R=D;T^X^Y^S,append(D,S,R)).
                                   Make `R` the result,
                                   with inputs being the list `[H|T]`
                                   and the scales `X` and `Y`
   128/H/A                         Let `A` be the binary representation of `H` (8 bits)
   X*A*B                           Let `B` be `A` with each element repeated `X` times
   Y*[[10|B]]*C                    Let `C` be `B` with a newline prepended,
                                   repeated `Y` times
   append(C,D)                     Let `D` be `C` flattened by one level (joining lines)
   (
       T=[],R=D                    If `T` is empty, let `R` be `D` 
       T^X^Y^S                     Else recurse with `T`, `X`, `Y` and `S`
           append(D,S,R)           Let `R` be the concatenation of `D` and `S`
   )

2

木炭,28字节

FθE↔ζ⭆⮌↨ι²×§ Xμ↔ηF›η⁰‖F‹ζ⁰‖↓

在线尝试!链接是详细版本的代码。说明:

Fθ

循环遍历字节列表。

E↔ζ

在垂直比例因子上进行映射,从而增加输出线。

⭆⮌↨ι²×§ Xμ↔η

将输入转换为2,取反,将数字映射到空格X,然后将每个字符乘以水平比例因子。

F›η⁰‖

如果水平比例因子为正,请进行反射以重新获得正确的图像。

F‹ζ⁰‖↓

如果垂直比例因子为负,则垂直反射。


并不是说它可以节省任何字节,但是我很好奇:为什么用FFor)而不是¿If)进行检查?
凯文·克鲁伊森

1
@KevinCruijssen在木炭简洁模式下else是隐含的,所以我唯一可以使用的if是它是否是该块中的最后一条语句。
尼尔

嗯,还不知道。因此If在这里使用两个实际上是一个If ... Else If ...而不是两个宽松的If。嗯,很高兴知道。
凯文·克鲁伊森


2

普通Lisp,157字节

(lambda(l x y)(dolist(i(if(< y 0)(reverse l)l))(dotimes(j(abs y))(dotimes(n 8)(dotimes(k(abs x))(princ(if(logbitp(if(< x 0)n(- 7 n))i)"#"" "))))(princ"
"))))

在线尝试!

说明

(lambda(l x y)                           ; Lambda with parameters `l`, `x`, `y`
    (dolist
        (i                               ; For `i` in the list  
            (if(< y 0)(reverse l)l)      ; The reverse of `l` if `y<0` else `l`
        )
        (dotimes(j(abs y))(dotimes(n 8)(dotimes(k(abs x))
                                         ; Do `y` times, for `n` from 0 to 7, do `x` times
        (princ(if(logbitp(if(< x 0)n(- 7 n))i)"#"" "))))
                                         ; If `x<0` and the `n`th bit is 1
                                         ; or `x>0` and the `7-n`th bit is 1
                                         ; print "#", else print " "
        (princ"
")                                       ; After every `y` loop, print a newline
        )
    )
)

2

Tcl,192字节

proc f {l x y} {lmap i [if $y<0 {lreverse $l} {lindex $l}] {time {lmap n {0 1 2 3 4 5 6 7} {time {puts -nonewline [expr $i&1<<($x<0?$n:7-$n)?{#}:{ }]} [expr abs($x)]};puts {}} [expr abs($y)]}}

在线尝试!

proc f {l x y}                           Define a function `f` with arguments `l`, `x`, `y`
{lmap i                                  For each `i` in
    [if $y<0 {lreverse $l} {lindex $l}]  The reverse of `l` if `y<0` else `l`
    {
        time {                           Do `abs(y)` times
            lmap n {0 1 2 3 4 5 6 7} {   For `n` from 0 to 7
                time {                   Do `abs(x)` times
                    puts -nonewline      Print without newline
                         [expr $i&1<<($x<0?$n:7-$n)?{#}:{ }]
                                         If `x<0` and the `n`th bit is 1 or
                                         `x>0` and the `7-n`th bit is 1
                                         then return "#" else return " "
                } [expr abs($x)]
            };
            puts {}                      Print a newline
        } [expr abs($y)]
    }
}

2

8088机器代码,IBM PC DOS, 77 71个字节

组装:

B402 84FF 7906 FD03 F14E F6DF 518A CFAC 5051 B108 8AF3 84F6 7902 F6DE
518A CEB2 2384 DB79 04D0 C8EB 02D0 C072 02B2 2050 CD21 58E2 FA59 E2E4
B20D CD21 B20A CD21 5958 E2CC 59E2 C5

清单:

    PR_BMP  MACRO BMP, SZBMP, ZX, ZY
            LOCAL LOOP_Y, LOOP_Y2, LOOP_X, LOOP_X2, X_POS, X_NEG
B4 02   MOV  AH, 2          ; DOS display char function 
84 FF   TEST ZY, ZY         ; is Y scale negative?
79 06   JNS  LOOP_Y         ; if positive, start Y LOOP
FD      STD                 ; direction flag start from end
03 F1   ADD  BMP, CX        ; advance input byte array to end
4E      DEC  BMP            ; zero adjust index
F6 DF   NEG  ZY             ; make counter positive
     LOOP_Y:    
51      PUSH CX             ; save outer byte loop counter
8A CF   MOV  CL, ZY         ; set up repeat counter (Y scale factor)
AC      LODSB               ; load byte into AL
     LOOP_Y2:
50      PUSH AX             ; save original AL
51      PUSH CX             ; save outer loop
B1 08   MOV  CL, 8          ; loop 8 bits
8A F3   MOV  DH, ZX         ; DH is positive X scale used as counter
84 F6   TEST ZX, ZX         ; is X scale negative?
79 02   JNS  LOOP_X         ; if so, make counter positive
F6 DE   NEG  DH             ; compliment X counter 
    LOOP_X:
51      PUSH CX             ; save bit counter
8A CE   MOV  CL, DH         ; set repeat counter (X scale factor)
B2 23   MOV  DL, '#'        ; by default, display a #
84 DB   TEST ZX, ZX         ; is X scale negative?
79 04   JNS  X_POS          ; if so, rotate left 1 bit
D0 C8   ROR  AL, 1          ; else rotate right LSB into CF
EB 02   JMP  X_NEG          ; jump to examine CF
    X_POS:
D0 C0   ROL  AL, 1          ; rotate left MSB into CF
    X_NEG:
72 02   JC   LOOP_X2        ; is a 1?   
B2 20   MOV  DL, ' '        ; if not, display a space
    LOOP_X2:    
50      PUSH AX             ; save AL (since silly DOS overwrites it)
CD 21   INT  21H            ; display char
58      POP  AX             ; restore AL
E2 FA   LOOP LOOP_X2        ; loop repeat counter
59      POP  CX             ; restore bit counter
E2 E4   LOOP LOOP_X         ; loop bit counter
B2 0D   MOV  DL, 0DH        ; display CRLF
CD 21   INT  21H
B2 0A   MOV  DL, 0AH
CD 21   INT  21H
59      POP  CX             ; restore outer loop
58      POP  AX             ; restore original AL
E2 CC   LOOP LOOP_Y2        ; loop row display
59      POP  CX             ; restore byte counter
E2 C5   LOOP LOOP_Y         ; loop byte counter
    ENDM

事实证明,这在ASM中比我最初想象的要麻烦得多。多个并发循环和大量if / else分支肯定会让您头疼。

这被实现为MACRO,因为它允许传递类似函数的参数以进行测试。

输出量

这是一个用于DOS的测试程序,它提示输入X和Y缩放比例并绘制到屏幕上。注意,由于默认的DOS窗口只有24行,因此缩放龙过多会滚动到顶部。

在此处输入图片说明

这是我们的小龙(鸭子):

在此处输入图片说明

在线尝试!

您可以通过以下步骤使用DOSBoxVirtualConsoles.com在DOS VM中进行测试:

  1. 下载VCS.ZIP(包含所有四个可执行文件)
  2. 转到https://virtualconsoles.com/online-emulators/DOS/
  3. 上载刚刚下载的ZIP文件,然后单击“开始”。
  4. 类型PLANEKEYTANKDRAGON



1

APL(Dyalog扩展),23 字节SBCS

dzaima的方法

匿名默认前缀功能。需要vH 作为论据 v 是垂直比例因子, H 是水平缩放因子,并且 是作为8列压缩位布尔矩阵的字节数组(这是在APL中表示原始字节的常规且最紧凑的方式)。需要⎕IO←0(从零开始的索引)。

' x'⊇⍨∘⊃{⊖⍣(>⍺)⍉⍵/⍨|⍺}/

在线尝试!

{}/ 使用以下匿名lambda从右向左减少:

|⍺ 左参数的大小(比例因子)

⍵/⍨ 用它来水平复制正确的参数

 转置

⊖⍣() 如果发生翻转:

  >⍺ 比例因子小于零

 公开(因为包含了减少量以将张量等级从1减少到0)

' x'⊇⍨ 使用该矩阵从字符串“ x”中选择元素



1

T-SQL,216字节

在执行此MS-SQL Studio管理之前,请按CRTL-t将数据显示为文本。高度不能调整为超过输入中的元素数。

由于STRING_AGG的实施非常糟糕,height变量仅在MSSM中有效。MS应该已经设置了第三个可选参数,以包括要串联的元素的顺序。

在线版本只能支持宽度的调整。高度会导致带有多个堆叠形状的时髦结果。

USE master
DECLARE @ table(v int,i int identity)
INSERT @ values
(0x06),(0x0F),(0xF3),(0xFE),(0x0E),(0x04),
(0x04),(0x1E),(0x3F),(0x7F),(0xE3),(0xC3),
(0xC3),(0xC7),(0xFF),(0x3C),(0x08),(0x8F),
(0xE1),(0x3F)
-- @  = width
-- @h = height
DECLARE @s INT=1,@h INT=1

SELECT iif(@s>0,reverse(x),x)FROM(SELECT
string_agg(replicate(iif(v&n=0,' ','X'),abs(@s)),'')x,i,j
FROM(values(1),(2),(4),(8),(16),(32),(64),(128))x(n)
,@,(SELECT top(abs(@h))i j FROM @)g GROUP BY i,j)f
ORDER BY i*@h

该脚本不会在在线版本中显示正确的形状,因此我做了一些小的调整以进行补偿。 在线尝试

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.