195
\$\begingroup\$

In mathematics an exclamation mark ! often means factorial and it comes after the argument.

In programming an exclamation mark ! often means negation and it comes before the argument.

For this challenge we'll only apply these operations to zero and one.

Factorial
0! = 1
1! = 1

Negation
!0 = 1
!1 = 0

Take a string of zero or more !'s, followed by 0 or 1, followed by zero or more !'s (/!*[01]!*/).
For example, the input may be !!!0!!!! or !!!1 or !0!! or 0! or 1.

The !'s before the 0 or 1 are negations and the !'s after are factorials.

Factorial has higher precedence than negation so factorials are always applied first.
For example, !!!0!!!! truly means !!!(0!!!!), or better yet !(!(!((((0!)!)!)!))).

Output the resultant application of all the factorials and negations. The output will always be 0 or 1.

Test Cases

0 -> 0
1 -> 1
0! -> 1
1! -> 1
!0 -> 1
!1 -> 0
!0! -> 0
!1! -> 0
0!! -> 1
1!! -> 1
!!0 -> 0
!!1 -> 1
!0!! -> 0
!!!1 -> 0
!!!0!!!! -> 0
!!!1!!!! -> 0

The shortest code in bytes wins.

\$\endgroup\$
18
  • 27
    \$\begingroup\$ But 0!=1!, so what's the point of handling multiple factorials? \$\endgroup\$
    – boboquack
    Feb 6, 2017 at 9:22
  • 39
    \$\begingroup\$ @boboquack Because that's the challenge. \$\endgroup\$ Feb 6, 2017 at 9:24
  • 14
    \$\begingroup\$ <?='1'; ... correct 75% of the time in php. \$\endgroup\$
    – aslum
    Feb 6, 2017 at 17:17
  • 13
    \$\begingroup\$ I may be wrong here but can't any number with any factorials after it simply be removed and replaced with 1? Like 0!!!! = 1!! = 0!!!!!!!! = 1!!! = 1! = 0! = 1 etc \$\endgroup\$ Feb 6, 2017 at 22:33
  • 3
    \$\begingroup\$ @AlbertRenshaw That is correct. \$\endgroup\$ Feb 6, 2017 at 22:54

64 Answers 64

2
\$\begingroup\$

Batch, 62 bytes

@set/ps=
@set s=%s:0!=1%
@set s=%s:!!=%
@cmd/cset/a%s:1!=1%

Takes input on STDIN. Batch actually understands leading !s correctly for this challenge, but the trailing !s need to be dealt with, which takes three steps:

  • Change 0! to 1
  • Delete pairs of !! (this is safe for the !!s before the digit too)
  • Delete any remaining trailing ! (which by now can only be after a 1)
\$\endgroup\$
2
\$\begingroup\$

Pyth, 11 bytes

s.v:z"0!"\1

Try it online!

Explanation

s.v:z"0!"\1
   :         Replace...
    z        in the input...
     "0!"    the string "0!"...
         \1  with the string "1".
 .v          Evaluate the result. Since only the first expression is evaluated,
             anything after the number will be ignored.
s            Convert the result to an integer and implicitly print it.
             This is necessary because ! returns True/False, not 0/1.
\$\endgroup\$
2
\$\begingroup\$

PHP 7.1, 58 55 54 37 35 bytes

Note: uses IBM-850 encoding

echo!!$argn[-1]^strspn($argn,~Ì)%2;

Run like this:

echo '!!!0!!!!' | php -nR 'echo!!$argn[-1]^strspn($argn,~Ì)%2;';echo
> 0

Explanation

echo
  strspn($a=$argv[1],~Ì) # Count the number of leading exclamation marks.
  % 2                    # Make 0 (even) or 1 (odd).
  ^ !!$a[-1];            # Negate with factorial part (truthy value of the 
                         # last char):
                         # - "0" is considered falsy.
                         # - "1" or "!" is considered truthy.

Tweaks

  • Saved 3 bytes by using IBM-850 encoding
  • Saved a byte by changing the regex slightly
  • Saved 17 bytes, new version without long function names and return
  • Saved 2 bytes by using -R (which makes $argn available)
\$\endgroup\$
2
\$\begingroup\$

Japt, 11 bytes

+OxUe/\d!/1

Try it online!

How it works

+OxUe/\d!/1

   Ue        Apply recursive replace to input string...
     /\d!/1    which replaces digit+! to 1
 Ox          Eval the result as vanilla JS
+            Cast the result (String or Boolean) to Number

The idea is similar to Arnauld's JS answer though I came up with it independently.

\$\endgroup\$
1
  • \$\begingroup\$ You could use the -N flag to get rid of the +. \$\endgroup\$
    – Shaggy
    Sep 15, 2021 at 11:59
2
\$\begingroup\$

Scala, 65 63 47 bytes

s=>s.takeWhile(34>).length%2^(s.last-48).abs%14

Try it online!

Many thanks to user for -16 chars!!!

\$\endgroup\$
2
  • \$\begingroup\$ Great answer. You can also use ascii values to get 59 bytes \$\endgroup\$
    – user
    Oct 16, 2020 at 13:26
  • \$\begingroup\$ 47 bytes, actually \$\endgroup\$
    – user
    Oct 16, 2020 at 13:58
2
\$\begingroup\$

Python, 183 159 125 bytes

-34 bytes thanks to @wasif

Probably not going to beat anyone, but it was fun.

g=lambda x:x<2or x*f(~-x);from re import*;a,b,c=split("(\d+)",input())
exec("b=g(int(b));"*len(c)+"b=not b;"*len(a));print(b)

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ You can replace n=factorial(n) with just n=1 (and therefore remove the math import). Similarly, n=not n with n=1-n and remove the int part later. The first for loop could be an ir statement (or some fancy logic in the initialisation of n) and the import is shorter if you just do import re \$\endgroup\$
    – Jo King
    Sep 17, 2021 at 21:15
  • \$\begingroup\$ 125 bytes! (outputting True for 1 and False for 0 is allowed) golfing it more will make it identical to other answers \$\endgroup\$
    – Wasif
    Sep 23, 2021 at 16:49
1
\$\begingroup\$

IBM/Lotus Notes Formula - 77 bytes

@Eval(@Left(a;@If(@Like(a;"%1%");"1";"0"))+@If(@Ends(a;"!");"1";@Right(a;1)))

There is no TIO for Notes Formula so a screenshot of all test cases is shown below:

All Test Cases

How it works

@Eval() evaluates a string as an expression

First we check if the input string in field (input) a contains 1 or 0 and take all characters to the left of whichever it is which will be a string of ! characters. We don't care how many. @Eval() will take care of that.

Next we look to see if there is a ! at the end of the string. If there is we append 1 to the ! string (0! and 1! are both 1 - it doesn't matter how many ! characters there are at the end) otherwise we append the last character unchanged because it is not a ! and could be either a 1 or a 0.

We now have a string containing the leading inversions plus a number defined by whether there are any factorial characters so we can feed this to @Eval() and get the results above.

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

Bean, 24 bytes

Hexdump:

00000000 26 4a c1 53 a0 17 53 d0 80 a0 5d 20 80 0a a1 80  &JÁS .SÐ. ] ..¡.
00000010 81 00 25 3a ae a1 ab 24                          ..%:®¡«$
00000018

Equivalent JavaScript:

+eval(a.replace(/.!+$/,1))

Sorry for stepping on your toes, Arnauld.

Explanation:

Takes first line of input as unformatted string in a, and replaces any digit followed by one or more ! with 1, so that the rest can be eval'd by JavaScript.

Try the demo, or the test suite

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

C#, 88 84 bytes

Saved 4 bytes thanks to TheLethalCoder.

s=>{var c=s.Replace("!","")[0];int b=s.IndexOf(c);return(s.Length>++b?b:b+c-49)%2;};

Previous version:

s=>{var c=s.Replace("!","")[0];int b=s.IndexOf(c),n=s.Length-b>1?1:c-48;return(n+b)%2;};

Full program with commented method and test cases:

using System;

class MathIsFactProgrammingIsNot
{
    static void Main()
    {
        Func<string, int> f =
        s=>
        {
            // removes all the exclamation marks and extracts the 0 or 1 digit
            var c = s.Replace("!","")[0];

            // number of exclamation marks before the digit
            int b = s.IndexOf(c),
            
            // the number of exclamation marks after the digit increased by 1 (because of the digit)
                n = s.Length - b > 1 ? 1 : c-48;
            // if no exclamation marks are present, converts the digit from the string to an integer
            
            return (n + b) % 2;   // applies binary negation
        };

        // test cases:
        Console.WriteLine(f("0"));  // 0
        Console.WriteLine(f("1"));  // 1
        Console.WriteLine(f("0!")); // 1
        Console.WriteLine(f("1!")); // 1
        Console.WriteLine(f("!0")); // 1
        Console.WriteLine(f("!1")); // 0
        Console.WriteLine(f("!0!"));    // 0
        Console.WriteLine(f("!1!"));    // 0
        Console.WriteLine(f("0!!"));    // 1
        Console.WriteLine(f("1!!"));    // 1
        Console.WriteLine(f("!!0"));    // 0
        Console.WriteLine(f("!!1"));    // 1
        Console.WriteLine(f("!0!!"));   // 0
        Console.WriteLine(f("!!!1"));   // 0
        Console.WriteLine(f("!!!0!!!!"));   // 0
        Console.WriteLine(f("!!!1!!!!"));   // 0
    }
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ n is only used in the return so you can remove declaring it. \$\endgroup\$ Feb 7, 2017 at 15:59
1
\$\begingroup\$

PowerShell, 28 bytes

+($args-replace'\d!+',1|iex)

Try it online!

Explanation

Replace any digit followed by 1 or more ! with 1 (to solve the factorials), then just execute the remaining string which is valid code. The result will be boolean so I use unary + to convert it to a number.

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

F#, 69 48 Bytes

let rec f=function|'!'::t->1-f t|'0'::[]->0|_->1

Try it online!

Tests

let test (input,expected) = 
  let result = input |> Seq.toList |> f
  if result = expected then
    printfn "%s = %d" input result
  else
    printfn "Error at %s" input

[
  ("0", 0)
  ("1", 1)
  ("0!", 1)
  ("1!", 1)
  ("!0", 1)
  ("!1", 0)
  ("!0!", 0)
  ("!1!", 0)
  ("0!!", 1)
  ("1!!", 1)
  ("!!0", 0)
  ("!!1", 1)
  ("!0!!", 0)
  ("!!!1", 0)
  ("!!!0!!!!", 0)
  ("!!!1!!!!", 0)
] |> Seq.iter test
\$\endgroup\$
2
1
\$\begingroup\$

Befunge-98 (PyFunge), 22 20 bytes

Golfed off 2 bytes because I realized that if I used k instead of j to do the logical notting to account for a 0 without a factorial, I didn't have to mod the ASCII value of 0 or 1 by 2. I did have to move the code because removing the 2% left a hole between the $~ and #< previously.

-kv$!~:'!
#<k!.@.$$~

Try it online!

Explanation

The first line:

-kv$         Does nothing because the top of the stack is 0
    !        Nots the top, so we start with a value of 1
     ~       Gets a character from input
-     :'!    Pushes (that character - the value of '!')
 kv          If that value is not 0 (the character was not '!'), go to the next line
   $!        If it is, Throw away the extra '!' and not the number below it (originally 1)
             Repeat from the ~

Now that we're on the second line, we have notted 1 for each ! before the number. If there is a ! after the number, we can just print this value, but if there isn't we need to adjust for whether or not the number is 0.

The second line:

 <            Directs the IP left.
#             Doesn't skip anything because it's at the beginning of a line
         ~    If we reached EOF (no factorials), the ~ will reverse the IP's direction
       $$     No EOF: Drop the '!' we just read along with the number
     @.               Print (1 notted the appropriate amount of times) and end
#<            EOF: Wrap around and skip the arrow
  k!               Not the top n + 1 times, where n is the ASCII value of 0 or 1 (48 or 49)
                       If the number is 1, it will be notted 50 times (even),
                       yielding no change.
                       If the number is 0, we not it 49 times (odd), which makes up for
                       starting with a 1 at the beginning.
    .@             Print this value and exit
\$\endgroup\$
1
  • \$\begingroup\$ Can you save a couple of bytes by outputting via exit code? \$\endgroup\$
    – Jo King
    Jan 15, 2018 at 1:30
1
\$\begingroup\$

Vim + bc, 18 bytes

:s/\d!\+/1␊V!bc␊

is a literal newline

Explanation

:s/\d!\+/1␊  Replace any digit followed by factorials with 1 ("0!!!" -> "1"; "1!!" -> "1")
V!bc␊        Evaluate the not-operators using the `bc` command, similarly to this answer

Vim, 36 bytes

:s/\d!\+/1␊:s/!!//g␊:s/!1/0␊:s/!0/1␊

is a literal newline

Explanation

:s/\d!\+/1␊  Replace any digit followed by factorials with 1 ("0!!!" -> "1"; "1!!" -> "1")
:s/!!//g␊    Remove all double nots ("!!!!!" -> "!"; "!!!!!!" -> "")
:s/!1/0␊     Replace !1 with 0
:s/!0/1␊     Replace !0 with 1
\$\endgroup\$
1
\$\begingroup\$

C (gcc), 42 bytes

c;e(char*a){c=*a<34?!e(a+1):*a-48|1[a]%2;}

Try it online!

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

GolfScript, 11 bytes

Blatant port (not copying the whole algorithm) of Martin Ender's CJam answer. At least I got the same length.

.)\;48=!\~;

Try it online!

Explanation

.           # Add a fresh copy of the input
 )          # Generate the input without the last item 
            # and the last item of the input
  \         # Swap so that the first output of ) is on top
   ;        # Remove so that there is only the last item
    48=     # Is the item equal to 48 (ASCII '0') ?
       !    # If not (0), there are !'s before either 0 or 1
            # and the result is obviously 1 (0 negated)
            # If yes (1), the last item is going to be 0,
            # and the result is 0 (1 negated).
        \   # Take the fresh unused copy of the input to the top
         ~  # Apply the input to the top
          ; # (Due to postfix evaluation the trailing
            # !'s are applied to the number.)
            # Discard the applied number, which is garbage

# Implicitly output the result
```
\$\endgroup\$
1
\$\begingroup\$

Rust macros, 69 bytes

macro_rules!f{(!$($x:tt)*)=>{1-f!($($x)*)};(0)=>{0};($($x:tt)*)=>{1}}

Defined a macro f that takes a sequence of tokens (including !, 0 and 1) as input and produces a token sequence that evaluates to the expected result. Port of a Haskell answer.

try it online

Explanation

macro_rules! f {
    (! $($x:tt)*) => {  // match an exclamation mark followed by any number of token trees
        1 - f!($($x)*)  // expand to 1- and call the macro recursively
    };    
    (0) => {            // match a 0 that's not followed by anything
        0               // replace with a 0
    };
    ($($x:tt)*) => {    // match any number of token trees
        1               // replace with 1
    }
}
\$\endgroup\$
1
\$\begingroup\$

Python 2, 37 bytes

f=lambda s:s<"0"and 1-f(s[1:])or"0"<s

Try it online!

Sometimes returns True/False instead of 0/1, which is allowed I think.

How

  • The factorial part can be evaluated simply as "0"<s. This is 0 only when s is 0, and 1 if s is anything else (e.g 1 or 0!!).
  • The negation part is evaluated using recursion. If s starts with ! (s<"0"), recurs as 1-f(s[1:]).
\$\endgroup\$
1
  • \$\begingroup\$ You can shorten the and part to s<"0">1>f(s[1:]) if you don't mind it always being True/False \$\endgroup\$
    – Jo King
    Sep 17, 2021 at 21:24
1
\$\begingroup\$

R, 41 bytes

+eval(parse(t=gsub("\\d!+",1,scan(,""))))

Try it online!

Two and a half years later, finally fixed the bug pointed out by JayCe, by switching * in the regex to a +...

The + is just to coerce the logical to numeric.

\$\endgroup\$
4
  • \$\begingroup\$ For some reason it's not working when I test it. What about this? \$\endgroup\$
    – JayCe
    May 18, 2018 at 16:46
  • \$\begingroup\$ @JayCe did you somehow reassign + to something else? ;-) I'm not having any trouble testing it (on TIO)...do you have a particular example? That approach is, I think different enough that it can be its own answer. \$\endgroup\$
    – Giuseppe
    May 18, 2018 at 16:53
  • \$\begingroup\$ You're right, my bad! Will post separately as you're suggesting. That said, we both return 1 for the input 0 so I need to fix this first... \$\endgroup\$
    – JayCe
    May 18, 2018 at 16:59
  • \$\begingroup\$ @JayCe goood point. In that case, I need to fix my answer, so I'll be deleting it for the moment. \$\endgroup\$
    – Giuseppe
    May 18, 2018 at 17:01
1
\$\begingroup\$

Vim, 29 bytes

:s/\d!!*\|1
A<C-r>=col('.')%2
<esc>d|

Try it online!

Explanation

If we normalize the number-and-factorial part, we can get the answer by counting the number of characters on the line mod 2.

:s/\d!!*\|1//<cr>

Substitute either 1) a digit followed by one or more !s or 2) a 1 digit with the empty string. (In the golfed version, the two final /s can be omitted.) This leaves a 0 if there was a lone 0 to begin with, and otherwise deletes the digit and everything after it.

A

Go to the end of the line and append something. The cursor is now positioned one column after the last character on the line.

<C-r>=col('.')%2<cr>

Calculate the column number mod 2 and insert that result (either 0 or 1).

<esc>d|

Leave insert mode; the cursor is now on the just-inserted character. Delete everything to the left of the cursor.

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

CLC-INTERCAL, 182 bytes.

The following source must be in Latin-1 or ISO-8859-1 encoding:

DO;1<-#1DO.9<-.9/;1SUB#1DOCOMEFROM:9DO.8<-"¥'.8¢:9'"~#1DOWRITEIN;1(1)DO:9<-.9~#16DO.7<-.9~#1DOWRITEIN;1DO.9<-"V'"'¥"'"&'"'¥"#1¢'.9~#4'"'~#1"¢.7'"~#1'¢.8"'~#1"¢#100'"~#5461DOREADOUT;1

Assumed I/O

  • Uses standard input/output.
  • Input: a line of the text. Does not matter trailing LF.

How to try it online

Try it online! Because of encoding issue, I recommend uploading and submitting the source rather than copying and pasting the code to the form. Also it may take very long time until the program ends.

How to test

Use the following shellscript:

#!/bin/sh
set -eu
cat<<'.' | awk 'BEGIN{ORS=""}$0=(NR>1?"":RS)$0' | iconv -f UTF-8 -t ISO-8859-1 >.i
DO;1<-#1
DO.9<-.9/;1SUB#1
DOCOMEFROM:9
DO.8<-"¥'.8¢:9'"~#1
DOWRITEIN;1
(1)DO:9<-.9~#16

DO.7<-.9~#1
DOWRITEIN;1

DONOTE remove the following long line to uncomment four sentences that begin with "DONOT.9<-" because it will result in timeout because of stupidly long expression.
DONOTE don't worry because they work equivalently.
DO.9<-"V'"'¥"'"&'"'¥"#1¢'.9~#4'"'~#1"¢.7'"~#1'¢.8"'~#1"¢#100'"~#5461

DONOT.9<-.9~#4
DONOT.9<-#1¢.9
DONOT.9<-.¥9~#1
DONOT.9<-"V'"'¥"'"&'".9"¢.7'"~#1'¢.8"'~#1"¢#100'"~#5461

DOREADOUT;1

.
wc -c .i >&2
sick .i
: >o
while read p _ q; do
   o="$(
      printf %s "$p" |
      ./.io |
      tee -a o
      printf X
   )"
   [ "X$o" = "X${q}X" ] &&
      printf "%s: Passed\n" "$p" >&2 ||
      printf "%s: Failed\n" "$p" >&2
done <<'.'
0 -> 0
1 -> 1
0! -> 1
1! -> 1
!0 -> 1
!1 -> 0
!0! -> 0
!1! -> 0
0!! -> 1
1!! -> 1
!!0 -> 0
!!1 -> 1
!0!! -> 0
!!!1 -> 0
!!!0!!!! -> 0
!!!1!!!! -> 0
.
cat o

How it works

DONOTE ;1SUB#1 shall be these:
   '!' is #116
   '0' is #101
   '1' is #100
DONOTE actually first 16 bits are random bits
DONOTE that has at least a 1 bit 
DONOTE when WRITEIN is done
DONOTE then second 16 bits are the values above
DONOTE EOF is really #0
DONOTE otherwise at least 2^16

DO;1<-#1 DONOTE for i/o
DO.9<-.9/;1SUB#1 DONOTE replaces every .9 with ;1SUB#1

DOCOMEFROM:9 DONOTE it is from label 1
DO.8<-"¥'.8¢:9'"~#1 DONOTE for fact
DOWRITEIN;1
(1)DO:9<-.9~#16 DONOTE '!' is #116 others are #101 or #100

DO.7<-.9~#1 DONOTE '0': 1, '1': 0

DOWRITEIN;1 DONOTE has trailing '!'?
DONOTE at this point .9 is '!': #116, EOF: #0, LF: #89

DONOTE explaining long expression

.9~#4                 #1 if .9&0x04==0x04 else #0
'¥"#1¢'...'"'~#1      ^#1
"&'"..."¢.7'"~#1      &.7
'¥"'...'¢.8"'~#1      ^.8
"V'"..."¢#100'"~#5461 |#100


DO.9<-"V'"'¥"'"&'"'¥"#1¢'.9~#4'"'~#1"¢.7'"~#1'¢.8"'~#1"¢#100'"~#5461


DONOTE finally
DOREADOUT;1
```
\$\endgroup\$
1
\$\begingroup\$

Swift, 58 bytes

let f={($0.last=="0" ?0:1)^($0+"").prefix{$0<"0"}.count%2}

Basically ended up being a port of @busukxuan's Python answer.

\$\endgroup\$
2
  • \$\begingroup\$ X bytes? did you forget to add the byte count? \$\endgroup\$
    – noodle man
    Mar 14 at 22:48
  • \$\begingroup\$ @noodleman Wow, yes I did. I’ll just go ahead and fix that… 🫣 \$\endgroup\$ Mar 15 at 0:00
0
\$\begingroup\$

RProgN, 31 bytes

~'(!*1?)0?(!*)'{L`x=L2%x+0>1*}R

Explained

~'(!*1?)0?(!*)'{L`x=L2%x+0>1*}R
~                               # Zero Space Segment
 '(!*1?)0?(!*)'                 # A pattern string, matching any number of !'s with optionally a 1, optionally an uncaptured 0, and any number of !'s
               {             }  # An anonymous function, which takes two arguments. The last !'s and the optional 1 with the first 1's.
                L               # Get the length of the last !'s
                 `x=            # Set 'x' to equal it.
                    L2%         # Get the length of the first !'s with the optional 1, mod 2, giving us the boolean portion.
                       x+       # Add x
                         0>1*   # If the total is larger than 0, converted to a number. If there are any leading !'s, this will always be 1, otherwise, it will be the boolean of the left handside.
                              R # Replace the input string via the function matching the first pattern.

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Pyth, 13 bytes

Code

s.v:z"\d!+""1

There may be a way to shave off a couple of bytes, but alas.

Explanation

s                # Cast to an integer (Python's int()).
 .v              # Evaluate (Python's eval()). This handles the negations.
   :             # Regex substitution. The following three expressions are its arguments.
    z            # Argument 1: what to replace in. This is equal to the (unevaluated) input string.
     "\d!+"      # Argument 2: what to replace. This is a regex that matches a number followed by one or more !'s.
           "1    # Argument 3: what to replace to. The string "1" (ending quote not needed in Pyth).

You can check it out here or run the test suite here. I have no earthly idea how to (or if one actually can) use the test suite feature to run tests as opposed to just evaluating a bunch of inputs at once, but if someone else knows, I'm all ears.

\$\endgroup\$
0
\$\begingroup\$

Haskell, 42

There must be a better way to do this...

f(h:t)|h=='!'=1-f t|h=='1'=1|t==[]=0|1<2=1
\$\endgroup\$
0
\$\begingroup\$

C, 56 bytes

c=1;f(char*a){c=-c;*a&16?c+=1-*a-1[a],c&=2,c/=2:f(a+1);}

Hint: only the last two bits count.

The basic idea was to use least significant bit for storing result of factorial, and next bit for storing the negation, then xoring the two.

c=0;
for(;*a<34;a++)c^=2; // invert the 2nd bit at each negation
while(*a)c|=*a++; // '0' ends with bits 00, '1' and '!' ends with bits 01, so this OR will let the first bit to resut of factorial (LSB) and leave the 2nd bit unchanged
c=((c>>1)^c)&1; // apply the negation (2nd bit) on the factorial (1st bit)

But it makes our intentions too clear. First, we don't need a loop for the factorial, and we can allways take 2 char, the 2nd being eventually a NULL terminator will have neutral 00 end bits. This is much like the answer Mathematics is fact. Programming is not from Ahemone, but longer and less elegant so far.

c=0;
while(*a++<34)c^=2; // invert the 2nd bit at each negation
c|=*a,c|=*--a; // '0' and NULL ends with bits 00, '1' and '!' ends with bits 01, so this OR will let the first bit to resut of factorial (LSB) and leave the 2nd bit unchanged
c=((c>>1)^c)&1; // apply the negation (2nd bit) on the factorial (1st bit)

C isn't going to win anyway, so let's trade some golf for some obfuscation: replace the last expression with something else, assuming 2-complement: -x == (~x+1) and observe how the last two bits evolve

- ...00 -> ...11+1 -> ...00
- ...01 -> ...10+1 -> ...11
- ...10 -> ...01+1 -> ...10
- ...11 -> ...00+1 -> ...01

We see that the LSB is unchanged via c=-c, and the 2nd bit becomes the xor of last two bits. So we can just pick this second bit with c>>=1,c&=1 or c&=2,c/=2;

Of course, the bit inversion ~x is useless, just adding+1 has the same effect.
But there is a reason behind it:
what if we would replace the XOR flip/flop with negated op?
at each neg -...01 becomes ...11 et vice et versa
If we then subtract 1, we have either ...00 or ...10 at the end of the loop.
We are back to our original solution.

c=1;
while(*a++<34)c=-c;
c-=1;
c|=*a,c|=*--a;
c=-c;
c&=2,c/=2;

And let's see what happens if we add the factorial bit instead of ORing:

...00 becomes 00 or 01 or 10 in case of '0' , '0!'||'1' , '1!'.
...10 becomes 10 or 11 or 00.
So using + gives the same parity than | on last two bits, even if we accidentally add a bit twice du to '1!' case.

Now we just have to roll the final c-=c inside the loop, and replace the + by - for getting our obfuscated solution.

Ah and also use recursion to take a functional style disguise, but of course with non reentrant, ugly static variable assignment side effect, else there would be no "advantage" to code in C ;)

\$\endgroup\$
0
\$\begingroup\$

JavaX, 77 74 bytes

!7p{print(repeatMultiReplace3(args[0],splitAtSpace("0! 1 1! 1 !0 1 !1 0";}

Run with, e.g.: " java -jar x30.jar 1006862 '!0' "

\$\endgroup\$
0
\$\begingroup\$

SmileBASIC, 63 bytes

INPUT S$WHILE"#">S$[0]N=!N
S$[0]="
WEND?(VAL(S$)||LEN(S$)>1)!=N

I don't think this is the best way...

\$\endgroup\$
0
\$\begingroup\$

Java (OpenJDK 8), 109 bytes

s->{int l=s.length(),n=(l>1?s.split("[01]")[0]:s).length();return l<2?s:(l-n<2&&s.charAt(n)<'1')==n%2>0?1:0;}

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Cubically, 42 bytes

UD3(L2~:7=3)6+13=7!6{<0%6&}~:7=3?6L2-6=0%6

Try it online!

For some unknown reason it exits with an error when the digit is 1, but it outputs the correct result regardless. The following is my basic algorithm:

  1. Start with 0
  2. Invert for each !
  3. If digit is 1 invert again and output (any number of trailing ! are irrelevant), ending the program
  4. If there is a ! after the digit, invert
  5. Output (any further ! are irrelevant)

And a more thorough explanation:

UD3                            Sets RIGHT to 33 and LEFT to 15

(L2~:7=3)6                     Flips TOP between 0 and 15 each time the input is ASCII 33 '!'

+13=7!6                        If the next character is NOT ASCII 15+33 '0':
       {<0%6&}                   output 1 if TOP is 15, 0 otherwise, then exit

~:7=3?6                        If the next character is ASCII 33 '!':
       L2                        flip TOP 

-6=0%6                         Output 1 if TOP is 0, 0 otherwise
\$\endgroup\$
1
  • \$\begingroup\$ Each %6 can be shortened to % thanks to language updates. \$\endgroup\$
    – MD XF
    Oct 8, 2017 at 21:44
0
\$\begingroup\$

Deorst, 42 bytes

o1:ER'[01]!+'gs''p@
'(!!)+'gst!0gso0@t!1gs

Try it online!

Regex based solution. Input must be quoted ('0')

How it works

Example input: '!!!0!!!!'

o1                     - Push '1';      STACK = ['!!!0!!!!', '1']
  :                    - Duplicate;     STACK = ['!!!0!!!!', '1', '1']
   ER                  - Reverse;       STACK = ['1', '1', '!!!0!!!!']
     '[01]!+'          - Push '[01]!+'; STACK = ['1', '1', '!!!0!!!!', '[01]!+']
             gs        - Regez replace; STACK = ['1', '!!!1']
               ''p     - Push '';       STACK = ['1', '!!!1', '']
                  @    - Swap;          STACK = ['1', '', '!!!1']
'(!!)+'                - Push '(!!)+';  STACK = ['1', '', '!!!1', '(!!)+']
       gs              - Regex replace; STACK = ['1', '!1']
         t!0           - Push '!0';     STACK = ['1', '!1', '!0']
            gs         - Regex replace; STACK = ['!1']
              o0       - Push '0';      STACK = ['!1', '0']
                @      - Swap;          STACK = ['0', '!1']
                 t!1   - Push '!1';     STACK = ['0', '!1', '!1']
                    gs - Regex replace; STACK = ['0']

Alternative, 27 bytes

t!1@t0$gs''p@
t!!gs'^\d'gcB

Try it online!

Requires input to be quoted ('0'). Based on Leo's Retina answer

How it works

t!1           - Push '!1';         STACK = ['!!!0!!!!', '!1']
   @          - Swap;              STACK = ['!1', '!!!0!!!!']
    t0$       - Push '0$';         STACK = ['!1', '!!!0!!!!', '0$']
       gs     - Regex replace;     STACK = ['!!!0!!!!']
         ''p  - Push empty string; STACK = ['!!!0!!!!', '']
            @ - Swap;              STACK = ['', '!!!0!!!!']
t!!           - Push '!!';         STACK = ['', '!!!0!!!!', '!!']
   gs         - Regex replace;     STACK = ['!0']
     '^\d'    - Push '^\d';        STACK = ['!0', '^\d']
          gcB - Count occurrences; STACK = [0]
\$\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.