# The Unholy numbers

This challenged is highly inspired by what @Mego created with his Holy and Holier numbers, lots of thanks to him and his puns.

Holy numbers are numbers composed of only the digits with holes, which are:

04689


Numbers with at least one unholy digit are considered unholy. Unholy digits are evil by definition, but being close to holy digits help them become neutral. Hence, the closer they are, the less unholy (1 when adjacent).

The unholiness of a number is the sum of the unholyness of its digits, a number composed of only unholy number has an infinite unholiness.

Number            :8 5 5 8 7
Digital Unholiness:0+1+1+0+1
Total Unholiness  :3

Number            :0 1 7 5 5 2 8 5 7
Digital Unholiness:0+1+2+3+2+1+0+1+2
Total Unholiness  :12

Number            :1 5 7 3 2 1
Digital Unholiness:∞+∞+∞+∞+∞+∞
Total Unholiness  :∞

Number            :0 4 6 8 9
Digital Unholiness:0+0+0+0+0
Total Unholiness  :0


You have to write a program or function that takes a positive integer or a string only composed of digits as input, and output its unholiness. If you chose to use an integer as input, you can assume it will never have a leading 0 as your language may drop it.

In case of infinite unholiness, you can chose between three outputs

• The character ∞ (3 bytes)
• Infinite output containing at least 1 non-zero digit, but only digits.
• A built-in Infinity value.

This is code-golf, so the shortest code in byte wins, good luck!

• Is returning a built-in Infinity value legal? – Neil Mar 2 '16 at 9:25
• @Neil I will allow it, as I didn't even think of it, good point there. – Katenkyo Mar 2 '16 at 10:56
• Some of your example inputs start with a leading zero; is it intended that we can write our function with input "a positive integer" only if our language of choice won't automatically drop the leading zero? Many languages will be forced to take string input for this reason. – A Simmons Mar 2 '16 at 11:36
• @ASimmons That's why I modified (a while back) the input so it can be a "string only composed of digits" aswell. Also, the important point isn't that it is a 0 but a holy digit, I will modify the post according to allow answer based on non-leading 0 numbers. – Katenkyo Mar 2 '16 at 12:26
• @katenkyo Yeah I saw you could input as a string but it seemed hard to take it as an integer. I approve of your edit to the OP. – A Simmons Mar 2 '16 at 13:56

# MATL, 25 24 bytes

7Zq1hVmt~f!wf-|X<st~?xYY


Try it online!

Input is a string. In the output, infinity is natively displayed as Inf.

### Explanation

7         % number literal
Zq        % prime numbers up to a 7: [2 3 5 7]
1         % number literal
h         % horizontal concatenation
V         % convert numbers to string: '2  3  5  7  1'
m         % take input implicitly. Determine which digits are 1,2,3,5,7
t         % duplicate
~         % element-wise negate: which digits are 4,6,8,9,0
f         % indices of occurrences of digits 4,6,8,9,0
!         % transpose into column array
w         % swap elements in stack
f         % indices of occurrences of digits 1,2,3,5,7
-         % element-wise subtraction with broadcast. Gives 2D array
|         % element-wise absolute value
X<        % minimum of each column
s         % sum of elements of array
t         % duplicate
~         % element-wise negate
?         % if all elements are true
x       %   delete
YY      %   push infinity
% (implicit) end if
% (implicit) convert to string and display


## Python (3), 137 131 bytes

def f(s):
l=range(len(s))
r=[min(i)for i in zip(*[[abs(j-i)for j in l]for i in l if s[i]in'46890'])]
return sum(r)if r else'∞'


## Results

>>> [f(i) for i in ['85587', '012321857', '157321', '04689']]
[3, 12, '∞', 0]

• I get a count of 131 Bytes, Is there something I am missing? Also, great answer :). – Katenkyo Mar 2 '16 at 10:59
• @Katenkyo I always forgot my editor add en empty line at the end of the file – Erwan Mar 2 '16 at 11:40

# GNU APL, 27 bytes

{+/⌊/|(⍳⍴⍵)∘.-(⍵⍳⍕⍟788)~⍴⍵}


Try it online!

To try it out using the above link, IO must be set to 0 and the input is provided as a string. For example:

⎕IO←0
{+/⌊/|(⍳⍴⍵)∘.-(⍵⍳⍕⍟788)~⍴⍵}'017552857'


## Explanation

{+/⌊/|(⍳⍴⍵)∘.-(⍵⍳⍕⍟788)~⍴⍵}  ⍝ Note: below explanation uses as example input 017552857
{                            ⍝ dfn
⍟788       ⍝ computes natural log of 788, which happens to be 6.66949809, containing only (and all) holy digits
⍕           ⍝ Converts this number to a string
⍵⍳            ⍝ Finds the indexes of chars in the right argument ⍵ which are present in the computed decimal. Items not found map to the length of the list, e.g. '017552857'⍳'6.66949809' -> 9 9 9 9 9 9 9 6 0 9
~⍴⍵    ⍝ Removed all non-found indexes from the list 9 9 9 9 9 9 9 6 0 9 -> 6 0
(⍳⍴⍵)                  ⍝ List of ascending integers up the length of the argument ⍵: 0 1 2 3 4 5 6 7 8
∘.-               ⍝ Inner product of the ascending integers 0..8 minus the match indexes 6 0. Result is ¯6 0, ¯5 1, .., 2 8
|                       ⍝ Absolute value of all elements
⌊/                        ⍝ Take the minimum of each pair to get the closest distance to a Holy number 0 1 2 3 2 1 0 1 2
+/                          ⍝ Sum this list


The reason for choosing GNU APL is that handily it will return the internal representation of infinity, '∞', when calculating the minimum value of the empty list. Summing this still retains ∞, which is then returned.

⍟788 was a cheeky way to lose a byte. I ended up writing a program to brute force inputs to functions until I found a suitable result which contained only holy numbers. Brute force program below:

    (,(⍳99)∘.{∧/(~'12357'∊c),'04689'∊(c←⍕b←⍺÷⍵):(⍺,'f',⍵,'=',b,'|') ⋄ 0}⍳99)~0


In this case it sees if any values of ⍺÷⍵ in 0 < ⍺,⍵ < 100 meet the condition. I manually played around with the functions to test.

It's a bit of a shame that this challenge doesn't allow undefined behaviour for the infinity case or that Dyalog doesn't return an infinite data type instead of throwing an error, otherwise the following solution would work in Dyalog APL:

# APL (Dyalog Unicode), 23 bytes

{+/⌊/|(⍳⍴⍵)∘.-⍸⍵∊⍕⍟788}


Try it online!

# Pyth, 312927 25 bytes

smhS.e?}b"04689"akd.n4zUz


Try it online: Demonstration or Test Suite

For each digit I compute the distances to each number. A distance is infinty, if the second digit is not holy. From these lists I take the minimal distance and sum it up.

### Explanation:

smhS.e?}b"04689"akd.n4zUz  implicit: z = input string of numbers
m                     Uz  map each d in [0, 1, ..., len(z)-1] to:
.e                z      map each k (index), b (value) of b to:
akd            absolute difference between k and d

?}b"04689"               if b in "04689" else
.n4         infinity
S                           sort
h                            take the first element (=minimum)
s                              print the sum


## JavaScript (ES6), 93 bytes

s=>[...s].map(n=>//.test(n)?++u:u=0,u=1/0).reverse().map(n=>r+=n?n<++u?n:u:u=0,r=0)&&r


If Infinity isn't a legal infinity, then add 13 bytes for ==1/0?'∞':r.

# Ruby (2.7+), 69 chars, 71 bytes

->n{x=!r=l=0;n.each_char{'04689'[_1]?x=l=0*r-=l*l/4:r+=l+=1};x ?r:?∞}


Unsupported by TIO

# Ruby (other), 71 chars, 73 bytes

->n{x=!r=l=0;n.each_char{|c|'04689'[c]?x=l=0*r-=l*l/4:r+=l+=1};x ?r:?∞}


Try it online!

## How it works:

• Iterate through the digits
• If a digit is holy
• reset increment
• subtract a number* from the score to correct the overcounting
• If a digit is unholy

*turns out this number depends only on the current value of the increment (l in the code), it's OEIS A002620 (quarter squares) (l*l/4 in the code).

Returns the ∞ character in case of infinity.

Interesting trick: x=l=0*r-=l*l/4 is equivalent to (r-=l*l/4;x=l=0) but using * instead of ; makes it a single statement allowing () to be dropped.

# 05AB1E, 20 bytes

ŽāĀISåƶZĀiāδαø€ßOë'∞


Explanation:

ŽāĀ                # Push compressed integer 40689
IS              # Push the input-string, converted to a list of digits
#  i.e. "085281755283" → [0,8,5,2,8,1,7,5,5,2,8,3]
å             # Check for each digit if it's in 40689 (1 if truthy; 0 if falsey)
#  → [1,1,0,0,1,0,0,0,0,0,1,0]
ƶ            # Multiply each value by its 1-based index
#  → [1,2,0,0,5,0,0,0,0,0,11,0]
Z           # Push the maximum of this list (without popping)
#  → 11
Āi         # If this maximum is not 0 (so there are holy digits present):
#   → 1 (truthy)
ā        #  Push a list in the range [1, list-length] (without popping the list)
#   → [1,2,3,4,5,6,7,8,9,10,11,12]
δ       #  Apply double-vectorized:
α      #   Take the absolute difference between each value
#    → [[0,1,2,3,4,5,6,7,8,9,10,11],[1,0,1,2,3,4,5,6,7,8,9,10],
#       [1,2,3,4,5,6,7,8,9,10,11,12],[1,2,3,4,5,6,7,8,9,10,11,12],
#       [4,3,2,1,0,1,2,3,4,5,6,7],[1,2,3,4,5,6,7,8,9,10,11,12],
#       [1,2,3,4,5,6,7,8,9,10,11,12],[1,2,3,4,5,6,7,8,9,10,11,12],
#       [1,2,3,4,5,6,7,8,9,10,11,12],[1,2,3,4,5,6,7,8,9,10,11,12],
#       [10,9,8,7,6,5,4,3,2,1,0,1],[1,2,3,4,5,6,7,8,9,10,11,12]]
ø     #  Then zip/transpose the list of lists; swapping rows/columns
#   → [[0,1,1,1,4,1,1,1,1,1,10,1],[1,0,2,2,3,2,2,2,2,2,9,2],
#      [2,1,3,3,2,3,3,3,3,3,8,3],[3,2,4,4,1,4,4,4,4,4,7,4],
#      [4,3,5,5,0,5,5,5,5,5,6,5],[5,4,6,6,1,6,6,6,6,6,5,6],
#      [6,5,7,7,2,7,7,7,7,7,4,7],[7,6,8,8,3,8,8,8,8,8,3,8],
#      [8,7,9,9,4,9,9,9,9,9,2,9],[9,8,10,10,5,10,10,10,10,10,1,10],
#      [10,9,11,11,6,11,11,11,11,11,0,11],[11,10,12,12,7,12,12,12,12,12,1,12]]
€ß   #  Get the minimum of each inner list
#   → [0,0,1,1,0,1,2,3,2,1,0,1]
O  #  And sum everything together
#   → 12
ë         # Else (no holy digits are present)
'∞      '#  Push string "∞" instead
# (after which the top of the stack is output implicitly as result)


See this 05AB1E tip of mine (section How to compress large integers?) to understand why ŽāĀ is 40689.

# Python 3, 96 bytes

lambda s:sum(min([9e999]+[abs(i-j)for j,c in enumerate(s)if c in'04689'])for i in range(len(s)))


Try it online!

# R, 100 bytes

sum(sapply(0:(d=log10(n<-scan()))+1,function(x)min(abs(x-which(n%/%10^(0:d)%%10%in%c(0,4,6,8,9))))))


Try it online!

# JavaScript (Node.js), 77 bytes

s=>s.reduce((m,c,i)=>m+Math.min(...s.map(c=>(i*i--)**.5+(174&1<<c?1/0:0))),0)


Try it online!