27
\$\begingroup\$

Repost and improvement of this challenge from 2011

A vampire number is a positive integer \$v\$ with an even number of digits that can be split into 2 smaller integers \$x, y\$ consisting of the digits of \$v\$ such that \$v = xy\$. For example:

$$1260 = 21 \times 60$$

so \$1260\$ is a vampire number. Note that the digits for \$v\$ can be in any order, and must be repeated for repeated digits, when splitting into \$x\$ and \$y\$. \$x\$ and \$y\$ must have the same number of digits, and only one can have trailing zeros (so \$153000\$ is not a vampire number, despite \$153000 = 300 \times 510\$).

You are to take a positive integer \$v\$ which has an even number of digits and output whether it is a vampire number or not. You can either output:

  • Two consistent, distinct values
  • A (not necessarily consistent) truthy value and a falsey value
    • For example, "a positive integer for true, 0 for false"

You may input and output in any convenient method. This is , so the shortest code in bytes wins.

The first 15 vampire numbers are \$1260, 1395, 1435, 1530, 1827, 2187, 6880, 102510, 104260, 105210, 105264, 105750, 108135, 110758, 115672\$. This is sequence A014575 on OEIS. Be sure to double check that your solution checks for trailing zeros; \$153000\$ should return false.

\$\endgroup\$
7
  • \$\begingroup\$ Sandbox. Brownie points for beating my 15 byte Jelly answer \$\endgroup\$ Commented Feb 8, 2021 at 17:39
  • 1
    \$\begingroup\$ does anyone else see something to the tune of ‘the first 15 vampire numbers are 1260 ... 102510 this 104620 ... 115672 is sequence’ etc.? \$\endgroup\$ Commented Feb 9, 2021 at 7:10
  • 1
    \$\begingroup\$ Just to be 100% sure: we don't have to check whether the input has an even number of digits, do we? \$\endgroup\$
    – Arnauld
    Commented Feb 9, 2021 at 10:11
  • \$\begingroup\$ @Arnauld No, the input is guaranteed to have an even number of digits \$\endgroup\$ Commented Feb 9, 2021 at 12:44
  • \$\begingroup\$ I am writing a completely different solution, always in C. Would be acceptable to take as input n[]={1,2,6,0,1260}? Or is it too much? I am asking because I would need a for loop with two statements just to get 1260 from its digits (or the single digits from 1260) \$\endgroup\$
    – anotherOne
    Commented Feb 9, 2021 at 15:51

13 Answers 13

8
\$\begingroup\$

Husk, 18 17 14 13 12 bytes

Edit: -3 bytes, and then another -1 byte, thanks to Leo, and -1 byte thanks to inspiration from pajonk's R answer (3rd edit)

€¹mΠ†dm½f→Pd

Try it online!

Outputs nonzero integer if it's a vampire number, zero otherwise.

Commented penultimate version:

€¹                  # index of input if present, zero otherwise, in
  mΠ                # products of each element-pair
    †d              # combining digits as a number from
         m½         # first & second halves of
           P        # all permutations of
            d       # digits of input;
      f             # and filtering only element-pairs for which
       ṁ→           # sum of last digits is nonzero
\$\endgroup\$
4
  • \$\begingroup\$ Nice one! I believe the condition to your filter can be simplified to just ṁ→ (sum of the last element of each half) saving three bytes \$\endgroup\$
    – Leo
    Commented Feb 8, 2021 at 23:59
  • \$\begingroup\$ And 1 more byte saved by using deep map ! tio.run/##ASUA2v9odXNr///igqzCuW3OoOKAoGRm4bmB4oaSbcK9UGT///… \$\endgroup\$
    – Leo
    Commented Feb 9, 2021 at 0:03
  • 1
    \$\begingroup\$ @Leo - That's amazing! Thanks! I never really figured-out the difference between m and : this is the first time that I've seen them behave differently, so I'm still struggling to understand what's going on... (and why let's us avoid the o here...) \$\endgroup\$ Commented Feb 9, 2021 at 0:11
  • 1
    \$\begingroup\$ Come to the Husk chat if you want to talk about this :) \$\endgroup\$
    – Leo
    Commented Feb 9, 2021 at 0:17
7
\$\begingroup\$

R, 156 146 143 135 bytes

-10 bytes thanks to Dominic van Essen

function(n,s=strsplit){for(i in 1:n)if(!n%%i&nchar(j<-n/i)==nchar(i)&all(el(s(paste0(j,i),''))%in%el(s(c(n,''),'')))&i%%10)return(T)
F}

Try it online!

\$\endgroup\$
2
  • 2
    \$\begingroup\$ Really nice! And you can drop the 2xsort by using %in% for 146 bytes... \$\endgroup\$ Commented Feb 9, 2021 at 11:55
  • 2
    \$\begingroup\$ Edit 3 (only check %10 for one factor, since each pair will always occur both ways around) is really smart! I've copied the approach to save a byte in my Husk answer - Thanks! \$\endgroup\$ Commented Feb 11, 2021 at 8:08
6
\$\begingroup\$

J, 43 bytes

".e.-@-:@#((0<[:".{:\)*[:*/".\)"1 i.@!@#A.]

Try it online!

Takes digits as a string.

For each permutation i.@!@#A.], use half the digit length -@-:@# to take non-overlapping infixes -- which slices into 2 halves -- and multiply those halves([:*/".\)"1. Then (to handle the trailing zero constraint) multiply that by (0<[:".{:\)*, which takes the last digits of each half, cats them, evaluates that as a two digit number, and checks if it's greater than 0.

Finally, check if the input number ". is an element of that list e..

\$\endgroup\$
4
  • \$\begingroup\$ I‘m not quite sure how the Footer works, how would I test this for a specific single input? \$\endgroup\$ Commented Feb 8, 2021 at 20:43
  • \$\begingroup\$ @cairdcoinheringaahing Edited TIO for clarity. \$\endgroup\$
    – Jonah
    Commented Feb 8, 2021 at 20:47
  • 1
    \$\begingroup\$ Looks like this fails for 153000 \$\endgroup\$ Commented Feb 8, 2021 at 21:08
  • 1
    \$\begingroup\$ Ugh, totally read over that the first time. Fixed now. Will regolf later. \$\endgroup\$
    – Jonah
    Commented Feb 8, 2021 at 21:42
6
\$\begingroup\$

JavaScript (Node.js), 88 bytes

f=(n,i=1)=>n<i*i*10&&i%10&&[...''+i+n/i].sort()+''==[...''+n].sort()||n*10>++i*i&&f(n,i)

Try it online!

  • [...''+i+n/i].sort()+''==[...''+n].sort() two factors use and only use digits in original number
    • if n/i is not an integer, it converted into a string with . and not equals to another side which doesn't contain a ..
  • n<i*i*10, n*10>i*i: lengths of two numbers are the same.
    • It equip to i/10 < n/i < i*10. And since n has even number of digits (as question mentioned), i and n/i will have same number of digits.
  • i%10: i is not end with "0"
\$\endgroup\$
5
\$\begingroup\$

05AB1E, 14 bytes

œ2δäÅΔPQy€θĀà*

Outputs a non-negative integer as truthy and -1 as falsey.

Try it online or verify all test cases.

Explanation:

œ            # Get all permutations of the (implicit) input
  δ          # Map over each permutation:
 2 ä         #  And split it into two equal-sized halves
    ÅΔ       # Get the 0-based index of the first truthy result,
             # or -1 if none are found:
      P      #  Take the product of the two halves
       Q     #  And check that it's equal to the (implicit) input
      y      #  Push the halves again
       €θ    #  Only leave the last digit of each halve
         Ā   #  Check that it's not 0 (1 if [1-9]; 0 if 0)
          à  #  Get the maximum of these two
      *      #  Multiply the checks to verify both are truthy
             #  (after which the found index is output implicitly as result)
\$\endgroup\$
0
5
\$\begingroup\$

C (gcc), 286 240 218 bloody bytes (o,_,o)

-55 bloody bytes thanks to ceilingcat!

#define S(x,y)x^=y^=x^=y
o,a,b,c,r;f(int*_){c=atoi(_);v(o,_,o=strlen(_),r=0);r=r;}v(k,_,o,i)char*_;{--k?({for(v(k,_,o,0);i<k;v(k,_,o,!++i))S(_[k%2*i],_[k]);}):(a=atoi(_)/exp10(o/2))*(b=atoi(_+o/2))==c&&(a+b)%10?r=1:0;}

Try it online!

The input is a string and the output is either 1 or 0.

The core of the answer is the function v(), which implements Heap's algorithm to generate all the possible permutations of the input digits.

Here's an explanation of the code before some golfing:

#define S(x,y)x^=y^=x^=y                 // Macro used to swap digits
o,                                       // length of the input string
a,                                       // first half of one of the possible permutations of digits
b,                                       // second half
r;                                       // result: 1 if the input is a vampire number, 0 otherwise
char c[9];                               // copy of the original input that will be compared with the permutations
f(_)char*_;{                             // That's a simple function taking the input string
    r=!strcpy(c,_);                      // initializing `r` to 0 and `c` to the input
    v(o,_,o=strlen(_));                  // calling v(o,_,o) while initializing `o` to the length of the input
    r=r;                                 // and returning rhe result `r`
}
v(                                       // v() is a recursive function taking three parameters:
k,                                       // the length of a substring of digits being permuted
_,                                       // the whole current permutation
o,                                       // the length of the whole permutation
i)                                       // `i` is here just to avoid declaring `int i` inside the `for` loop
char*_;{
    if(k-1){                             // if `k` is not 1
        v(k-1,_,o);                      // call v() to permute `k-1` digits
        for(i=0;++i<k;                   // until `i` is less than `k`
        v(k-1,_,o))                      // call v() to permute `k-1` digit, but only after having
            S(_[k%2?0:i-1],_[k-1]);      // swapped _[k-1] with either _[0] or _[i-1]
    }
    else                                 // else (i.e. if k == 1)
        (a=atoi(_)/exp10(o/2))           // if `a` (getting the first half of the permutation, converted to integer)
        *(b=atoi(_+o/2))                 // multiplied by `b` (getting the second half)
        ==atoi(c)                        // equals the original input
        &&(a+b)%10?                      // and only one between `a` and `b` has trailing zeros
        r=1                              // then the result is set to 1
        :0;                              // otherwise do nothing, this permutation wasn't the right one
}

I tried other algorithms, but couldn't find a shorter one. I leave here the dumbest of the tries, which is a solution that doesn't solve the problem. It only finds most of the vampire numbers (probably).

\$\endgroup\$
7
  • \$\begingroup\$ Looks like 15300 is included in your output list, when it should return false \$\endgroup\$ Commented Feb 9, 2021 at 2:00
  • \$\begingroup\$ @ceilingcat Wow thank you so much!! Using exp10 instead of pow made possible to cut off the (int) cast of the result. I own you these 5 more bytes. \$\endgroup\$
    – anotherOne
    Commented Feb 9, 2021 at 11:39
  • 1
    \$\begingroup\$ You are right, the commas would indeed fix the issue because they are sequence points. However this is codegolf and undefined behaviors are well accepted as long as the program shows the expected output in at least one compiler of your choice. \$\endgroup\$
    – anotherOne
    Commented Feb 9, 2021 at 21:19
  • 1
    \$\begingroup\$ @tgm1024--Monicawasmistreated if you wanted to swap without undefined behaviour the simplest solution is to just have an extra variable, z, and use z=x,x=y,y=z which adds 3 bytes (1 for longer macro and 2 for declaring z - since you cannot reuse an existing variable), compared to 4 for sequence points. but as noted UB is ok here. \$\endgroup\$ Commented Feb 11, 2021 at 9:44
  • 1
    \$\begingroup\$ Davide, @HansOlsson, understood. Still feeling my way around this site. \$\endgroup\$ Commented Feb 11, 2021 at 13:05
4
\$\begingroup\$

Charcoal, 54 bytes

⊞υ⟦ωθ⟧FυFE§ι¹⟦⁺§ι⁰κΦ§ι¹⁻λν⟧⊞υκ⊙EΦυ¬⊟ιI⪪⊟ι⊘Lθ∧Σ﹪ιχ⁼θIΠι

Try it online! Link is to verbose version of code. Outputs a Charcoal boolean, i.e. - for vampire, nothing if not. Explanation:

⊞υ⟦ωθ⟧

Start a breadth-first enumeration of permutations of the input string.

Fυ

Loop over each partial permutation so far.

FE§ι¹⟦⁺§ι⁰κΦ§ι¹⁻λν⟧⊞υκ

Append each unused character to the permutation so far and push the result plus the remaining characters to the list.

⊙EΦυ¬⊟ι

Find whether any of the entries where all of the characters were used, ...

I⪪⊟ι⊘Lθ

... after being split into halves and cast to integer, ...

∧Σ﹪ιχ

... have a non-zero sum of the last digits, ...

⁼θIΠι

... and have the product of the halves resulting in the original string.

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

Python 2, 113 ... 112 109 bytes

def f(n,s=sorted):x=s(`n`);l=10**(len(x)/2);return any(x==s(`i`+`n/i`)for i in range(l/10,l)if i%10and n%i<1)

Try it online!

-3 byte thanks Kevin Cruijssen

\$\endgroup\$
1
  • 1
    \$\begingroup\$ The // can be / for -3. It will do integer-division implicitly in Python 2 if both arguments are integers. (In Python 3+ you'll indeed have to use //.) \$\endgroup\$ Commented Feb 9, 2021 at 10:06
4
\$\begingroup\$

Ruby, 104 96 bytes

It almost looks like a complete English sentence. Which probably is a bad thing for golfing.

->n{n.digits.permutation.any?{|s|a,b=s.each_slice(s.size/2).map{|x|x.join.to_i};a%10>0&&a*b==n}}

Try it online!

It can be written in 94 bytes with Ruby 2.7:

->n{n.digits.permutation.any?{|s|a,b=s.each_slice(s.size/2).map{_1.join.to_i};a%10>0&&a*b==n}}
\$\endgroup\$
4
\$\begingroup\$

Python 2, 105 95 94 bytes

-10 bytes thanks to Kevin Cruijssen! (switch to Python 2)
-1 byte thanks to dingledooper!

Very inefficient, segfaults for \$ n \gtrsim 18500\$ on TIO.

f=lambda n,k=2,S=sorted:k<n and(k%10>n%k<(len(`k`)==len(`n/k`)<S(`k`+`n/k`)==S(`n`)))|f(n,k+1)

Try it online!

Commented:

f=lambda n,k=2,S=sorted   # recursive function
  k<n                     # if k>=n return False
  and                     # otherwise:
  ( ... )                 # long boolean expression which is True if k and n//k make n a valid vampire number
    k%10                  # the last digit of k is 
  > n%k                   # larger than n%k which is
  < ( ... )               # less than another boolean expression
                          # These two comparisons can only be satisfied with k%10>0<1
      len(`k`)            # the number of digits of k
   == len(`n/k`)          # is equal to the number of digits of n//k
    < S(`k`+`n/k`)        # and sorting the digits of k and n//k 
   == S(`n`)              # results in the same list as sorting the digits of n

| f(n,k+1)                # bitwise OR with result of the recursive call
\$\endgroup\$
5
  • 1
    \$\begingroup\$ 97 bytes by switching to Python 2. \$\endgroup\$ Commented Feb 9, 2021 at 9:40
  • \$\begingroup\$ Reply to a deleted comment, but might be interesting to others: If n has divisors j and n//j that satisify all conditions, we will find this pair twice, since we iterate k from 2 to n. Either k=j or k=n//j satisfies k%10>0 and the remaining boolean expression is True for both values of k. \$\endgroup\$
    – ovs
    Commented Feb 9, 2021 at 10:02
  • 1
    \$\begingroup\$ My comment above should be 95 bytes actually. The // can also be / in Python 2. \$\endgroup\$ Commented Feb 9, 2021 at 10:04
  • 1
    \$\begingroup\$ @KevinCruijssen thanks a lot! I was initially hesitant to use `n` here because this doesn't work for long integers, but I guess restricting this to int is fine. As a bonus Python 2 seems to run out of stack size a little bit later ;). \$\endgroup\$
    – ovs
    Commented Feb 9, 2021 at 10:09
  • 1
    \$\begingroup\$ -1 byte since conditionals can be used on conflicting types in Python 2. \$\endgroup\$ Commented Feb 9, 2021 at 19:32
3
\$\begingroup\$

JavaScript (ES6), 93 bytes

Assumes that the input has an even number of digits. Returns a Boolean value.

f=(n,[...a]=n,p='')=>a[p.length]?a.some((v,i)=>f(n,a.filter(_=>i--),p+v)):p%10&&p*a.join``==n

Try it online!


JavaScript (ES6), 97 bytes

Expects the integer as a string. Returns 0 or 1.

f=(n,[...a]=n,p,q,k)=>a.some((v,i)=>f(n,a.filter(_=>i--),k?[p]+v:p,k?q:[q]+v,!k))|p%10*!(p*q^n|k)

Try it online!

Commented

f = (                     // f is a recursive function taking:
  n,                      //   n = input integer, as a string
  [...a] = n,             //   a[] = list of digits of n
  p, q,                   //   n is split into p and q (both initially undefined)
  k                       //   k is a flag, set on odd iterations
) =>                      //
  a.some((v, i) =>        // for each digit v at position i in a[]:
    f(                    //   do a recursive call:
      n,                  //     pass n unchanged
      a.filter(_ => i--), //     remove the i-th entry from a[]
      k ? [p] + v : p,    //     append v to p if k is set
      k ? q : [q] + v,    //     append v to q if k is not set
      !k                  //     toggle k
    )                     //   end of recursive call
  )                       // end of some()
  |                       // success if:
    p % 10 *              //   the last digit of p is not 0,
    !(p * q ^ n | k)      //   p * q = n and k is not set
\$\endgroup\$
2
\$\begingroup\$

Jelly, 15 bytes

Œ!ŒH€SṪ$ƇḌP€=ḌẸ

Try it online!

Takes a list of digits.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ 14 bytes (My solution, forgot I could input as digits) \$\endgroup\$ Commented Feb 8, 2021 at 23:25
  • 1
    \$\begingroup\$ @cairdcoinheringaahing Wow, it's exactly the same, except for the fact that I'm a moron and didn't realize that I could just use i. \$\endgroup\$
    – xigoi
    Commented Feb 8, 2021 at 23:28
2
\$\begingroup\$

Japt, 20 bytes

á mó f_dÌîmì ×Ãd¥Uì

Try it online! or check all test cases (specifically the 15 vampire numbers and 153000)

Takes input as an array of digits. Input as an integer is one byte longer

Explanation:

á mó f_dÌîmì ×Ãd¥Uì    
á                       # Get all permutations of the input digits
  mó                    # Divide each permutation into two groups of equal length
     f_  Ã              # Only keep ones where:
       dÌ               #  At least one of the groups ends with a non-zero number
          ®    Ã        # For each remaining pair of groups:
           mì           #  Treat each group of digits as an integer
              ×         #  Multiply those integers
                d       # Return true if at least one of the results...
                 ¥Uì    # ... Is equal to the original number
\$\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.