44
\$\begingroup\$

In this challenge you are going to write an interpreter for a simple language I've made up. The language is based on a single accumulator A, which is exactly one byte in length. At the start of a program, A = 0. These are the languages instructions:

!: Inversion

This instruction simply inverts every bit of the accumulator. Every zero becomes a one and every one becomes a zero. Simple!

>: Shift Right

This instruction shifts every bit in A one place to the right. The leftmost bit becomes a zero and the rightmost bit is discarded.

<: Shift Left

This instruction shifts every bit in A one place to the left. The rightmost bit becomes a zero and the leftmost bit is discarded.

@: Swap Nybbles

This instruction swaps the top four bits of A with the bottom four bits. For example, If A is 01101010 and you execute @, A will be 10100110:

 ____________________
 |                  |
0110 1010    1010 0110
      |_______|

That's all the instructions! Simple, right?

Rules

  • Your program must accept input once at the beginning. This will be a line of code. This is not an interactive interpreter! You can only accept input once and do not have to loop back to the start once that line has been executed.
  • Your program must evaluate said input. Every character that is not mentioned above is ignored.
  • Your program should then print out the final value of the accumulator, in decimal.
  • Usual rules for valid programming languages apply.
  • Standard loopholes are disallowed.
  • This is , smallest byte count wins.

Here are some small programs to test out your submissions. Before the arrow is the code, after it is the expected result:

  • ! -> 255
  • !>> -> 63
  • !<@ -> 239
  • !nop!&6*! -> 255

Enjoy!

\$\endgroup\$
2
  • \$\begingroup\$ I'm presuming from ! -> 255 that we're to use 8 bits per byte here? The question isn't explicit. \$\endgroup\$ Commented Sep 9, 2015 at 12:10
  • 7
    \$\begingroup\$ @TobySpeight A byte, by definition, is 8 bits. \$\endgroup\$
    – hyperneutrino
    Commented Feb 15, 2016 at 0:30

39 Answers 39

15
\$\begingroup\$

Pyth, 36 35 bytes

u%@[t_G/G2yGi_jGJ16JG)x"!><@"H256z0

Test harness

The internal representation of the accumulator is an integer. This integer is mod-ed by 256 on each iteration, as desired. The operations performed are -G-1, G/2, G*2 and G converted to base 16, reversed, and converted back to base 10, where G is the accumulator.

I missed the line about ignoring everything else. This has been remedied. Thanks, @Dennis.

\$\endgroup\$
4
  • \$\begingroup\$ So -G-1 is shorter than ~G in Pyth? I somewhat doubt that. \$\endgroup\$ Commented Jun 21, 2017 at 1:30
  • \$\begingroup\$ The code in question is actually t_G, where _ is negation and t is -1. In Pyth, ~ means something totally different. \$\endgroup\$
    – isaacg
    Commented Jun 21, 2017 at 1:47
  • \$\begingroup\$ I meant Python ~ (bitwise NOT) \$\endgroup\$ Commented Jun 21, 2017 at 1:48
  • \$\begingroup\$ @CalculatorFeline My point was there is no 1-character function with that effect in Pyth, so the above code (at least for that operation) is as good as it's going to get. \$\endgroup\$
    – isaacg
    Commented Jun 21, 2017 at 1:49
13
\$\begingroup\$

C, 96

Assuming ASCII (or compatible) input:

a;main(c){while(c=getchar()+1)a=(c^34?c^61?c^63?c^65?a:a*257/16:a/2:a*2:~a)&255;printf("%u",a);}

Tidier:

a;
main(c){
  while(c=getchar()+1)
    a=(c^34?
      c^61?
        c^63?
          c^65?
            a
          :
            a*257/16
        :
          a/2
      :a*2:~a
    )&255;
  printf("%u",a);
}

Basically it's just a collection of nested ternary expressions. I'm incrementing the value obtained from getchar() so that an EOF (-1) results in a value of zero and the program exits.

(ideone link)

\$\endgroup\$
7
  • 1
    \$\begingroup\$ I tried the challenge myself and I wrote almost exactly the same code. Btw. your program doesn't drop the bit when shifting upwards (input: !<> should result in 127 and not 255). Either define your a as char, or use the line a&=255 (and use %u) to get the correct effect. Also you can shorten your negation a^255 to ~a. a>>4&15 is also shorter than your (a&240)/16. \$\endgroup\$ Commented Sep 8, 2015 at 12:53
  • \$\begingroup\$ Ah, good point. Turns out it was more efficient to mask out the lower 8 bits at each iteration. \$\endgroup\$
    – r3mainer
    Commented Sep 8, 2015 at 13:10
  • 1
    \$\begingroup\$ In this case you can even use the format string %u instead of %hhu \$\endgroup\$ Commented Sep 8, 2015 at 13:19
  • 1
    \$\begingroup\$ I just saw it now, but you can also use a/16|a*16 instead of a/16|(a&15)*16. The few bits on top get removed by the &255. \$\endgroup\$ Commented Sep 8, 2015 at 13:27
  • 1
    \$\begingroup\$ A tiny improvement: a*257/16 is one byte shorter than a/16|a*16. \$\endgroup\$ Commented Sep 9, 2015 at 12:37
11
\$\begingroup\$

Python 3, 133 bytes

Uses a dictionary to make up for a lack of switch-case syntax in Python. See more here.

a="0"*8
for i in input():a={"!":''.join(str(1-int(b))for b in a),"<":a[1:]+"0",">":"0"+a[:-1],"@":a[4:]+a[:4]}.get(i,a)
print(int(a,2))

The accumulator is a string which is converted into a base 10 number at the end.

Example I/O:

$ python3 bitsnbytes.py
!
255
$ python3 bitsnbytes.py
!>>
63
$ python3 bitsnbytes.py
!<@
239
$ python3 bitsnbytes.py
!nop!&6*!
255
\$\endgroup\$
2
  • \$\begingroup\$ If it was a real, interactive interpreter, it would be for i in sys.stdin: :) \$\endgroup\$
    – Zizouz212
    Commented Sep 7, 2015 at 16:15
  • 5
    \$\begingroup\$ @Zizouz212 I believe you mean if it was interactive; it looks like a real interpreter to me. ;) \$\endgroup\$
    – Alex A.
    Commented Sep 7, 2015 at 16:25
9
\$\begingroup\$

Javascript (ES6), 80 91 90 bytes

a=>[...a].reduce((p,c)=>c=='!'?p^255:c=='<'?p*2%256:c=='>'?p>>1:c=='@'?p/16|0+p%16*16:p,0)

Pretty much as short as it can get. Defines an anonymous function which takes the program as input.

  • For !, takes x XOR 255, as JS's ~ would consider x a 32-bit number.
  • For <, multiplies x by 2 and takes the result mod 256.
  • For >, truly shifts the bits of x 1 bit to the right.
  • For @, floors x/16 and adds it to x%16*16.

Thanks to @vihan for suggesting the use of reduce to save a byte.

\$\endgroup\$
5
  • \$\begingroup\$ You can use < to save around 4 bytes. Using reduce might also save some bytes \$\endgroup\$
    – Downgoat
    Commented Sep 7, 2015 at 16:52
  • 1
    \$\begingroup\$ @vihan Do you mean < in place of ==? If so, that wouldn't work, as no-op characters would incorrectly perform an operation. I used that in my previous, 80-byte solution. \$\endgroup\$ Commented Sep 8, 2015 at 1:26
  • \$\begingroup\$ Isn't ES6 fat arrow standard on PPCG that you have to define it? \$\endgroup\$
    – bren
    Commented Sep 9, 2015 at 0:09
  • \$\begingroup\$ @SpeedyNinja I don't know of any such standard, but if you could point me to a post about one, I'll modify my answer. \$\endgroup\$ Commented Sep 9, 2015 at 3:05
  • \$\begingroup\$ 0+ in p/16|0+p%16*16 does nothing \$\endgroup\$
    – l4m2
    Commented Mar 31 at 2:59
9
\$\begingroup\$

Java (8), 514 483 411 366 359 239 224 229 198 194 187 186 184 182 181 180 177 characters

Wow, this has been golfed down a LOT! Thanks to everyone who gave me suggestions! I greatly appreciate it!

interface T{static void main(String[]g)throws Exception{int i,a=0;while((i=System.in.read())!=10)a=(i==33?255-a:i==62?a/2:i==60?a*2:i==64?a>>4|a<<4:a)%256;System.out.print(a);}}

Golfed 31 (!) bytes by optimizing the nibble swap with bitwise operations as opposed to lengthy Integer.??? methods.

Golfed 72 (!!!!) chars by removing the unnecessary string created to swap nibbles. Much better than before!?

Golfed 45 (!!) chars by removing use of java.util.Scanner and reading from System.in directly. Note that now that the lambda expression is gone, Java 8 is no longer required! Just merely Java 1 would do!

Golfed 7 chars by making class (default) (removed public keyword), thanks to @bmarks

Golfed 120 (!!!!!!!) chars by turning all those lengthy Integer class operations in the bit flipping to 255 - a. Now that's much shorter!

Golfed 15 (!) chars by converting shifts to multiplication and division, removing the braces from the while statement, and making a local within the main method.

Ungolfed 9 =( chars because of a problem with the left shift not discarding the leftmost byte. Therefore, I now do mod (256). The right shift will make the resulting number one bit shorter than before, so there is no need to use mod on right shift. My nibble-swap thing will swap the last 4 bits and the second-last nibble, and the and (&) truncates all other bits. My inversion program doesn't cause any problems if the original number is less than 256.

Golfed 31 35 chars thanks to @Geobits by converting switch statement to a lot of ternary statements, and also converting chars to ints, shortening the literals.

Golfed 7 chars by removing unnecessary &240 in the nibble swap ((a&240)>>4 to a>>4 and converting (a&15)<<4 to a<<4&240. The last change only golfed one character though.

Golfed 1 char by removing unnecessary = in a /= 2, because a = a /= 2 is equivalent to a = a / 2.

Golfed 2 chars by turning println to print.

Golfed 2 chars by removing accidental a= in a=255-a (a=a=255-a is equivalent to a=255-a)

Golfed 1 char by turning a<<4&240 into a%16<<4.

Golfed 1 char by adding brackets to the outside of the ternary statement and doing %256. That way, the %16 is unnecessary in the left-shift part of the nibble swap. The brackets add 2 chars and the %16 saves 3 chars.

Golfed 3 chars by changing class to interface and removing public using Java 8's static interface method feature. Thanks to @TheNumberOne (no comment, but find his answer on "Tips for golfing in Java"

\$\endgroup\$
8
  • \$\begingroup\$ I don't think the class has to be public. Also, I think if you make a an Integer instead of an int, you could do a.parseInt, a.toString, etc. instead of Integer.parseInt,Integer.toString, etc. \$\endgroup\$
    – bmarks
    Commented Sep 8, 2015 at 3:02
  • \$\begingroup\$ Thanks for the first suggestion; I'm going to remove all Integer class methods though. \$\endgroup\$
    – hyperneutrino
    Commented Sep 8, 2015 at 23:18
  • \$\begingroup\$ Perhaps you can do while((i=System.in.read())>10) instead of !=10 to save a byte? \$\endgroup\$
    – bmarks
    Commented Sep 9, 2015 at 0:29
  • \$\begingroup\$ Good idea, but then anything below 10 will cause the program to terminate, and I'm supposed to ignore other characters, not make then the end of the world (or at least my program:)) I'll consider it though; perhaps there are no valid ascii characters below 10. \$\endgroup\$
    – hyperneutrino
    Commented Sep 9, 2015 at 0:33
  • 4
    \$\begingroup\$ It's almost never worth it to use a switch while golfing. The case/break are just too long. You should be able to save a bunch by making the whole thing a ternary; something like a=i=='!'?255-a:i==62?a/2:i=='<'?a*2%256:i=='@'?(a&240)>>4|(a&15)<<4:a; \$\endgroup\$
    – Geobits
    Commented Sep 9, 2015 at 13:51
8
\$\begingroup\$

CJam, 37 bytes

0q{"!><@"#"~ 2/ 2* GmdG*+ "S/=~255&}/

Try it online in the CJam interpreter.

How it works

0                   e# Push 0 (accumulator).
q                   e# Read from STDIN.
{                   e# For each character in the input:
  "!><@"#           e#   Find its index in "!><@" (-1 if not found).
  "~ 2/ 2* GmdG*+ " e#   Push that string.
  S/                e#   Split at spaces to push ["~" "2/" "2*" "GmdG*+" ""].
                    e#     "~"      : signed 64-bit bitwise NOT
                    e#     "2/"     : divide by 2
                    e#     "2*"     : multiply by 2
                    e#     "GmdG*+" : (x) -> (x/16) (x%16) -> (16(x%16) + (x/16))
                    e#     ""       : NOOP
  =~                e#  Select the corresponding string and evaluate it.
  255&              e#  Zero all but the 8 least significant bits.
}/                  e#
\$\endgroup\$
7
\$\begingroup\$

Rust, 121 115 bytes

fn r(s:&str)->u8{let mut n=0u8;for t in s.chars(){match t{'!'=>n=!n,'>'=>n/=2,'<'=>n<<=1,'@'=>n=n>>4|n<<4,_=>()}}n}

Sample run:

fn main() {
    println!("{}", r("!"));    //=> 255
    println!("{}", r("!>>"));  //=> 63
    println!("{}", r("!<@"));  //=> 239
}

Ungolfed:

fn run_ungolfed(s: &str) -> u8 {
    let mut n = 0u8;
    for t in s.chars() {
        match t {
            '!' => n = !n,
            '>' => n >>= 1,
            '<' => n <<= 1,
            '@' => n = (n >> 4) | (n & 15) << 4,
            _ => ()
        }
    }
    n
}

Surprisingly short for Rust. Nothing else really interesting other than the fact that I learned more precedence rules today—who knew (a>>b)|c is the same as a>>b|c?

Shaved off a byte by changing n>>=1 to n/=2; however, the same cannot be done with multiplication, because arithmetic overflow is a panic (i.e. crash) in Rust.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ The precedence thing makes sense when you convince yourself that >> is sort of like division and | is sort of like addition. \$\endgroup\$
    – lynn
    Commented Sep 7, 2015 at 20:23
7
\$\begingroup\$

HP 41C/CV/CX (77 bytes, 42 steps)

Purely for giggles, here it is for the HP 41C/CV/CX calculator. (Requires either the Extended Functions module, or a 41CX for the ATOX function.)

Put your program into the Alpha register, which is a little tricky, as there's no way to enter ! or @ directly from the keyboard (use XTOA with the ASCII codes 33 and 64 respectively to append them).

Steps 08 and 10 allow for ignoring invalid opcodes; remove them to save 2 steps, but the program will crash on invalid input.

01 LBL"BB
02 0
03 LBL A
04 ATOX
05 X=0?
06 GTO E
07 X<>Y
08 SF 25
09 XEQ IND Y
10 CF 25
11 GTO A
12 LBL 33
13 255
14 X<>Y
15 -
16 RTN
17 LBL 60
18 2
19 *
20 256
21 MOD
22 RTN
23 LBL 62
24 2
25 /
26 INT
27 RTN
28 LBL 64
29 RCL X
30 16
31 /
32 INT
33 X<>Y
34 16
35 *
36 256
37 MOD
38 +
39 RTN
40 LBL E
41 RDN
42 RTN
\$\endgroup\$
6
\$\begingroup\$

Python 2, 79 bytes

I realized that I have done something very similar to this in Python earlier. This is just a port of my Ruby answer, but it is incidentally the shortest Python answer as of now :D

a=0
for i in raw_input():a=[~a,a/2,a*2,a*16+a/16,a]["!><@".find(i)]&255
print a

The difference from the Ruby version is that this one doesn't ignore invalid instructions while iterating over the input. Instead I take advantage of the fact that Python tends to return -1 instead of nil when there is no match -- The current value of a is appended to the back of the result array, so that all invalid instructions maps to the same, unchanged value.

\$\endgroup\$
4
\$\begingroup\$

Python 3, 124 94 93 bytes

a=0
for i in input():
 if i in"!><@":a=(i=='!')*(255-a)+(i==">")*a//2+(i=="<")*(a+a)%256+(i=="@")*(16*(a%16)+a//16)
print(a)

"!" is same as subtracting from 255.
"<" is same as multiplying by 2. But 8 bit register means mod 256.
">" is same as integer division by 2.
"@" means shifting last 4 bits (a%16) by 4 bits(*16) and adding the first four bits(a/16).

EDIT (read shameless copying)
Saw the other answer in python (by Beta decay). It uses a really effective way to simulate switch cases using dictionary. Using that we can write

a=0
for i in input():a={"!":255-a,"<":a<<1&255,">":a//2,"@":(a%16)<<4+a>>4}.get(i,a)
print(a)

Thanks, Beta Decay.

\$\endgroup\$
1
  • \$\begingroup\$ No matter what operation you do, you have to reduce mod 256 right? So why not do that at the end: a={"!":255-a,"<":a*2,">":a//2,"@":(a%16)<<4+a>>4}.get(i,a)%256. This immediately saves you a byte (because you'll do a*2 instead of a<<1)...but @daniero's answer also shows that if you do it this way then (a%16)<<4 can be shortened to just a<<4, because any bit 16 or larger will be eliminated once you multiply it by 16 and reduce it mod 256. Nice! Also, you can now replace 255-a by -1-a...or better, by just ~a. Altogether, these suggestions should save you 9 bytes. \$\endgroup\$
    – mathmandan
    Commented Sep 9, 2015 at 6:06
3
\$\begingroup\$

Haskell, 89 bytes

a#'!'=255-a
a#'>'=div a 2
a#'<'=mod(a*2)256
a#'@'=mod(a*16)256+div a 16
a#_=a
f=foldl(#)0

Usage example: f "!>>" -> 63

\$\endgroup\$
3
\$\begingroup\$

Rust, 111 bytes

More of a comment on @Doorknob's answer, but I don't have any rep for comments as I just created an account.

One can shave 10 bytes off his Rust solution with the following:

fn r(s:&str)->u8{let mut n=0u8;for t in s.chars(){n=match t{'!'=>!n,'>'=>n>>1,'<'=>n<<1,'@'=>n>>4|n<<4,_=>n}}n}
\$\endgroup\$
1
3
\$\begingroup\$

Python 3, 127 bytes

Edit: shorting, thanks @Jakube

Edit2: fix, thanks @Anachor

a=0
for i in input():a=(a^255if i=="!"else a>>1if i==">"else a<<1if i=="<"else(a&15)<<4|(a&240)>>4if i=="@"else a)&255
print(a)
\$\endgroup\$
3
  • \$\begingroup\$ Maybe this is because windows' new line. That's plus two bytes. I'll use that byte counter next time. :-) Thanks. \$\endgroup\$
    – uno20001
    Commented Sep 7, 2015 at 18:32
  • \$\begingroup\$ Note that this doesn't discard the leftmost bit when left shifting, so !< gives 510 while it should be 254 \$\endgroup\$
    – Rohcana
    Commented Sep 7, 2015 at 18:48
  • \$\begingroup\$ I hope now it does. Sorry for my mistakes, this is my first "golf" challenge. \$\endgroup\$
    – uno20001
    Commented Sep 7, 2015 at 19:05
3
\$\begingroup\$

Ceylon, 297 290

shared void y(){value t=process.readLine()else"";variable Byte a=0.byte;for(c in t){switch(c)case('!'){a=a.not;}case('>'){a=a.rightLogicalShift(1);}case('<'){a=a.leftLogicalShift(1);}case('@'){a=a.and(#f0.byte).rightLogicalShift(4).xor(a.and(#f.byte).leftLogicalShift(4));}else{}}print(a);}

Formatted:

shared void y() {
    value t = process.readLine() else "";
    variable Byte a = 0.byte;
    for (c in t) { switch (c)
        case ('!') { a = a.not; }
        case ('>') { a = a.rightLogicalShift(1); }
        case ('<') { a = a.leftLogicalShift(1); }
        case ('@') { a = a.and(#f0.byte).rightLogicalShift(4).xor(a.and(#f.byte).leftLogicalShift(4)); }
        else {} }
    print(a);
}

#f and #f0 are hexadecimal numbers for the nibbles, .byte converts an integer into a byte. I'm lucky that Byte's .string attribute already uses the unsigned representation of a byte. Ceylon also features a switch statement without fall-through, and a string is a list of characters, which can be iterated.

I also tried to cut those long shift method names down by using an aliasing import, but this actually becomes 7 bytes longer:

import ceylon.language{Byte{r=rightLogicalShift,l=leftLogicalShift}}shared void x(){value t=process.readLine()else"";variable Byte a=0.byte;for(c in t){switch(c)case('!'){a=a.not;}case('>'){a=a.r(1);}case('<'){a=a.l(1);}case('@'){a=a.and(#f0.byte).r(4).xor(a.and(#f.byte).l(4));}else{}}print(a);}

Formatted:

import ceylon.language {
    Byte {
        r=rightLogicalShift,
        l=leftLogicalShift
    }
}
shared void x() {
    value t = process.readLine() else "";
    variable Byte a = 0.byte;
    for (c in t) {
        switch (c)
        case ('!') { a = a.not; }
        case ('>') { a = a.r(1); }
        case ('<') { a = a.l(1); }
        case ('@') { a = a.and(#f0.byte).r(4).xor(a.and(#f.byte).l(4)); }
        else {}
    }
    print(a);
}

This might be useful if we need those methods a bit more often.

\$\endgroup\$
3
\$\begingroup\$

Ruby, 81 73 bytes

So much simpler -- no eval! For each valid character in the input, it evaluates each instruction, and finds the appropriate instruction through the index of $& (the current character in the input).

a=0
gets.scan(/[!><@]/){a=[~a,a/2,a*2,a*16+a/16]["!><@".index$&]&255}
p a
\$\endgroup\$
4
  • 1
    \$\begingroup\$ That's genius. Much shorter that any other way. 2 upvotes by me! \$\endgroup\$
    – edc65
    Commented Sep 9, 2015 at 6:44
  • \$\begingroup\$ How can you double upvote...? \$\endgroup\$
    – hyperneutrino
    Commented Sep 12, 2015 at 15:40
  • \$\begingroup\$ @JamesSmith He's probably referring to this and my python answer :) \$\endgroup\$
    – daniero
    Commented Sep 12, 2015 at 17:46
  • \$\begingroup\$ @danerio I see. \$\endgroup\$
    – hyperneutrino
    Commented Sep 12, 2015 at 17:54
3
\$\begingroup\$

JavaScript (ES6), 76 81

As an unnamed function returning the accumulator value

This is a porting of the super clever answers by @daniero (that have way too few upvotes)

Bonus: you can pass an initial value of the accumulator. If not passed, starting value is 0 as by specific.

(p,a)=>(p.replace(/[!<>@]/g,i=>a=(i<'<'?~a:i<'>'?a*2:i<'@'?a/2:a*257/16)&255),a)

Test running the snippet below in any EcmaScript 6 browser (I tested in Firefox)

f=(p,a)=>[...p].map(c=>a=255&[a,~a,a*2,a/2,a*257/16][1+'!<>@'.indexOf(c)])|a

// TEST
out=x=>O.innerHTML+=x+'\n'

function go(x) { out(x+' -> '+f(x)) }

go('!'),go('!>>'),go('!<@'),go('!nop!&6*!')

// LESS GOLFED
F=(p,a)=>// a as a parameter, if not passed its value starts as undefined, then becomes NaN, but the operators '&' and '~' treat it as 0
  [...p].map(c => // execute following function for each character p
    a = 255 & // any intermediate result is converted to numeric and truncate to a byte          
   // evaluate all possible results (then choose one bases on the current character)
   [a,   // NOP, if unexpected char 'a' remains the same
    ~a,  // tilde == binary not (will give a result wider than a byte)
    a*2, // < shift left is *2 (can give a result wider than a byte) 
    a/2, // > shift right is /2 (can give a non integer result)
    a *257 / 16  // move nibbles around (will give a result wider than a byte)
   ] // array of all results
   [1+'!<>@'.indexOf(c)] // find index to get the correct result
  ) // end map, returns an array in any case
    // eventually a single element array containg a
  | a // return accumulator
Test program:<input id=I><button onclick='go(I.value)'>go</button>
<pre id=O></pre>

\$\endgroup\$
2
\$\begingroup\$

STATA, 197 bytes

di _r(a)
gl b=0
forv x=1/`=length("$a")'{
gl c=substr("$a",`x',1)
if"$c"=="!" gl b=255-$b
if"$c"==">" gl b=int($b/2)
if"$c"=="<" gl b=mod($b*2,256)
if"$c"=="@" gl b=mod($b,16)*16+int($b/16)
}
di $b

Ungolfed

display _request(a) //get the input via prompt and put in var a
global b=0 //initialise A to be 0
forv x=1/`=length("$a")'{ //for loop from 1 to last char in a
global c=substr("$a",`x',1) //get the char at index x in a
if "$c"=="!" global b=255-$b //invert is the same as 255-A
if "$c"==">" global b=int($b/2) //right shift is the same as A/2 (with integer division)
if "$c"=="<" global b=mod($b*2,256) //left shift is the same as A*2%256
if "$c"=="@" global b=mod($b,16)*16+int($b/16) //nibble swap is the same as A%16*16+A/16
}
display $b //display the result of A

Does not work with the online interpreter and requires the non-free default interpreter. This would be somewhat easier with actual bitwise operations, but I don't think they're too useful for most of the common uses of STATA.

\$\endgroup\$
1
  • \$\begingroup\$ Why doesn't the online interpreter work? \$\endgroup\$ Commented Jun 21, 2017 at 3:23
2
\$\begingroup\$

JavaScript, 104

[].reduce.call(prompt(),function(a,i){return(i=='!'?~a:i=='>'?a/2:i=='<'?a*2:i=='@'?a>>4|a<<4:a)&255},0)

Nested ternary operators map to instructions.

BITWISE AND is used to constrain our Number type to a single byte.

\$\endgroup\$
2
\$\begingroup\$

Julia, 117 94 86 73 bytes

p->(a=0x0;[a=c==33?~a:c==60?a<<1:c==62?a>>1:c!=64?a:a<<4|a>>4for c=p];1a)

This is an anonymous function that accepts a string and returns an integer. To call it, assign it to a variable.

Ungolfed:

function f(p)
    # Initialize the accumulator to 0 as an 8-bit unsigned integer
    a = 0x0

    # Loop over the characters in the input
    for c in p
        a = c == 33 ? ~ a :        # '!'
            c == 60 ? a << 1 :     # '<'
            c == 62 ? a >> 1 :     # '>'
            c != 64 ? a :          # no-op
            a << 4 | a >> 4        # '@'
    end

    # Convert the accumulator to a regular integer and return
    return Int(a)
end

Saved 8 bytes thanks to Sp3000 and 13 thanks to Dennis!

\$\endgroup\$
2
\$\begingroup\$

Forth (gforth), 217

: o over ; : x 0 begin key dup emit swap o 13 = if . exit else o 33 = if invert else o 62 = if 1 rshift else o 60 = if 1 lshift else o 64 = if dup 4 lshift swap 4 rshift or then then then then then nip 255 and again ;

Not as short as I had hoped but oh well. I'm sure this can be golfed further. There doesn't seem to be any alternatives to if/elseif :/

Formatted / ungolfed:

: x
  0 ( accumulator )
  begin
    key dup emit swap ( read char, print it and stash it away )
         over 13 = if . exit ( on newline, print accumulator and return. )
    else over 33 = if invert ( inversion )
    else over 62 = if 1 rshift ( shift 1 right )
    else over 60 = if 1 lshift ( shift 1 left )
    else over 64 = if dup 4 lshift swap 4 rshift or ( swap )
    then then then then then
    nip ( remove read character )
    255 and ( constrain accumulator to 1 byte after each step )
  again
;
\$\endgroup\$
2
\$\begingroup\$

AWK -

  • instead of doing both an upshift and downshift for @, this uses the trick about % 255 instead of % 256

    unlike standard nomenclature that calls it left-shift and right-shift that describes what a computer is doing to the bits,

    which also un-intuitively requires flipping the direction of the number line mentally when dealing with 2's-complement negatives - since the "direction" of both positive and negative infinity is left hand side,

    I prefer using the terms up-shift and down-shift since they actually describe what we're doing to the numbers themselves that equally applies to unsigned as well as 2's-complement negatives, since we're upping the magnitude of the value or drawing it down.

    it's the same approach when describing manual gear shifting in sports cars, whether the manufacturer implemented it in the traditional multi-up-down design, clicking mini-tabs at the wheel, a circular knob, or a linear slider on some touch-screen.

    while it's true that neither up-shift nor down-shift provide insight to wrap-around effects of signed integer types, the same is also true for left-shift and right-shift.

  • the main for(..) loop performs all calculations arithmetically instead of using any bitwise ops

  • it uses upfront regex to scrub out self-cancelling actions, such as consecutive double swaps or double inverts

  • p.s. +++ isn't some strange undocumented operator in awk - that's just _ + ++_^_ that awk allows per POSIX specs, and since both left and right hand side of the + refer to the same variable (_), it matters not whether it got parsed as _++ + _^_ or _ + ++_^_ since the effects are absolutely identical

one can write fully POSIX-compliant awk code without using a single semi-colon (;)

 echo '
    ! -> 255
    !>> -> 63
    !<@ -> 239
    !nop!&6*! -> 255' |

gawk 'function _______(__,___,____,_____,_) {
  
  _ = "^[^!]+|@@|!!|[^!"(_____ = "<>@")"]+"
  while(gsub(_,___,__)) { }
  _ += ++_+_
  
  if (__ < "! ")
      return (_+++_^_-_)*!!__

  split(substr(__,--_),____,___)
  __ = ___ = _+_^_^++_-_
  
  for(_ in ____)___ = (_=index(_____,____[_]))<=!!_ ? (_ ?(___+___) % (_+__) \
      : __-___) : _+_==_*_ ? (___-___%_)/_ : ___<__ ? ++_*___*_%__ : ___
  return ___ 

} ($++NF = _______($!_))^_'

! -> 255 255
!>> -> 63 63
!<@ -> 239 239
!nop!&6*! -> 255 255

# gawk profile, created Tue Apr  2 07:15:18 2024

# Rule(s)

 4  ($++NF = _______($!_))^_ { # 4
 4      print
     }


# Functions, listed alphabetically

 4  function _______(__, ___, ____, _____, _)
    {
 4      _ = "^[^!]+|@@|!!|[^!" (_____ = "<>@") "]+"
 2      while (gsub(_, ___, __)) { }

 4      _ += ++_ + _
 4      if (__ < "! ")
 2          return (_+++_^_-_) * !!__

 2      split(substr(__, --_), ____, ___)
 2      __ = ___ = _+_^_^++_-_

 4      for (_ in ____)
 4          ___ = (_ = index(_____,____[_])) <= !!_? (_? (___+___) % (_+__) :\
            __-___) : _+_ == _*_ ? (___-___%_)/_ : ___<__ ? ++_*___*_%__ : ___

 2      return ___
     }
\$\endgroup\$
1
\$\begingroup\$

Crystal, 139 bytes

def f x
b=0_u8
x.chars.each do|c|
b=case c
when'!'
~b
when'>'
b>>1
when'<'
b<<1
when'@'
b<<4|b>>4
else raise ""
end
end
puts b
end
\$\endgroup\$
1
\$\begingroup\$

C# 193

void Main(){byte a=0;foreach(var c in Console.ReadLine()){if(c=='!')a=(byte)~a;if(c=='>')a=(byte)(a>>1);if(c=='<')a=(byte)(a<<1);if(c=='@')a=(byte)(((a&240)>>4)|((a&15)<<4));}Console.Write(a);}
\$\endgroup\$
2
  • 2
    \$\begingroup\$ Don't you need using System; or something like that to access Console.ReadLine and Console.Write without the System. prefix? \$\endgroup\$
    – Alex A.
    Commented Sep 7, 2015 at 16:30
  • \$\begingroup\$ Also it seems to me that you shouldn't have to cast to byte for each operation but I could be wrong. \$\endgroup\$
    – Alex A.
    Commented Sep 7, 2015 at 17:22
1
\$\begingroup\$

Lua, 344 char

a=string.rep("0",8)
t=io.read()
f={["!"]=function()local s="";for j=1,8 do s=s..(a:sub(j,j)=="0"and"1"or"0") end;return s end,[">"]=function() return "0"..a:sub(1,7) end,["<"]=function()return a:sub(2,8).."0"end,["@"]=function()return a:sub(5,8)..a:sub(1,4)end}
for i=1,#t do a=(f[t:sub(i,i)]or function()return a end)()end
print(tonumber(a,2))

Inspired by @Beta Decay's use of a string accumulator, seeing as lua has no byte type. Could probably be golfed more by using fewer functions.

\$\endgroup\$
1
\$\begingroup\$

R, 194 bytes

b<-readline();A<-rep(0,8);s<-strsplit(b,"")[[1]];for(r in s){if(r=="!")A<-(A+1)%%2;if(r==">")A<-c(0,A)[1:length(A)];if(r=="<")A<-c(A,0)[-1];if(r=="@")A<-c(A[5:8],A[1:4])};print(sum(A*(2^(7:0))))

ungolfed

b <- readline()
A <- rep(0, 8) 
s <- strsplit(b, "")[[1]]
for (r in s) {
    if (r == "!")
        A <- (A + 1) %% 2
    if (r == ">")
        A <- c(0, A)[1:length(A)]
    if (r == "<")
        A <- c(A, 0)[-1]
    if (r == "@")
        A <- c(A[5:8], A[1:4])
}
print(sum(A*(2^(7:0))))
\$\endgroup\$
2
  • \$\begingroup\$ All the <- can be replaced by = here, thus reducing the code by 7 bytes. Additionally you might be able to replace the series of if statements by one call to switch (as in A=switch(r,"!"=(A+1)%%2, ...)) \$\endgroup\$
    – plannapus
    Commented Apr 20, 2016 at 7:08
  • \$\begingroup\$ The resulting b=readline();A=rep(0,8);s=strsplit(b,"")[[1]];for(r in s)A=switch(r,"!"=(A+1)%%2,">"=c(0,A)[1:length(A)],"<"=c(A,0)[-1],"@"=c(A[5:8],A[1:4]),A);print(sum(A*(2^(7:0)))) is 167 bytes. \$\endgroup\$
    – plannapus
    Commented Apr 20, 2016 at 7:17
1
\$\begingroup\$

RPL, 170.5 bytes

The input should be entered as a string on level 1.

\<< DEC 8 STWS \-> S 
    \<< #0d 1 S SIZE 
        FOR I "!><@" S I DUP SUB POS 1 + { \<< \>> NOT SR SL \<< DUP #16d / SWAP #16d * + \>> } SWAP GET EVAL NEXT \>> 
\>>
\$\endgroup\$
1
\$\begingroup\$

K, 57 bytes

It's a start:

0{y+2*x}/(8#0){((~:;{-1_0,x};{1_ x,0};4!;{x})"!><@"?y)x}/

tested using Kona:

  f:0{y+2*x}/(8#0){((~:;{-1_0,x};{1_ x,0};4!;{x})"!><@"?y)x}/
...
  f'("!";"!>>";"!<@";"!nop!&6*!")
255 63 239 255

I might be able to do better in k5, but it's a complex series of tradeoffs- for example, converting binary to decimal is as easy as 2/, but the behavior of ? makes it harder to handle a default case for instruction lookup.

\$\endgroup\$
1
\$\begingroup\$

PHP, 189 bytes

<? $c='00000000';foreach(str_split($argv[1])as$a){$a=='!'&&$c=strtr($c,'01','10');$a=='<'&&$c=substr($c.'0',1);$a=='>'&&$c=substr('0'.$c,0,8);$a=='@'&&$c=substr($c.$c,4,8);}echo bindec($c);

It's not that it gonna beat many answers, it's only for practice

\$\endgroup\$
1
\$\begingroup\$

HPPPL, 302 294 bytes

#pragma mode(separator(.,;)integer(d8))EXPORT b()BEGIN print();local p,j,a;a:=#0d;INPUT({{p,[2]}});for j from 1 to dim(p)do c:=p(j);case if c==33 then a:=BITNOT(a)end if c==62 then a:=BITSR(a,1)end if c==60 then a:=BITSL(a,1)end if c==64 then a:=BITSL(a,4)+BITSR(a,4)end end;end;print(a*1);END;

Ungolfed:

// make sure integers are unsigned 8 bit decimal numbers
#pragma mode( separator(.,;) integer(d8) ) 
EXPORT b()
BEGIN
  print();
  local p,j,a;
  a:=#0d;                         // set a to integer value 0
  INPUT({{p,[2]}});               // open input dialog treating input as string ( type [2])
  for j from 1 to dim(p) do
    c:=p(j);
    case
      if c==33 then a:=BITNOT(a) end             // !
      if c==62 then a:=BITSR(a,1) end            // >
      if c==60 then a:=BITSL(a,1) end            // <
      if c==64 then a:=BITSL(a,4)+BITSR(a,4) end // @
    end;
  end;
  print(a*1); // converts to proper output by promoting to non integer format
              // print(a) would result in
              // #239:8d for 239 if the default bit size is not set to 8 bits decimal
              // indicating an 8 bit unsigned decimal integer, or
              // #239d if the default bit size is already set to 8 bits decimal

END;

HPPPL Input command

HPPPL Output to Terminal

This answer ensures that the HP Prime uses unsigned 8 bit integers even if the mode is set to e.g. 64 bits by the user. If the calculator is set up manually to using unsigned 8 bit decimal integers, then the pragma command can be omitted. If the output does not need to follow the format strictly then the a*1 at the end can simply be a. Multiplying the result by 1 just ensures the output does not follow the internal output for integer values. The print command in line 4 can also be omitted if the terminal does not need to be cleared before printing out the result. If passing the program as a string argument is allowed, then the INPUT command can be omitted as well.

This is the shortest version with input and proper output, without the pragma argument (if the calculator is set to Uint8 by default:

243 bytes:

EXPORT b()BEGIN local p,j,a;a:=#0d;INPUT({{p,[2]}});for j from 1 to dim(p)do c:=p(j);case if c=33 then a:=BITNOT(a)end if c=62 then a:=BITSR(a,1)end if c=60 then a:=BITSL(a,1)end if c=64 then a:=BITSL(a,4)+BITSR(a,4)end end;end;print(a*1);END;
\$\endgroup\$
1
\$\begingroup\$

Perl 6, 96 89 bytes

{my $a=0;$a=(+^*,*+<1,*+>1,{$_+<4+$_+>4},{$_})["!<>@".index($_)//4]($a)%256 for .comb;$a}

Old solution:

{my $a=0;$a=(255-*,*+<1+&255,*+>1,{$_+&15+<4+$_+>4},{$_})["!<>@".index($_)//4]($a)for .comb;$a}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.