27
\$\begingroup\$

A Primenary (binary-prime) string is one which, when written as a binary grid, every row and column has a prime total.

That's quite a vague explanation, so let's break it down with a worked example...


For this example we'll use the string bunny:

First, find the ASCII code point of each character and its binary representation:

Char | ASCII | Binary

b      98      1100010
u      117     1110101
n      110     1101110
n      110     1101110
y      121     1111001

Take these binary values, from top to bottom, and arrange them into grid (adding leading zeros if necessary):

1 1 0 0 0 1 0
1 1 1 0 1 0 1
1 1 0 1 1 1 0
1 1 0 1 1 1 0
1 1 1 1 0 0 1

Then, count the number of 1s in each row and column:

1 1 0 0 0 1 0   > 3
1 1 1 0 1 0 1   > 5
1 1 0 1 1 1 0   > 5
1 1 0 1 1 1 0   > 5
1 1 1 1 0 0 1   > 5

v v v v v v v

5 5 2 3 3 3 2

If, and only if, every single total is prime (such as here) then the string is a valid binary-prime.


The Challenge

Your task is to create a function or program which, when given a string, returns/outputs truthy if the string is primenary, and falsy otherwise.

Rules/Details

  • You may assume that the string's characters will always be in the ASCII range 33-126 (inclusive).
  • The string will not be empty.
  • A primenary string does not have to have a prime length - for example, W1n* is valid, despite having 4 characters.
  • This is , so the shortest answer (in bytes) wins - but all submissions are welcome.
  • Standard loopholes are banned.

Test Cases

'husband'     -> True
'HOTJava'     -> True
'COmPaTIBILE' -> True
'AuT0HACk'    -> True

'PPCW'        -> False
'code-golf'   -> False
'C++'         -> False
'/kD'         -> False

'HI'          -> False
'A'           -> False

There is also a working, but incredibly verbose Python example on repl.it that you can test your solution against.

\$\endgroup\$
  • \$\begingroup\$ Can I ask how you discovered that husband was valid? Or any of them? Great problem, though! \$\endgroup\$ – Gabriel Benamy Nov 6 '16 at 21:55
  • 3
    \$\begingroup\$ @GabrielBenamy I'm glad someone asked! I looped through an online dictionary file, trying a few random capitalizations of each letter, sometimes switching letters for numbers, etc. Then I had a look through the outputted list and picked a couple of test cases I liked \$\endgroup\$ – FlipTack Nov 6 '16 at 22:00
  • \$\begingroup\$ Every 1-2 character input is guaranteed to return False, correct? \$\endgroup\$ – mbomb007 Nov 8 '16 at 21:21
  • \$\begingroup\$ ... because 0 and 1 are not prime, and every 1-2 char input string containing only chars in the given range is guaranteed to contain at least one 0 or 1 as a vertical sum. You should add some 1 and 2 character strings as test cases. \$\endgroup\$ – mbomb007 Nov 8 '16 at 21:35
  • \$\begingroup\$ @mbomb007 1 char inputs cannot have prime numbers columnwise, so they will return false. 2 char inputs could, but not in the ASCII range we're using, so for this scenario you're correct. \$\endgroup\$ – FlipTack Nov 8 '16 at 21:36

21 Answers 21

8
\$\begingroup\$

MATL, 10 bytes

BtXsw!shZp

Try it online!

This is the ideal language for the job. It's pretty much a literal transliteration of the challenge specification.

Bt % Converts input to binary matrix, duplicate
Xs  % Sum columns (alternative X version to prevent defaulting to sum along first non-singleton dimension, thanks @Jonathan Allan)
w! % Get the duplicate to the top of the stack, transpose
s  % Sum again
h  % Concatenate horizontally
Zp % Check primality element-wise. Display implicitly.

Since any zero makes a MATL array falsy as per meta, nothing else is needed - basically, an implicit A is called on ? (if).

\$\endgroup\$
  • \$\begingroup\$ a should be falsy, but returns 1 1? (its columns do not add up to primes) \$\endgroup\$ – FlipTack Nov 12 '16 at 13:02
  • \$\begingroup\$ I think BtXsw!shZp would fix this and be a winner for 10. \$\endgroup\$ – Jonathan Allan Nov 12 '16 at 23:35
  • \$\begingroup\$ @Flp.Tck Completely forgot about MATLAB's 'forgiving' behaviour when working with row vectors. I'm sorry, fixed it now. \$\endgroup\$ – Sanchises Nov 13 '16 at 9:02
  • \$\begingroup\$ Works now :) (might want to update the try it online link tho) \$\endgroup\$ – FlipTack Nov 13 '16 at 9:10
  • \$\begingroup\$ @Flp.Tkc Done. Thanks for a nice challenge! \$\endgroup\$ – Sanchises Nov 13 '16 at 9:16
4
\$\begingroup\$

Jelly, 13 12 11 bytes

OBUZ;$S€ÆPẠ

TryItOnline! or all test cases

How?

OBUZ;$S€ÆPẠ - Main link: word                  e.g. ha!
O           - cast to ordinals                 e.g. [104,97,33]
 B          - convert to binary                e.g. [[1,1,0,1,0,0,0],[1,1,0,0,0,0,1],[1,0,0,0,0,1]]
  U         - reverse each entry (say "b")     e.g. [[0,0,0,1,0,1,1],[1,0,0,0,0,1,1],[1,0,0,0,0,1]]
     $      - last two links as a monad
   Z        - transpose                        e.g. [[0,1,1],[0,0,0],[0,0,0],[1,0,0],[0,0,0],[1,1,1],[1,1]]
    ;       - concatenate with "b"             e.g. [[0,1,1],[0,0,0],[0,0,0],[1,0,0],[0,0,0],[1,1,1],[1,1],[0,0,0,1,0,1,1],[1,0,0,0,0,1,1],[1,0,0,0,0,1]]
      S€    - sum €ach                         e.g. [2,0,0,1,0,3,2,3,3,2]
        ÆP  - is prime (1 if prime, 0 if not)  e.g. [1,0,0,0,0,1,1,1,1,1]
          Ạ - all truthy?                      e.g. 0
\$\endgroup\$
3
\$\begingroup\$

05AB1E, 17 bytes

Çžz+b€¦€SDøìO0ÛpP

Try it online!

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

Jelly, 15 bytes

O+⁹Bṫ€3µS€;SÆPP

Try it online! or Verify all test cases..

Explanation

O+⁹Bṫ€3µS€;SÆPP  Main link. Input: string z
O                Ordinal, get ASCII value of each char
  ⁹              Nilad representing 256
 +               Add 256 to each ordinal value
   B             Binary digits of each
    ṫ€3          Tail, take each list of digits from the 3rd value to the end
                 These are the last seven digits of each
       µ         Start a new monadic chain
        S€       Sum each list of digits by rows
           S     Sum by column
          ;      Concatenate
            ÆP   Test if each is prime, 1 if true else 0
              P  Product
\$\endgroup\$
3
\$\begingroup\$

Mathematica, 75 bytes

And@@Join@@PrimeQ@{+##&@@#,+##&@@@#}&@IntegerDigits[ToCharacterCode@#,2,7]&

Unnamed function taking a string as input and returning True or False.

ToCharacterCode@# converts the input into the list of its ASCII values; IntegerDigits[...,2,7] turns each value into the list of its bits, padded to length 7 if necessary. So now we have a 2D array and we want all its row sums and column sums; lo and behold, the character-spasm {+##&@@#,+##&@@@#}&@... does exactly that (it applies the +##&, "sum all arguments", function to the list of vectors in the first coordinate using @@, and to each vector as its own list of integers in the second coordinate using @@@). Then we just check whether the results are PrimeQ, flatten the list with Join@@, and take the And of all those values.

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

Ruby -rprime, 100 bytes

->s{a=s.bytes.map{|b|b.digits 2}
a.all?{|r|r.sum.prime?}&([0]*7).zip(*a).all?{|c|c.count(1).prime?}}

Try it online!

Explanation

->s{
    a=s.bytes                       # Get byte values from string
             .map{|b|b.digits 2}    # For each, map it to its binary digits
                                    #   (least significant digits first)
a.all?{|r|r.sum.prime?}             # Each character has a prime number of 1's?
    &                               # Bit-and (because it saves bytes here)
    ([0]*7).zip(*a)                 # Zip bit array with an all-zero array
                                    #   (If we don't, then uneven array lengths
                                    #   cause some columns to not be returned.)
    .all?{|c|c.count(1).prime?}     # All columns have a prime number of 1's?
                                    #   (We use count instead of sum here because
                                    #   zip pads columns with trailing nils, which
                                    #   can't be added to numbers via sum.)
}
\$\endgroup\$
1
\$\begingroup\$

Perl, 151 121 111 + 3 = 114 bytes

Run with -lF. The program will only function correctly for the first input. Terminate the program and rerun for your next input.

Thanks to @Dada for letting me know the // after F were redundant. An additional byte can be removed (for 112) by piping the input in via echo -n, but I feel that that's technically adding more code, so YMMV.

for$c(@a=map{sprintf"%07b",ord}@F){$b[$_].=substr$c,$_,1 for 0..6}s/0//g,$d|=/^1?$|^(11+?)\1+$/ for@a,@b;say!$d

Readable:

                                     #Implicitly split input into characters in @F array
for$c(@a=map{sprintf"%07b",ord}@F)  #Convert @F to 7-bit binary as @a, then loop through it                        
    $b[$_].=substr$c,$_,1 for 0..6   #Transpose @a's bits into @b
}
s/0//g,$d|=/^1?$|^(11+?)\1+$/ for@a,@b; #Remove any zeros, then run through composite regex
say!$d                          #If all composite regex checks fail, then it's fully prime.
\$\endgroup\$
  • 1
    \$\begingroup\$ A version that only works on the first input is perfectly fine, so you can put the 141 bytes version as the main one, and suggest the other one to use on multiple inputs. \$\endgroup\$ – Dada Nov 6 '16 at 21:33
  • \$\begingroup\$ Also note that you can omit the // after -F, and you can take the input without final newline (with echo -n) to get rid of -l flag. \$\endgroup\$ – Dada Nov 6 '16 at 21:36
1
\$\begingroup\$

Python 3, 228 227 225 bytes

Not a great answer, I wasn't able to golf it as much as I would've liked, but I spent so long on it I feel I should post it. Suggestions on cutting bytes would be greatly appreciated.

r=range
n=[format(ord(c),"08b")for c in input()]
n=map(lambda s:s.count("1"),n+["".join([f[1]for f in filter(lambda e:e[0]%8<1,enumerate("X"*-~i+"".join(n)))][1:])for i in r(8)])
print(all(all(s%d for d in r(2,s))for s in n))

Edit 1: replaced e[0]%8==0 with e[0]%8<1, losing a byte. Thanks Flp.Tkc!

Edit 2: replacing (i+1) with -~i, losing two additional bytes. Thanks Erik for exposing how bad my bit-level knowledge is :) While testing this revision, I discovered that kappa is valid... make of that what you will.

\$\endgroup\$
  • 1
    \$\begingroup\$ could you change e[0]%8==0 to e[0]%8<1? \$\endgroup\$ – FlipTack Nov 6 '16 at 17:37
  • \$\begingroup\$ @Flp.Tkc Good spot! There's no reason why that can't be done. \$\endgroup\$ – FourOhFour Nov 6 '16 at 17:40
  • 1
    \$\begingroup\$ @Flp.Tkc I don't think I could save bytes by making it a function. I like how you've got 404 rep btw :) \$\endgroup\$ – FourOhFour Nov 6 '16 at 17:45
  • \$\begingroup\$ It is supposed to be <1, not <0? \$\endgroup\$ – Destructible Lemon Nov 6 '16 at 22:13
  • \$\begingroup\$ @Destructible Watermelon yep let me correct that. \$\endgroup\$ – FourOhFour Nov 7 '16 at 8:12
1
\$\begingroup\$

Groovy, 151 137 bytes

{p={x->x<3||(2..(x**0.5)).every{x%it}};y={it.every{p(it.count("1"))}};x=it.collect{0.toString((int)it,2) as List};y(x)&&y(x.transpose())}

No primality check in groovy...

p={x->x<3||(2..(x**0.5)).every{x%it}}; - Closure for primality testing.

y={it.every{p(it.count("1"))}}; - Closure to ensure that all counts of "1" for a passed binary 2D array are prime.

x=it.collect{0.toString((int)it,2) as List}; - Coversion from string to binary array.

y(x)&&y(x.transpose()) - For all prime-validated sums in the main matrix and the transposed matrix, ensure that they return true.

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

Pyth, 37 bytes

L.AmP_sdb=sMM.[L\0lh.MlZQ=.BMQ&yZy.TZ

Try it online!


                                 Code | Explanation
--------------------------------------+----------------------------------------------------------------
L.AmP_sdb=sMM.[L\0lh.MlZQ=.BMQ&yZy.TZ | Full code
L                                     | Define function y(b):
   m    b                             |   For each d in b:
    P_sd                              |     Is the sum of the elements of the list prime?
 .A                                   |   Return whether all elements of the resulting list are truthy
                         =   Q        | Assign the following to Q:
                          .BMQ        |   The list of binary strings for each character in the input
         =             Z              | Assign the following to Z:
               L             Q        |   For every element in Q:
             .[ \0                    |     Pad with 0 on the left
                  lh.MlZQ             |     To the length of the longest element in Q
            M                         |   For each element in the resulting list:
          sM                          |     Convert each character to an integer
                              &yZ     | Print y(Z) AND
                                 y.TZ |   y( <Transpose of Z> )
\$\endgroup\$
1
\$\begingroup\$

Brachylog, 14 bytes

ạḃᵐB↔ᵐz₁,B+ᵐṗᵐ

Try it online!

Outputs through success or failure. (In the case of success, a list of all column and row sums is available through the output variable.

   B              The variable B is
ạ                 the codepoints of the input
 ḃᵐ               converted to lists of binary digits,
    ↔ᵐ            which with each list reversed
      z₁          then zipped without cycling
        ,B        and concatenated with B
          +ᵐ      has elements which all sum to
            ṗᵐ    prime numbers.
\$\endgroup\$
1
\$\begingroup\$

O5AB1E, 12 bytes

Çžy+bø€SOp¦W

Try it online!

This is my first code golf so go easy :)

Ç              % Converts the implicit input into ascii values
 žy+           % Adds 128 to each value, inspired by Emigna as a way to pad zeros
    b          % Convert all values into bits
     ø         % Transpose
      €SO      % Sum each string of binary digits created
         p¦    % Check if each element is prime and cut the first element out (adding 128 makes it equal to the number of characters)
           W   % Take the minimum value to effectively "and" all the elements
\$\endgroup\$
  • \$\begingroup\$ This yield an empty result for a single letter input. I'm not well versed in O5AB1E but if that is a falsey value, it's ok. \$\endgroup\$ – Sanchises Jun 26 at 6:28
1
\$\begingroup\$

Python 3, 209 189 180 171 160 bytes

Thanx squid for -9 bytes :)

def p(s):n=s.count('1');return(n>1)*all(n%i for i in range(2,n))
def f(s):t=[f'{ord(c):07b}'for c in s];return all(map(p,t+[[u[j]for u in t]for j in range(7)]))

Try it online!

\$\endgroup\$
  • \$\begingroup\$ I like how you rewrote the test case print statement :) \$\endgroup\$ – movatica Jun 26 at 18:52
  • \$\begingroup\$ Yeah I'm a smidge obsessive compulsive about f-strings... Also, isn't it equivalent if you remove t+ in the map statement? \$\endgroup\$ – Reinstate Monica Jun 26 at 18:59
  • \$\begingroup\$ Nope, because the prime check needs to cover both rows and columns in the bit matrix. t has all the rows, while [[t[i][j]..i..]..j..] is the transposed t, i.e. the columns. If there is a shorter way to transpose the matrix, we can save more bytes :) \$\endgroup\$ – movatica Jun 26 at 19:06
  • \$\begingroup\$ It's working when I try it, do you know of a string that breaks it? \$\endgroup\$ – Reinstate Monica Jun 26 at 19:07
  • \$\begingroup\$ Yes. beezz should return false, but does not. It's because the prime check is broken, it returns True for 4 bits. Try print(p('1111')). Fixed it now. All the test cases did not cover that, because all of the used characters ar primenary. \$\endgroup\$ – movatica Jun 26 at 19:30
1
\$\begingroup\$

K (oK), 40 33 bytes

Solution:

&/{2=+/d=_d:x%!x}'+/'m,+m:(7#2)\'

Try it online!

Explanation:

Half is creating the matrix, the other half is the primality check.

&/{2=+/d=_d:x%!x}'+/'m,+m:(7#2)\' / the solution
                                ' / apply to each (')
                               \  / decode
                          (   )   / do this together
                           7#2    / 7#2 => 2 2 2 2 2 2 2
                        m:        / save as m
                       +          / transpose
                     m,           / append to m
                  +/'             / sum (+/) each (')
                 '                / apply to each
  {             }                 / lambda taking implicit x
              !x                  / range 0..x
            x%                    / x divided by ...
          d:                      / save as d
         _                        / floor
       d=                         / equal to d?
     +/                           / sum (+/)
   2=                             / equal to 2?
&/                                / minimum
\$\endgroup\$
0
\$\begingroup\$

PHP, 173 bytes

for($r=1;$b=substr_count($t[$i]=sprintf('%07b',ord($argv[1][$i++])),1);)$r&=$b==2|$b%2&$b>2;for(;$k++<7;){for($b=$j=0;$t[++$j];$b+=$t[$j][$k-1]);$r&=$b==2|$b%2&$b>2;}echo$r;

Test it online

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

JavaScript, 234 bytes

f=z=>(z=[...z].map(v=>v.charCodeAt(0))).map(v=>v.toString(2).replace(/0/g,"").length).every((p=v=>{for(i=2;i<v;i++){if(v%i===0){return 0}};return v>1}))&&[...""+1e6].map((v,i)=>z.reduce((a,e)=>!!(e&Math.pow(2,i))+a,0)).every(v=>p(v))

We get the horizontal values by converting the number to binary, removing the zeros using a string replacement, and then counting the 1s. The vertical sums are obtained by looping 1 to 7 and using a bitwise AND with 2 raised to the nth power.

\$\endgroup\$
  • \$\begingroup\$ Math.pow(2,i) can be shortened to (1<<i) assuming i<32, maybe saving 7 bytes, maybe not though. \$\endgroup\$ – Naruyoko Jun 26 at 0:27
0
\$\begingroup\$

Clojure, 180 bytes

#(let[S(for[i %](for[j[1 2 4 8 16 32 64]](min(bit-and(int i)j)1)))A apply](not-any?(fn[i](or(= i 1)(seq(for[d(range 2 i):when(=(mod i d)0)]d))))(into(for[s S](A + s))(A map + S))))

There might be a shorter way of generating bit lists and also the primality test.

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

Perl 5 -MList::Util=all,sum -pF, 96 92 bytes

$_=all{//;all{$'%$_}2..$_-1}(map{$_=sprintf'%07b',ord;y/1//}@F),map{sum map{s/.//;$&}@F}0..6

Try it online!

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

Python 3, 164 bytes

import numpy;a=numpy.array([list(f'{ord(_):07b}')for _ in input()]).astype(int);print(all([(v>1)*all(v%i for i in range(2,v))for v in set(a.sum(0))|set(a.sum(1))]))
\$\endgroup\$
0
\$\begingroup\$

Ruby 2.7 -rprime, 95 bytes

->s{a=s.bytes.map{[*@1.digits(2),0][..6]}
(a.map(&:sum)+a.transpose.map(&:sum)).all?(&:prime?)}

No TiO link because TiO still runs Ruby 2.5.5. 😭

Explanation

Pretty simple. The first line gets the binary digits of each character as an array padded out to seven digits, which really ought to be easier:

a = s.bytes.map { [*@1.digits(2), 0][..6] }

Check out that numbered block parameter (@1) and beginless range (..6) hotness.

The second line sums the rows and columns and tests if they're all prime:

(a.map(&:sum) + a.transpose.map(&:sum)).all?(&:prime?)
\$\endgroup\$
0
\$\begingroup\$

JavaScript (Node.js), 149 146 ... 134 130 129 bytes

x=>[...x].map(y=>a=[...a.map(n=>y.charCodeAt()&2**i++?++z&&-~n:n,z=i=0),z],a=[...Array(7)])&&!a.some(n=>(P=r=>n%--r?P(r):~-r)(n))

Try it online!

Explanation

x=>                        // Main function:
 [...x].map(               //  For each y in x:
  y=>
   a=[...a.map(            //   For each i in range(0, len(a)):
    n=>                   
     y.charCodeAt()&2**i++ //    If y AND 2**i is not zero:
     ?++z&&-~n:n,          //     z = z + 1; a[i] = a[i] + 1 (1 if a[i] is undefined)
    z=i=0                  //   Initially z = 0
   ),z],                   //   Then push z at the end of a
  a=[...Array(7)]          //  Initially a = [undefined] * 7
 )&&!a.some(               //  Then for each n in a:
  n=>(
   P=r=>                   //   Composite function:
    n%--r?                 //    If n % (r - 1) == 0 or r == 1:
     P(r)                  //     Return P(r - 1)
    :~-r                   //    Else: Return r - 2
  )(n)                     //   Starting from r = n
 )                         //  Return whether the composite function returns 0 for all n.

How does it even work!?

  • y.charCodeAt()&2**i
    • We need this code to return the corresponding bit of y.charCodeAt() if 0 <= i < 7, and 0 otherwise.
    • When i < 7, the code apparently works as usual.
    • When 7 <= i <= 32, since the corresponding bit of y.charCodeAt() is 0 anyway, the result is 0 as expected.
    • When 32 < i < 1024, since int32(2**i) == 0, the result is 0 as expected.
    • When 1024 <= i, we have 2**i == Infinity, and since int32(Infinity) == 0, the result is 0 as expected.
  • (P=r=>n%--r?P(r):~-r)(n)
    • For simplicity we let R = --r = r - 1.
    • This helper function terminates when n % R == 0 or n % R is NaN.
      • n % R == 0: R is a factor of n.
        • If R == 1, then n is prime because all 1 < R < n can't divide n. Return 0 (falsy).
        • If R == -1, then n == 0. Return -2 (truthy).
        • Otherwise, return R - 1 where R - 1 > 0 (truthy).
      • n % R is NaN: Invalid modular calculation.
        • If R == 0: n == 1. Return -1 (truthy).
        • If n is NaN: R is NaN. Return -1 (truthy).
    • As a result, only when R == 1 can this function return a falsy value, indicating n is prime.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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