# Write a Deadfish Interpreter

A rewrite of this question with a simpler input format and guidelines.

## Challenge

Deadfish uses a single accumulator, on which all commands are to be performed.

It has the following commands:

Command Description
i increment the accumulator
d decrement the accumulator
s square the value of the accumulator
o output the value of the accumulator as a number

If, after executing a command, the accumulator is equal to -1 or equal to 256, the accumulator must be reset to zero.

## I/O

Input can be taken as a single string, list of codepoints, or any other reasonable format. It is guaranteed that the input will only consist of deadfish commands.

Output can be given as an array of numbers, or just the numbers printed with separators between them.

## Testcases

(some are borrowed from the Esolangs wiki)

iissso -> 0
diissisdo -> 288
iissisdddddddddddddddddddddddddddddddddo -> 0
isssoisoisoisoiso -> 1,4,25,676,458329
ooooosioiiisooo -> 0,0,0,0,0,1,16,16,16
iiii -> nothing
iiiiiiiissdiiiiiiiiiiiiiiiiio -> 4112
o -> 0


Without Outputs

• Can there be leading separators? – att Jan 30 at 22:41
• What if the accumulator exceeds 256? For example, 29^2? – Xcali Jan 31 at 1:12
• @Xcali the checks are only for -1 or 256, so nothing should happen in that case. – Razetime Jan 31 at 2:09
• @tsh As long as it satisfies the testcases, it is fine. The accumulator will stay within the maximum integer range of your language. – Razetime Jan 31 at 3:44
• diso tests every functionality of the code except for 256 – Gotoro Jan 31 at 14:52

## Batch, 157 bytes

@set a=0
@for %%c in (%*) do @call:%%c
:s
@set/aa=a*a-1
:i
@set/aa+=2
:d
@set/aa-=1
@if %a%==-1 set a=0
@if %a%==256 set a=0
@exit/b
:o
@echo %a%


Takes each Deadfish command as a separate command-line argument. Explanation:

@set a=0


Initialise the accumulator.

@for %%c in (%*) do @call:%%c


Loop through all of the commands, executing each in turn, then fall through into performing an additional s command, whose effect is non-observable.

:s
@set/aa=a*a-1


For the s command, square the accumulator and decrement it, then fall through to the i command, which increments it again.

:i
@set/aa+=2


For the i command, add 2 to the accumulator, then fall through to the d command, which decrements it.

:d
@set/aa-=1


For the d command, decrement the accumulator.

@if %a%==-1 set a=0
@if %a%==256 set a=0
@exit/b


Adjust the accumulator if necessary, then return for the next command.

:o
@echo %a%


For the o command, output the accumulator, then implicitly return for the next command.

204 bytes taking input as a single string (probably actually not the best approach; the call-and-fall through approach above could probably save 10 bytes):

@set/ps=
@set a=0
:l
@if "%s%"=="" exit/b
@for %%a in (1+1.i 1-1.d a.s)do @if %%~xa==.%s:~,1% set/aa=a*%%~na
@if %s:~,1%==o echo %a%
@set s=%s:~1%
@if %a%==-1 set a=0
@if %a%==256 set a=0
@goto l


Takes input on STDIN. Explanation:

@set/ps=
@set a=0


Read the commands and clear the accumulator.

:l
@if "%s%"=="" exit/b


Loop until there are no commands left.

@for %%a in (1+1.i 1-1.d a.s)do @if %%~xa==.%s:~,1% set/aa=a*%%~na


If the command is an arithmetic operation then perform the calculation: a=a*1+1 for i, a=a*1-1 for d and a=a*a for s; it's not possible to use * in a for loop because it's always a wildcard and cannot be quoted (unlike =, which can be quoted).

@if %s:~,1%==o echo %a%


If the command is an o then output the accumulator.

@set s=%s:~1%


Remove the command from the input.

@if %a%==-1 set a=0
@if %a%==256 set a=0
@goto l


Adjust the accumulator if necessary and loop.

# Racket, 178 bytes

(define(f s[a 0])(unless(null? s)(let([x(car s)][y(cdr s)][b(match a[-1 0][256 0][_ a])])(match x[105(f y(+ b 1))][100(f y(- b 1))][115(f y(* b b))][_(and(writeln b)(f y b))]))))


Try it online!

More readable:

(define (f s [a 0])
(unless (empty? s)
(let ([x (first s)]
[y (rest s)]
[b (match a
[-1  0]
[256 0]
[_   a])])
(match x
[105 (f y (+ b 1))]
[100 (f y (- b 1))]
[115 (f y (* b b))]
[_   (and (writeln b)
(f y b))]))))


# R, 111 91 bytes

-20 bytes thanks to CriminallyVulgar

C=scan(,'');n=0;for(x in C){if(n%in%c(-1,256))n=0;n=switch(x,i=n+1,d=n-1,s=n^2,o=print(n))}


Try it online!

• 91 using a switch instead of the clever arithmetic: Try it online! – CriminallyVulgar Feb 2 at 17:28

# APL (Dyalog Classic), 47 bytes

i←+∘1⋄d←-∘1⋄s←×⍨⋄o←⎕∘←⋄{}{0⌈a×256≠a←⍎⍕⍺,⍵}/⌽0,⍞


Try it online!

# Rust, 119 bytes

Closure with a single parameter of type Iterator<Item = u8> with ASCII bytes

|s|{let mut a=0;for c in s{a=match c{105=>a+1,100=>a-1,115=>a*a,111=>{println!("{}",a);a},_=>a};if a==-1||a==256{a=0}}}


Try it online! (with caller function)

Ungolfed version

|s|{
let mut a = 0;
for c in s {
a = match c {
105 => a + 1,
100 => a - 1,
115 => a * a,
111 => { println!("{}", a); a },
_ => a
};
if a == -1 || a == 256 { a = 0 }
}
}

• Suggest if-1==a instead of if a==-1 – ceilingcat May 17 at 4:50

# Java (JDK), 98 bytes

s->{int a=0;for(var c:s){if((c%=7)>5)System.out.println(a);a=c%5<3?1-c%5+a:a*a;a=a<0|a==256?0:a;}}


Try it online!

# Lua (LuaJIT), 153 151 bytes

t={}v=0;loadstring(s:gsub('.',{d='v=v-1;',i='v=v+1;',s='v=v*v;',o='t[#t+1]=v;'}):gsub(';',';v=(v==256 or v<0)and 0 or v;'))()print(table.concat(t,','))


Try it online!

# Vyxal, 28 bytes

❝,(\&\⨥\⨪\²\₴ni+ₑuγd‿¥c[0£


Try it Online!

Takes a list of numbers, where 0 represents i, 1 represents d, 2 represents s and 3 represents o

• @2x-1 that's a result of the safe-evaluation regex I have in place – lyxal Mar 1 at 3:56

# Yabasic, 119 115 bytes

a=0
for j=1 to len(i$) c=instr("isdo",mid$(i$,j,1)) if c<4 a=a+2-c if c=2 a=a*a if c=4 ?a; if a<0 or a=256 a=0 next  Try it online! The actual input is done via reading DATA statements for each Deadfish program. For an interactive version I'd just replace that with an INPUT i$ statement, and calling RUN at the end should re-run the program, initializing variables to 0 and removing the need for the a=0 statement.

I feel this could be more compact, but everything else I try actually makes it bigger. The only really "golf-y" thing is the line:

if c<4 a=a+2-c


which for command 2=square has no effect, avoiding the need for one IF evaluation and saving 11 bytes vs the more straightforward implementation.

Even the XOR 256 trick works out identical in length to the more straightforward version above so I stuck with the simpler code.

edit - I did save 4 bytes because the BASIC interpreter I'm using puts a space as a seperator between numbers automatically, so no need to add it.

# Julia, 70 bytes

s->(a=0;!c=a=[a*=a⊻256>0,a-1,a*a,a+1,c%5>0&&print(a,-)][c÷2%6];.!s)


Based on ovs's answer

Try it online!