| Bytes | Lang | Time | Link |
|---|---|---|---|
| 031 | Uiua | 251016T131838Z | Jake |
| 036 | R | 250622T142305Z | pajonk |
| nan | Commodore 64 Assembler | 250620T215540Z | Jani Joe |
| 012 | Charcoal | 250617T125115Z | Neil |
| 044 | brainfuck | 250627T180029Z | matteo_c |
| 018 | 8086 machine code .COM format | 250626T075908Z | ErikF |
| 027 | C clang | 250618T011148Z | a stone |
| 050 | Swift 6 | 250621T143927Z | macOSist |
| 029 | jq | 250615T212207Z | GammaFun |
| 024 | Python | 250615T231418Z | Lucenapo |
| 011 | oK | 250620T090333Z | zgrep |
| 034 | Haskell | 250615T222331Z | Ibozz91 |
| 025 | JavaScript Node.js | 250620T034851Z | l4m2 |
| nan | Perl 5 a | 250618T061929Z | Xcali |
| 007 | 05AB1E | 250617T082332Z | Kevin Cr |
| 004 | Vyxal | 250617T081233Z | lyxal |
| 025 | Ruby | 250617T222453Z | Value In |
| 007 | APLDyalog Unicode 20 | 250617T095554Z | Mat_rdv |
| 052 | APLNARS | 250617T075458Z | Rosario |
| 034 | Retina 0.8.2 | 250617T051305Z | Neil |
| 062 | Excel | 250617T011302Z | z.. |
| 028 | JavaScript ES6 | 250615T212341Z | Arnauld |
| 006 | Jelly | 250615T194722Z | Jonathan |
Commodore 64 Assembler, 19 14 Bytes (6502/KickAssembler)
Routine
CWEFTA: lax #0 // 2 Reset A and X.
walk: dey // 1 Have we taken more steps than the size of array?
bmi end // 2 If yes, we're stuck in a loop and couldn't escape.
clc // 1 Clear carry flag
adc array,x // 2 Add array element at index X to A
tax // 1 Make it the new array index
cmp length // 2 Have we gone past the end of the array yet?
bcc walk // 2 If not, continue moving forward in the array
end: rts // 1 Positive Y for escape, negative for failure
Explanation
- The array must reside on zero page.
- We need a way to tell our routine where our array ends and where other random data in the memory starts. Thus the length of the array is passed to the routine in Y register and also stored on ZP.
- Starting from the first array element, we add its value to Accumulator, and make it the new array index for the (possible) next round. We then check if the index is pointing past the end of the array. If it isn't, we continue iterating through the array.
- If we've taken more steps than there are elements in the array, we know we're stuck in a loop and thus can't escape.
- At the end, Y register contains a positive number if we escaped, negative if we didn't.
- The code uses only one trick that could be considered sizecoding to reduce its size: Instead of e.g.
LDA #0andTAXto zero out both A and X, we use the unintended opcodeLAX #0(Load to A and X), which saves us a byte. Otherwise the code is plain 6502. - The biggest savings come from storing the array and variables on zero page, which saves us two bytes in comparison to having to use 16bit addressing, as well as using the sign (most significant bit) of Y as our result boolean which saves us three bytes.
Try It Out (in your favourite IDE or CLI)
First in this test program the array and its length are copied to zero page, then our golfing code routine is called, and finally border colour is changed according to the result in Y register: White for successful escape, Black for failure.
.const length = $2 // Length of the array is held on ZP address $2
.const array = $3 // Array itself starts from ZP address $3
BasicUpstart2(start)
start: sei // Disable IRQs (stop BASIC and KERNAL from messing with ZP)
lax le
tay
sty length // Copy array length from our program to zero page
copy: lda ar-1,x // Copy array from our program to zero page
sta array-1,x
dex
bne copy
jsr CWEFTA // CALL OUR ROUTINE
cpy #0 // Is Y positive or negative?
bmi nega // Jump if negative
ldy #WHITE // Otherwise, load white
.by $2c // BIT abs to skip the next two bytes
nega: ldy #BLACK // Load black
sty $d020 // White border=escaped, black=didn't
cli // Re-enable interrupts...
rts // ...and return to BASIC prompt
ar: .by 0,4,1,78,2
le: .by (le-ar)
// Can We Escape From The Array?
CWEFTA: lax #0 // 2 Reset A and X.
walk: dey // 1 Have we taken more steps than the size of array?
bmi end // 2 If yes, we're stuck in a loop and couldn't escape.
clc // 1 Clear carry flag
adc array,x // 2 Add array element at index X to A
tax // 1 Make it the new array index
cmp length // 2 Have we gone past the end of the array yet?
bcc walk // 2 If not, continue moving forward in the array
end: rts // 1 Positive Y for escape, negative for failure
Charcoal, 12 bytes
FA¿ⅈ←M⊖ι→‹ⅈ⁰
Try it online! Link is to verbose version of code. Outputs an inverted Charcoal boolean, i.e. nothing if we escape, - if we don't. Explanation:
FA
Loop through the values.
¿ⅈ←
If we're skipping values then decrement the count left to skip, otherwise...
M⊖ι→
... start skipping values according to the current value, unless that is zero, in which case skip everything.
‹ⅈ⁰
See whether we skipped everything. (¬‹ⅈ⁰ would see whether we escaped.)
brainfuck, 44 bytes
>>-,+[->+<[>-]>[<<[-]+>>->]<<-[-<<,>>]-,+]<.
Outputs 0 if the answer is true, 1 if false.
Assumes that:
- input is given as a sequence of bytes in the range
[0, 254]; - in the considered brainfuck implementation, when the input ends (i.e. EOF is reached) the input command has no effect, the value of the pointed cell is not altered, and the program keeps running.
The used algorithm works in the following way:
- the answer cell is automatically initialized with
0; - try to read an int/char from the input;
- if
0is read, the array input is inescapable and the answer cell is set to1and go to step 2 (we could also go directly to step 3 but I found it harder to implement); - if any other number
nis read, skip the nextn-1input chars and go to step 2; - if EOF is reached, go to step 3.
- if
- output the value of the answer cell.
Ungolfed and commented program:
>>
read input until EOF
-,+
[
-
if read 0 set error
>temp0[-]+
>temp1[-]
<<x[
do nothing
x>-]>
[<
set error
<[-]+>
x>->]<<
skip (n minus 1) input chars
-
[-<<,>>]
-,+
]
output: 0 if true; 1 if false
<.
8086 machine code (.COM format), 18 bytes
Returns AX=0/ZF (false: cannot finish) or AX<>0/!ZF (truthy: did finish)
I iterate through the array until either I hit 0 as an next-entry offset or exceed the bounds of the array. To determine the bounds, I shorten the array length by one to account for the mandatory first element and then subtract the offsets from the remaining array length; if the remaining length goes negative, the array bounds have been exceeded.
Notes:
LODSBplus theDEC AXadjustment is the same number of bytes asMOV AL,[SI]but I thinkLODSBlooks cooler.- Some light golfing of the test harness for fun.
Machine code bytes (in hex)
49 33 C0 AC 84 C0 74 09 2B C8 78 05 48 03 F0 EB F2 C3
Assembly source
;; DS:[SI]: array
;; CX: array length
;; Returns:
;; AX=0 or ZF (FALSE): array traversal does not complete
;; AX<>0 or !ZF (TRUE): traversal does complete
PROC TRAVENDS
START:
DEC CX ; Adjust the count to account for mandatory first element
XOR AX,AX ; Not using AH: clear both parts
SCANLOOP:
LODSB
TEST AL,AL ; Is it 0 (the only value that fails)?
JZ DONE ; Can't continue
SUB CX,AX ; Adjust the new array length remaining (0=last element)
JS DONE ; Done if remaining length is <0 (past the bounds)
DEC AX ; Adjust for LODSB
ADD SI,AX ; Move array pointer
JMP SHORT SCANLOOP
DONE:
RET
ENDP TRAVENDS
Test harness
IDEAL
P8086
MODEL TINY
CODESEG
ORG 100H
MAIN:
MOV BX,0A00H ; Preload "10" for the following DIV; set parse state to "space"
XOR CX,CX ; Number of array elements
MOV SI,81H ; Command line
MOV DI,OFFSET ARRDATA ; Array output
ARRLOOP:
XOR DX,DX ; Zero out the number value
NUMLOOP:
LODSB ; Get character
SUB AL,' '
JZ ISSPACE ; Is space, next element
JS ISDONE ; Is some other control character (we're assuming 0DH), done parsing elements
SUB AL,'0'-' ' ; Not in '0'-'9'
JS SYNTAX
CMP AL,9
JA SYNTAX
TEST BL,BL ; Came out of "space" state?
JNZ INNUM
INC CX ; Increase array count
MOV BL,1 ; Set state to "number"
INNUM:
MOV AH,DL
AAD ; Store (prev*10)+curr
MOV DX,AX
JMP SHORT NUMLOOP
ISDONE:
MOV BL,2 ; Completed array
ISSPACE:
TEST BL,BL ; Still in "space" state?
JZ ENDSPACE
NUMDONE:
XCHG AX,DX ; Just left "number" state: store in array
STOSB
ENDSPACE:
CMP BL,2
JZ ARRDONE ; Done array?
MOV BL,0 ; In "space" state
JMP SHORT ARRLOOP
ARRDONE:
MOV [ARRSIZE],CX ; Store array length for later use
TEST CX,CX ; Quit if no elements stored
JZ SYNTAX
PRINTARR: ; Print array (always at least one entry)
MOV AH,9
MOV DX,OFFSET ARRSTARTTEXT
INT 21H
MOV SI,OFFSET ARRDATA
PRINTELEMS:
DEC CX
XOR AX,AX ; Division target
LODSB
TEST AL,AL
JZ ISZERO ; Is '0', just print it
CALL PROC PRINTNUM ; Print number
JMP SHORT ENDNUM
ISZERO:
MOV AH,2
MOV DL,'0'
INT 21H
ENDNUM:
MOV AH,9
TEST CX,CX ; Array done?
JZ ENDARR ; Yes, print next bit of output
MOV DX,OFFSET ARRMIDTEXT ; No, print a comma and space
INT 21H
JMP SHORT PRINTELEMS
ENDARR:
MOV DX,OFFSET ARRENDTEXT
INT 21H
TRAVERSE:
MOV CX,[ARRSIZE] ; Restore the array size
MOV SI,OFFSET ARRDATA ; Restore the array start
CALL PROC TRAVENDS ; Check if the traversal goes out of bounds
MOV AH,9
JZ PRINTFAIL ; function returns AX=0 (or ZF): false
PRINTSUCCESS:
MOV DX,OFFSET SUCCESSTEXT ; function returns AX<>0 (or !ZF): truthy
JMP SHORT ENDMAIN
PRINTFAIL:
MOV DX,OFFSET FAILTEXT
JMP SHORT ENDMAIN
SYNTAX:
MOV AH,9
MOV DX,OFFSET USAGETEXT
ENDMAIN:
INT 21H
MOV DX,OFFSET ENDTEXT ; Output CR+LF
INT 21H
MOV AX,4C00H ; Done
INT 21H
PROC PRINTNUM
DIV BH ; AL = AL/10
XOR DX,DX ; Storage register
MOV DL,AH ; Store remainder
PUSH DX ; Keep on stack for printing later
XOR AH,AH ; Make sure AH is clear to avoid division messups
TEST AL,AL ; Finished divisions: quotient=0
JNZ NOTDONE
JMP SHORT PRINTDIGIT
NOTDONE:
CALL PROC PRINTNUM ; Recurse and fall into print digit routine (AL>0)
PRINTDIGIT:
MOV AH,2
POP DX
ADD DL,'0'
INT 21H ; Print stored digit
RET
ENDP PRINTNUM
;; DS:[SI]: array
;; CX: array length
;; Returns: AX=0 (FALSE): array traversal does not complete, <>0 (TRUE): traversal does complete
PROC TRAVENDS
START:
DEC CX ; Adjust the count to be zero-based
XOR AX,AX ; Not using AH: clear both parts
SCANLOOP:
LODSB
TEST AL,AL ; Is it 0 (the only value that fails)?
JZ DONE ; Can't continue
SUB CX,AX ; Adjust the new array length remaining (0=last element)
JS DONE ; Done if remaining length is <0 (past the bounds)
DEC AX ; Adjust for LODSB
ADD SI,AX ; Move array pointer
JMP SHORT SCANLOOP
DONE:
RET
ENDP TRAVENDS
USAGETEXT DB "TRAVARR: array values$"
ARRSTARTTEXT DB "Array: [$"
ARRMIDTEXT DB ", $"
ARRENDTEXT DB "]: $"
SUCCESSTEXT DB "success$"
FAILTEXT DB "fail$"
ENDTEXT DB 0DH, 0AH, "$"
ARRSIZE DW ?
ARRDATA DB ?
END MAIN
ENDS
C (clang), 34 27 bytes
-7 thanks to @jdt
f(*a,l){l<1||f(a+*a,l-*a);}
Try it online! Takes input as a pointer to an array and its length. Returns nonzero if escape is possible, otherwise segfaults.
f(*a,l){ /* function taking array of int a and its length l */
l<1 /* if length < 1: (implicitly return) */
|| /* else: */
f(a+*a,l-*a);} /* call f with the array advanced by its first
element. If this element is zero, then it
recurses infinitely, causing a stack overflow */
jq, 36 29 bytes
-7 bytes by Niel for using null + 0 → 0 to simplify the loop condition.
until(.[0]+0==0;.[.[0]:])==[]
.[.[0]:] slices off the first .[0] elements. We repeat this operation until either the array is empty or the first element is 0. The result is whether the array is empty.
JavaScript (Node.js), 25 bytes
a=>a.every(k=t=>k=--k||t)
a=>a.every(t=>a=--a||t) would fail [0] (it successfully decrease to nonzero)
05AB1E, 7 bytes
Δ¬.$}g_
Returns 1/0 for escaped/trapped respectively.
Try it online or verify all test cases.
Unfortunately, only 1 is truthy in 05AB1E, and everything else is falsey. Outputting an empty array when escaped and a non-empty array when trapped would be just 4 bytes by removing the trailing }g_:
Try it online or verify all test cases.
Explanation:
Δ # Loop until the result no longer changes
# (using the implicit input-list in the first iteration):
¬ # Get the first item (without popping the list)
.$ # Remove that many leading items from the list
} # After the changes-loop:
g_ # Check that the resulting list is empty
# (after which the result is output implicitly)
Vyxal, 4 bytes
hȯ)Ẋ
Outputs an empty list for escaped, and a non empty list for trapped.
Explained
hȯ)Ẋ
)Ẋ # Repeat until the input doesn't change, starting with the input:
ȯ # Remove the first
h # result[0]
ȯ # items of the result
💎
Created with the help of Luminespire.
Ruby, 25 bytes
Returns true if we escape, or throws SystemStackError if not. I could save 1 byte by switching to z&& and returning nil if we escape, but I don't want my returns to be falsy vs error so I won't.
f=->a{z,=a;!z||f[a[z..]]}
APL(Dyalog Unicode 20), 7 bytes SBCS
⍬≡⊃⍛↓⍣≡
Explanation
≡ Match (array equality)
⍣ Power
⍣≡ fixpoint (do until the argument stop changing)
↓ Drop
⍛ f⍛g Y ←→ (f Y) g Y
⊃ First element
⊃⍛↓ drop as many elements of a vector as indicated by its first element
≡
⍬ Empty vector
⍬≡⊃⍛↓⍣≡ solution
APL(NARS), 52 chars
r←f w;i
i←r←1
→0×⍳i>≢w⋄→3×⍳0≠w[i]⋄r←0⋄→0
i+←w[i]⋄→2
// 8+6+27+11 = 52
0 It means false, 1 It means true. test: (,1 means one array of 1 ement that is 1)
f ,1
1
f 1 4 0
1
f 0 4 1 78 2
0
Retina 0.8.2, 34 bytes
\d+
$*
^.(?>(?=(1)+)(?<-1>1*.)+)+$
Try it online! Link includes test cases. Explanation:
\d+
$*
Convert the values to unary.
^.(?>...)+$
Repeatedly match but without backtracking if the end of the array cannot be reached. This helps by not having to ensure that the correct number of positions were skipped but also by not having to ensure that each position was properly skipped.
(?=(1)+)
Look ahead to see how many positions to skip.
(?<-1>1*.)+
Use a .NET balancing group to skip that many positions.
Excel, 62 bytes
Expects the array in A1:A
=LET(F,LAMBDA(F,i,LET(x,INDEX(A:.A,i),IF(x,F(F,i+x)))),F(F,1))
Returns #REF! if we can escape and FALSE if we can't.
JavaScript (ES6), 28 bytes
Returns undefined if we can escape or 0 if we're trapped.
f=(a,i=0)=>a[i]&&f(a,i+a[i])
Jelly, 6 bytes
ṫ‘ḢƊÐL
A monadic Link that accepts a list of nonnegative integers and yields 0 (falsey) if we will escape the array, or a non-empty list (truthy) if we will be trapped.
(To not have inverted order, add Ṇ for +1 byte)
Try it online! Or see the test-suite.
How?
ṫ‘ḢƊÐL - Link: list of non-negative integers
ÐL - repeat while results are unique, applying:
Ɗ - last three links as a monad - f(Current):
ṫ - tail of {Current} from each 1-index...
‘ - ...incremented elements of {Current}
Ḣ - head -> Current tailed from 1-index of its first element
...or zero if {Current} is empty