52
\$\begingroup\$

You are developing some code to generate ID numbers. Policy requires that no ID numbers include the digit sequence 666.

Create a function (or your language's equivalent) which takes a positive integer parameter and returns the next integer that does not include 666 when that integer is expressed in decimal. (60606 is fine, 66600 is not.)

Your code must not use a loop that adds one until it finds a result that fits the rules.

f(1) returns 2.
f(665) returns 667.
f(665999999) returns 667000000 without having looped a million times.
(Following examples added since the question was first posed.)
f(666666666) also returns 667000000.
f(66600) returns 66700.
f(456667) returns 456670.

UPDATE:
Replacing 666 with 667 won't work if there's more than one 666 in the input.

\$\endgroup\$
18
  • 1
    \$\begingroup\$ What about something like 456667? Should that return 456670, or are we only worried about a leading 666? \$\endgroup\$
    – Kyle Kanos
    Commented Apr 29, 2014 at 14:18
  • 11
    \$\begingroup\$ I think this would be better as code-golf than popularity-contest since there are such straightforward solutions. \$\endgroup\$ Commented Apr 29, 2014 at 16:08
  • 10
    \$\begingroup\$ @nyuszika7h but the result should be 66700. \$\endgroup\$ Commented Apr 29, 2014 at 17:07
  • 3
    \$\begingroup\$ as a real challenge, there should've also been a requirement to not have "666" anywhere in the code \$\endgroup\$
    – DLeh
    Commented Apr 30, 2014 at 19:18
  • 2
    \$\begingroup\$ Depending on your regex implementation, you could use '6{3}' to detect 666. \$\endgroup\$
    – celtschk
    Commented May 1, 2014 at 19:33

33 Answers 33

52
\$\begingroup\$

Python, no string manipulation

def f(n):
    n += 1
    p = 1
    m = n
    while m:
        if m % 1000 == 666:
            n += p - n % p
        p *= 10
        m /= 10
    return n

Works by finding powers of 10, p, where 666 appears, and adding p - n % p to n which replaces 666xxxxx with 66700000.

\$\endgroup\$
5
  • 6
    \$\begingroup\$ I like this in that if this was actually a real customer requirement, this implementation is non-hacky, sensible and efficient. \$\endgroup\$
    – RomanSt
    Commented Apr 29, 2014 at 14:32
  • \$\begingroup\$ Will this work with numbers that contain multiple instances of 666? \$\endgroup\$
    – supercat
    Commented Apr 29, 2014 at 15:48
  • 1
    \$\begingroup\$ Yes. The leftmost 666 is the only one that actually matters, and this algorithm fixes that one last. \$\endgroup\$ Commented Apr 29, 2014 at 16:20
  • 19
    \$\begingroup\$ @romkyns Post an actual real customer requirement to codegolf to trick other people into doing their work for them? That's evil! (hides) \$\endgroup\$
    – billpg
    Commented Apr 29, 2014 at 16:37
  • 3
    \$\begingroup\$ For everyone who uses python 3: This code does not work on python 3+, to run this code on python 3 you have to change m /= 10 to m //= 10. If you don't then m will become a float and the condition m % 1000 == 666 will continously be false and other "666" in n are left unchanged. \$\endgroup\$
    – Sirac
    Commented May 4, 2014 at 12:36
49
\$\begingroup\$

JavaScript (updated to work with all test cases)

The little-known truth is that there are actually four 6s, but one of the betrayed the others and polymorphed into code form to eradicate them from the world digits of the numbers. Here is that traitorous six:

    x=prompt(''+
  'Enter number');
 alert(      ( (~x[
'ind'+
'exOf']('666')))?(x 
.replace(/666(.*)$/,
function    (mat,g){
return       '667'+g
 ['re'+      'place'
 ](/./g,0)})):((+x+
    1+'').replace(
     666,667)));

Here is an explanation. First, beautify the code and remove useless stuff like ''+'string' and ((code)):

x = prompt('Enter number');
alert(
    ~x['indexOf']('666')
        ?
    x.replace(/666(.*)$/, function(mat,g) {
        return '667' + g['replace'](/./g,0)
    })
        :
    (+x+1+'').replace(666, 667)
);

Convert weird notations (like ~indexOf and ['replace']) into more common ones:

x = prompt('Enter number');
alert(
    x.indexOf('666') > -1
        ?
    x.replace(/666(.*)$/, function(mat, g) {
        return '667' + g.replace(/./g, 0)
    })
        :
    ((parseInt(x) + 1) + '').replace(666, 667)
);

And now simply understand that the algorithm goes like this:

  • If there is already a 666 in the input,

    • replace it with a 667.
    • replace every digit after that with a 0.
  • else,

    • add one to the number.
    • NOTE: we are now guaranteed to have either no 666, a 666 at the end of the string, or a 666 somewhere else that already has zeroes going to the end (think "carrying" when doing "manual" addition).
    • if there's a 666, replace it with a 667.

Old version (doesn't work for 666666666):

    s='Enter number';x
  =prompt(           ''+
 s);x=+x+
(-~![]);
x=(''+x).replace('666',
666+([][         +[]]+[])
[+[]]['l         ength'[
 'repla'+       'ce'](
  / /g,'')]);alert(x)

To understand this, let's first beautify it:

s = 'Enter number';
x = prompt('' + s);
x = +x + (-~![]);
x = ('' + x).replace('666',666+([][+[]]+[])[+[]]['l         ength'['repla'+'ce'](/ /g,'')]);
alert(x);

Now let's remove useless things like '' + string and 'str' + 'ing', remove the unnecessary s variable, and change weirdness like -~![] into 1:

x = prompt('Enter number');
x = +x + 1;
x = ('' + x).replace('666', 666+"undefined"[0]['l         ength'['replace'](/ /g,'')]);
alert(x);

'l ength'['replace'](/ /g,'') is simply "length":

x = prompt('Enter number');
x = +x + 1;
x = ('' + x).replace('666', 666+"undefined"[0].length);
alert(x);

And "undefined"[0] is "u", and "u".length is 1:

x = prompt('Enter number');
x = +x + 1;
x = ('' + x).replace('666', 666 + 1);
alert(x);

Now we're done! It should be pretty easy to understand now.

\$\endgroup\$
5
  • 13
    \$\begingroup\$ I like your answer but it fails for 666666666 \$\endgroup\$
    – Michael M.
    Commented Apr 29, 2014 at 13:18
  • 3
    \$\begingroup\$ @Michael Added new version! Works for 666666666, and the font of the 6 is fancier ;) \$\endgroup\$
    – Doorknob
    Commented Apr 29, 2014 at 21:14
  • 1
    \$\begingroup\$ Huh - using ~1 for != -1 is pretty cool. \$\endgroup\$
    – wchargin
    Commented Apr 30, 2014 at 2:02
  • \$\begingroup\$ @WChargin Too bad that doesn't work in LiveScript. I know this isn't code golf but I have a golfed version in my post for fun. \$\endgroup\$
    – user344
    Commented Apr 30, 2014 at 9:14
  • \$\begingroup\$ It does work in LiveScript :). ~a.indexOf('b') generates the correct JS, try it on livescript.net ! \$\endgroup\$
    – Ven
    Commented May 3, 2014 at 20:51
19
\$\begingroup\$

Applescript

This site doesn't have enough Applescript answers. Lets banish some demons!

property demon : "666"
property trinity : 1

on exorcise above possessed
    set possessed to possessed as text
    set relic to AppleScript's text item delimiters
    set AppleScript's text item delimiters to demon
    set deliverance to possessed's first text item
    if possessed is deliverance then
        set deliverance to possessed + trinity
    else
        set AppleScript's text item delimiters to trinity
        set compellingPower to ¬
            (count of possessed's characters) - ¬
            (count of deliverance's characters) - ¬
            (count of demon's characters)
        set deliverance to ¬
            deliverance & ¬
            demon + trinity & ¬
            last text item of (((10 ^ compellingPower) as integer) as text)
    end if
    set AppleScript's text item delimiters to relic
    return deliverance
end exorcise

log (exorcise above 666)
log (exorcise above 66666666)
log (exorcise above 1266612)
log (exorcise above 1212)

Log output:

(*667*)
(*66700000*)
(*1266700*)
(*1213*)

I'd wanted to get some of the more powerful quotes from The Exorcist into this, but that would have made this posted decidedly NSFW. You can read the IMDB page instead.

\$\endgroup\$
7
  • \$\begingroup\$ How do you run this without having OS X? \$\endgroup\$
    – user344
    Commented Apr 30, 2014 at 9:44
  • \$\begingroup\$ I think Applescript is pretty much dependent on OSX stackoverflow.com/questions/7642299/… - I'm not aware of any ports to other platforms. OS 9 did have a version of Applescript, though no guarantees that this script would run there. \$\endgroup\$ Commented Apr 30, 2014 at 14:23
  • 2
    \$\begingroup\$ It would have made the post Not For Safe Work? Dammit, my job isn't dangerous \$\endgroup\$
    – Cruncher
    Commented Apr 30, 2014 at 17:39
  • 1
    \$\begingroup\$ @Cruncher oops ;-) \$\endgroup\$ Commented Apr 30, 2014 at 17:43
  • 1
    \$\begingroup\$ +1 for the choice of variable names (and because apple script is cool). \$\endgroup\$
    – Floris
    Commented Apr 30, 2014 at 20:50
14
\$\begingroup\$

Perl

You said we must not increment in a loop. I'm not using any mathematical operators at all! Here is a pure regex-substitution approach (no guarantees it's safe for your sanity).

#!/usr/bin/perl

$_ = <>;

s/$/ ~0123456789/;
s/(?=\d)(?:([0-8])(?=.*\1(\d)\d*$)|(?=.*(1)))(?:(9+)(?=.*(~))|)(?!\d)/$2$3$4$5/g;
s/9(?=9*~)(?=.*(0))|~| ~0123456789$/$1/g;
s/(?!^)\G\d|(666)\d/${1}0/g;
s/666/667/g;

print($_)

The first three substitutions increment the number by one. I did solve that problem myself once, but it included a substitution that had to be looped until no more substitutions were made, so I used Andrew Cheong's approach instead.

The fourth substitution turns all digits following a 666 into zeros. The final substitution turns the remaining 666 into a 667.

As a bonus this will work with multiple integers in the input as long as they are separated by non-digit characters.

\$\endgroup\$
8
\$\begingroup\$

LiveScript

This is bending the rules. You see, you said I must not use a loop that adds one until it finds a correct result. So I subtract minus one instead!

nextId = (id) ->
  while (id + 1).toString!indexOf('666') != -1
    id -= -1
  id + 1

A golfed version in 53 48 45 bytes for fun:

n=(i)->(while~(i+1+'')indexOf(\666)=>i-=-1);i+1

Thanks to user1737909 for helping golf it further.

Tests

Requires Node.js with the LiveScript npm module or a compatible assert library.

assert = require \assert

assert.equal nextId(1), 2
assert.equal nextId(665), 667
assert.equal nextId(665999999), 667000000
assert.equal nextId(66600), 66700
assert.equal nextId(456667), 456670
\$\endgroup\$
12
  • 5
    \$\begingroup\$ It is going to fail horribly when you get to 665999, as your stack will explode. \$\endgroup\$
    – TimWolla
    Commented Apr 29, 2014 at 12:48
  • 9
    \$\begingroup\$ Very clever. You should be writing RFCs to spot loopholes like that. \$\endgroup\$
    – billpg
    Commented Apr 29, 2014 at 12:59
  • 1
    \$\begingroup\$ @TimWolla That's interesting. How did you find that? \$\endgroup\$
    – user344
    Commented Apr 29, 2014 at 14:52
  • 1
    \$\begingroup\$ @nyuszika7h: If you think about it, 666000 through 666999 will all fail... you'll be recursing at least 1000 times. \$\endgroup\$
    – alc
    Commented Apr 29, 2014 at 14:58
  • 1
    \$\begingroup\$ I don't have a particular reason, I guess. \$\endgroup\$
    – user344
    Commented Apr 29, 2014 at 16:28
6
\$\begingroup\$

Ruby

This is (I think) the first answer that works for 666666666. (Except the cheaty subtracting -1 answer. ;) )

x = gets.chomp.to_i + 1
p (x..x.to_s.gsub('666', '667').to_i).select{|i| !(i.to_s.index '666') }.min

I'm in a hurry now; explanation will be added later.

Update: much more efficient version (almost constant runtime I believe):

x = gets.chomp
if x.index '666'
    # replace ex. 6661234 with 6670000
    puts x.sub(/666(.*)/){ "667#{"0" * $1.length}" }
else
    # old algorithm (guaranteed to result in
    # 0 or 1 666s now)
    puts (x.to_i+1).to_s.sub(/666/, "667")
end
\$\endgroup\$
2
  • \$\begingroup\$ Actually, my answer works fine for 666666666. \$\endgroup\$
    – isaacg
    Commented Apr 29, 2014 at 13:56
  • \$\begingroup\$ Constant runtime is impossible. Even checking if a "666" exists is a linear problem. This is a strictly harder problem than that. \$\endgroup\$
    – Cruncher
    Commented Apr 30, 2014 at 17:36
4
\$\begingroup\$

PowerShell

($args[0]+1 -replace '(?<=666.*).','0') -replace '666', '667'
\$\endgroup\$
3
\$\begingroup\$

C#

148 137 chars

Was able to shave off a few chars thanks to @recursive

public static int f(int b){b++;var z=new Regex("666\\d*");var q=z.Replace(b+"","667",1);return int.Parse(q.PadRight((b+"").Length,'0'));}

Ungolfed:

public static int f(int b)
{
    b++;
    var z = new Regex("666[\\d]*");
    var q = z.Replace(b+"", "667", 1);
    return Int32.Parse(q.PadRight((b+"").Length, '0')); 
}

Fiddle: http://dotnetfiddle.net/XB83bf

\$\endgroup\$
6
  • 1
    \$\begingroup\$ The square brackets in your regex are unnecessary, and there are also a lot of syntactically unnecessary spaces. \$\endgroup\$
    – recursive
    Commented Apr 29, 2014 at 16:00
  • \$\begingroup\$ Oh, and Int32 can be replaced with int. \$\endgroup\$
    – recursive
    Commented Apr 29, 2014 at 16:01
  • \$\begingroup\$ @recursive You are correct, thanks! \$\endgroup\$
    – Trying
    Commented Apr 29, 2014 at 16:07
  • \$\begingroup\$ Note this is a popularity-contest and not code-golf. Having said that if you feel shaving off characters will make your answer more popular, then go for it! \$\endgroup\$ Commented Apr 29, 2014 at 18:14
  • 2
    \$\begingroup\$ First I have seen of dotnetfiddle.net =) AWESOME! \$\endgroup\$
    – Paul C
    Commented Apr 30, 2014 at 15:48
3
\$\begingroup\$

J

Finally, a good use for E.!

(({.~ , '667' {.!.'0'~ #@[ - ]) '666'&E. i. 1:) @ ": @ >:

In essence, we find the first position in which the argument has a full 666, and we replace that substring and everything after with 66700000... until the end.

Explained in detail:

  • ":@>: - Increment by one and convert to string.
  • '666'&E. - Make a vector of booleans, true in each place that '666' begins in the string.
  • i.1: - Find the index of the first true in the vector, else return the length of the vector.
  • #@[-] - Length of the string (which is also the length of the vector) minus the result of i..
  • '667'{.!.'0'~ - Take a substring of '667' with a length of that result, padding on the right with '0' if necessary.
  • {.~ - Take a substring with the length of the original result from i..
  • , - Append the two together.

In use:

   f =: (({.~,'667'{.!.'0'~#@[-])'666'&E.i.1:)@":@>:
   f 1              NB. this leaves okay numbers untouched
2
   f 665999999      NB. properly handles multiple increments
667000000
   f 16266366646666 NB. only takes effect at sets of 3 sixes
16266366700000

And since this isn't a code golf, this doesn't have to get golfed to hell with crazy optimizations. Everybody wins!

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

Python

def next_id(id_num):
  id_num_p1=str(id_num+1)
  pieces=id_num_p1.split('666')
  if len(pieces)==1:
    return id_num+1
  next_id_str=pieces[0]+'667'+'0'*(len(id_num_p1)-len(pieces[0])-3)
  return int(next_id_str)
\$\endgroup\$
2
\$\begingroup\$

J

No strings, loops or conditionals:

   next =: 3 :'<.(y+1)(+-|~)10^<:666 i:~666,1000|<.(y+1)%10^i.<.10^.>:y'

   next 1
2
   next 665
667
   next 665999999
667000000
   next 666666666
667000000
   next 66600
66700

Similarly to cardboard_box's solution, this separates the number into groups of three digits by dividing by powers of ten. It uses the index of the first occurrence of 666 to round the number up appropriately.

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

Haskell (70 characters)

Here is a simple implementation in Haskell.

import Data.List
import Data.Char

nextid :: Integer -> Integer
nextid = foldl' ((+).(*10)) 0 . purge . map digitToInt . show . (+1)
  where purge (6:6:6:xs) = 6 : 6 : 7 : map (const 0) xs
        purge (x:xs)     = fromIntegral x : purge xs
        purge []         = []
  • Firstly, it uses map digitToInt . show to convert a possibly evil ID to a list of digits.
  • Next, purge matches the evil pattern and replaces it with its good equivalent.
  • Finally, foldl' ((+).(*10)) 0 reduces the list of digits to one Integer.

Let's see if it works!

ghci> nextid 1
2
ghci> nextid 665
667
ghci> nextid 665999999
667000000
ghci> nextid 666666666
667000000
ghci> nextid 66600
66700
ghci> nextid 456667
456670
ghci> nextid 6660239486660239466
6670000000000000000

Looks good. And just for fun a golfed version.

f=read.w.show.(+1);w('6':'6':'6':t)="667"++(t>>"0");w(h:t)=h:w t;w t=t
\$\endgroup\$
1
\$\begingroup\$

Java

Isn't it enough to do this?

private static int nextId(int currentId) {
    String currentIdStr = String.valueOf(currentId);
    return currentIdStr.contains("666") ? Integer.parseInt(currentIdStr.replace("666", "667")) : ++currentId;
}
\$\endgroup\$
4
  • \$\begingroup\$ Close, but that should be String.valueOf(currentId + 1). \$\endgroup\$
    – user344
    Commented Apr 29, 2014 at 12:10
  • \$\begingroup\$ Oh right, I forgot that +1 thingy! :D \$\endgroup\$ Commented Apr 29, 2014 at 12:12
  • \$\begingroup\$ That conditional is useless; the original solution slightly modified per my suggestion will work too: return Integer.parseInt(String.valueOf(currentId + 1).replace("666", "667")); \$\endgroup\$
    – user344
    Commented Apr 29, 2014 at 12:23
  • 1
    \$\begingroup\$ Not true... 66600 would be returned as 66701, which is 1 too high. \$\endgroup\$ Commented Apr 29, 2014 at 12:39
1
\$\begingroup\$

R

Replacing 666 with 667 works.

f <- function(x) {
  x <- as.integer(x + 1)
  if (grepl(666, x)) {
    k <- regexpr(666, x)
    cat(substring(x, 1, k + 1), 7, rep(0, nchar(x) - k - 2), sep = "")
  }
  else cat(x)
}

Results

> f(1)
2
> f(665)
667
> f(665999999)
667000000
> f(666666666)
667000000
> f(66600)
66700
> f(126660)
126670
> f(126661)
126670
> f(666666666)
667000000
\$\endgroup\$
1
\$\begingroup\$

Perl

$_++;$_.=$/;s:666(.*):667 .'0'x($+[1]-$-[1]):e

Inline code which changes the content inside $_, a pretty standard ideology in perl. Can be used in conjunction with -p flag like this:

$ perl -p % <<< 66666
66700
\$\endgroup\$
1
\$\begingroup\$

3 Different JavaScript answers:

1. JavaScript (ECMAScript 6)

f=x=>(a=b=c=0,[c?'0':a+(a=b)+(b=i)==666?(c='7'):i for(i of ""+(x+1))].join('')*1)

Converts the number to a string then iterates over each character until it finds 666 then it changes that last 6 to a 7 and outputs 0 for all following characters.

2. JavaScript (ECMAScript 6 Draft)

Recursive function without string manipulation:

g=(x,y=x+1,p=1)=>y?g(y%1e3==666?y*p+p:y>x?y:x,y/10|0,p*10):x

Or more verbosely:

function g(x,y=x+1,p=1)
{
  if ( y == 0 )
    return x;
  else if ( y % 1000 == 666 )
    return g( y*p+p, Math.floor(y/10), p*10 );
  else
    return g( Math.max(y, x), Math.floor(y/10), p*10 );
}

Tests:

g(5) // 6
g(65) // 66
g(665) // 667
g(66599) // 66700
g(66666) // 66700
g(6656665665) // 6656670000

3. JavaScript

Using regular expressions:

function h(x)(""+(x+1)).replace( /^(.*?)(666)(.*)$/, function(a,b,c,d)(b+667+d.replace(/./g,0)) )*1

Or (the same but using ECMAScript 6)

h=x=>(""+(x+1)).replace(/^(.*?)(666)(.*)$/,(a,b,c,d)=>b+667+d.replace(/./g,0))*1
\$\endgroup\$
2
  • \$\begingroup\$ With your first version, if you enter 6 septillion, 666 sextillion you get a return value of 6.667 so technically it's still there. Don't think it can be helped though. \$\endgroup\$
    – Spedwards
    Commented May 4, 2014 at 14:01
  • \$\begingroup\$ 1e20 is about the largest order of magnitude that JavaScript (at least in FireFox) will print as an integer without resorting to scientific notation. \$\endgroup\$
    – MT0
    Commented May 4, 2014 at 16:24
1
\$\begingroup\$

AWK

awk '{i=index(++$0,"666")}
      i{a=substr($0,1,i-1)
       b=substr($0,i+3)
       gsub(/./,0,b)
       $0=a"667"b}
      1
' <<_INPUT_
1
665
665999999
666666666
66600
_INPUT_

gives

2
667
667000000
667000000
66700

edit: 2nd solution

awk -F666 -vOFS=667 '{++$0;$1=$1}
    NF-1{for(gsub(/./,0,$2);NF>2;--NF){$2=$2 0 0 0
               for(i=length($NF);i;--i)$2=$2 0}}1
' <<_INPUT_
1
665
665999999
666666666
66600
1236661
_INPUT_

yields

2
667
667000000
667000000
66700
1236670
\$\endgroup\$
5
  • 1
    \$\begingroup\$ which doesn't seem to be correct answers. 665 should give 667, 66600 should give 66700 etc \$\endgroup\$
    – user12205
    Commented Apr 29, 2014 at 14:25
  • 1
    \$\begingroup\$ Your results contain a lot of "666" substrings. \$\endgroup\$ Commented Apr 29, 2014 at 14:28
  • \$\begingroup\$ That's embarrassing. I fixed the 2(!) fence-post-errors I made because I forgot that awk indexes strings 1-based. \$\endgroup\$
    – mschilli
    Commented Apr 29, 2014 at 15:56
  • \$\begingroup\$ @Cruncher As explicitly stated in the question, f(665) returns 667 as it is asking for "the next integer that does not include 666" \$\endgroup\$
    – user12205
    Commented Apr 30, 2014 at 17:48
  • \$\begingroup\$ I added a 2nd way that is a) more awkish and b) minimizes the use of string functions. \$\endgroup\$
    – mschilli
    Commented May 4, 2015 at 7:25
0
\$\begingroup\$

Python:

def f(b):
    b = `b+1`
    while '666' in b: b = b.replace('666','667',1)
    return int(b)

Or:

 f=lambda b:int(`b+1`.replace('666','667'))
\$\endgroup\$
2
  • \$\begingroup\$ I don't see how that works. Wouldn't that turn 666666 into 667667 instead of 667000? \$\endgroup\$ Commented Apr 29, 2014 at 16:35
  • \$\begingroup\$ @m.buettner Good point, I think I already have an solution. \$\endgroup\$ Commented Apr 29, 2014 at 16:56
0
\$\begingroup\$

Java

public static int f(int i) {
    i++;
    i += findAdjustment(i);
    return i;
}

private static int findAdjustment(int i) {
    if (i < 666) {
        return 0;
    }
    int adjustment = findAdjustment(i / 10);
    if (adjustment != 0) {
        // Leftmost 666 found, fix adjustment by current last digit
        return adjustment * 10 - i % 10;
    } else if (i % 1000 == 666) {
        return 1; // This is leftmost 666, need to be corrected by 1
    } else {
        return 0; // no adjustment needed
    }
}

Using recursive function to find leftmost 666 and calculation how much to adjust the number when popping the call stack again.

\$\endgroup\$
5
  • \$\begingroup\$ I don't think this code is correct. What result does it give for input 666666666? \$\endgroup\$ Commented Apr 29, 2014 at 13:09
  • \$\begingroup\$ You are right, didn't realise that the input already could contain Evil numbers. So f(666666666) -> 667667667? \$\endgroup\$ Commented Apr 29, 2014 at 13:28
  • \$\begingroup\$ f(666666666) -> 667000000 \$\endgroup\$
    – djhurio
    Commented Apr 29, 2014 at 13:34
  • \$\begingroup\$ @djhurio Seems I can not generate tests for edge cases today. Believe I have it fixed now, but the code is not so short any more. \$\endgroup\$ Commented Apr 29, 2014 at 14:01
  • 1
    \$\begingroup\$ @RogerLindsjö This is a popularity-contest, not a code-golf. \$\endgroup\$
    – user344
    Commented Apr 29, 2014 at 18:39
0
\$\begingroup\$

Batch

Simple iterated string manipulation.

@echo off

setLocal enableDelayedExpansion
set /a inp=%1+1
for /f usebackq %%a in (`powershell "&{'%inp%'.length-1}"`) do (
    set a len=%%a-2
    set chars=%%a
)

for /l %%b in (0, 1, %len%) do (
    if "!inp:~%%b,3!"=="666" (
        set inp=!inp:~0,%%b!667
        set /a a=%%b+3
        for /l %%c in (!a!, 1, %chars%) do set inp=!inp!0
        goto :break
    )
)

:break

echo %inp%

It starts at the first three characters of the number (as a string), and works its way to the end until it finds 666, it then replaces that 666 with 667, and loops to the length of the string adding zeros.

The test cases all produce the correct results.

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

perl, 45 bytes

A single regex with the /e flag does all the work here:

$_=<>+1;s/666(.*)$/"667".0 x length$1/e;print
\$\endgroup\$
0
\$\begingroup\$

SQL

To be precise, SQL Server 2012 Transact-SQL.

create function dbo.GoodIntegers( @i bigint )
returns bigint
as begin
    declare @s varchar(20) = cast( @i+1 as varchar(20) ) ;
    declare @badindex int = charindex( '666', @s ) ;
    declare @rv bigint  = cast ( 
        iif( @badindex = 0 ,
            @s ,
            concat( left( @s, @badindex - 1 ), '667', replicate( '0', len( @s ) - @badindex - 2 ) )
        ) as bigint 
    ) ;
    return @rv ;
end ; -- function dbo.GoodIntegers
\$\endgroup\$
0
\$\begingroup\$

Python

import re
def exorcise(number):
    number = str(number+1)
    i = re.compile("^(\d*?)(666)(\d*)$")
    if re.match(i,number):
        n = re.match(i,number).groups()
        return int(n[0]+"667"+"".join(["0"*len(n[2])]))
    return int(number)
\$\endgroup\$
0
\$\begingroup\$

Julia

function f(x::Int)
    y = string(x+1)
    n = length(y)
    z = string(^("0",n))
    ~ismatch(r"6{3}", y) ?
    int(y) :
    while ismatch(r"6{3}",y)
        m = match(r"6{3}", y)
        y = string(y[1:m.offset+1], '7', z[m.offset+3:n])
    end
    int(y)
end

REPL results

julia> f(1)
2

julia> f(665)
667

julia> f(665999999)
667000000

julia> f(666666666)
667000000

julia> f(66600)
66700

julia> f(456667) 
456670
\$\endgroup\$
0
\$\begingroup\$

C#

Am I doing it right

static int F(int n)
{
    n++;

    int a = 666;
    int b = 1;

    while (n >= b)
    {
        if (((n - a) / b) % 1000 == 0)
        {
            n += b;
        }

        a *= 10;
        b *= 10;
    }

    return n;
}
\$\endgroup\$
0
\$\begingroup\$

vba

Function f(num As Long) As Long
Dim SixPos As Long
Dim s As String
s = CStr(num)
SixPos = InStr(s, "666")
If SixPos = 0 Then
    s = CStr(num + 1)
    SixPos = InStr(s, "666")
End If
If SixPos Then
    Mid(s, SixPos + 2, 1) = "7"
    If Len(s) > SixPos + 2 Then
        Mid(s, SixPos + 3, Len(s) - SixPos + 3) = String$(Len(s) - SixPos + 3, "0")
    End If
End If

f = CLng(s)

End Function

In action:

Sub demo()
Debug.Print f(1) 'returns 2.
Debug.Print f(665) 'returns 667.
Debug.Print f(665999999) 'returns 667000000 without having looped a million times.
'(Following examples added since the question was first posed.)
Debug.Print f(666666666) 'also returns 667000000.
Debug.Print f(66600) 'returns 66700.
Debug.Print f(456667) 'returns 456670.
End Sub

result:

2 
667 
667000000 
667000000 
66700 
456670 
\$\endgroup\$
0
\$\begingroup\$

C++

I know this isn't code-golf, but (a) some people have suggested that it is a good golf challenge, and (b) this is my first challenge/golf answer, I thought it would be fun, and if I do this here I don't get shown up in an actual golf challenge for being a terrible golfer. X)

Basically, replaced '666' with '667' works if you do it for the first instance in the number and then write out trailing 0s.

Golfed (175 155 chars):

#include<sstream>
int f(int x){std::stringstream s,o;s<<++x;x=0;for(char c=s.get();!s.eof();c=s.get())o<<((x+=c=='6')++==3?'7':--x>3?'0':c);o>>x;return x;}

Ungolfed:

#include<sstream>
int f(int x){
    std::stringstream s,o;
    s<<++x;    // Increment to next int.
    x=0;       // Reusing this to count 6s
    for(char c=s.get();!s.eof();c=s.get()){    // For each digit
        if (c=='6'){
           ++x;    // Count sixes...
        }
        if(x==3) {  // Devil's number!
            c='7'; // Output 7 here.
            ++x;   // Increment once more.
        } else if (x > 3) {
            c='0';    // Already replaced 666 with 667, so write out 0s
        }
        o<<c;   // Append digit
    }
    o>>x; // Get int
    return x;
}
\$\endgroup\$
3
  • \$\begingroup\$ I think you don't need x+=c=='6'?1:0, you can get away with x+=c=='6'. Haven't tried it, though. \$\endgroup\$
    – user344
    Commented May 1, 2014 at 15:29
  • \$\begingroup\$ Also, you left out the std:: before stringstream. It doesn't compile without that. \$\endgroup\$
    – user344
    Commented May 1, 2014 at 15:32
  • \$\begingroup\$ Added std::, thanks for that @nyuszika7h. I made the mistake of using an IDE that autogenerated 'using namespace std;' to test it in. -_- I will try the x+=c=='6' reduction, as well as looking at doing this with int digits rather than sstream chars... \$\endgroup\$
    – mike32
    Commented May 1, 2014 at 18:27
0
\$\begingroup\$

Ruby

n=(gets.chomp.to_i+1).to_s
i=n.index("666")
if i!=nil
    n=n[0..i+1]+"7"+"0"*(n.length-i-3)
end
puts n
\$\endgroup\$
0
\$\begingroup\$

perl, 36 just a sub, no bytes

A shorter version than my last solution, using a mix of arithmetic and regex ops.

sub{($_[0]+1)=~s/666(.*)/667$1/r-$1}
\$\endgroup\$
1
  • \$\begingroup\$ print+(<>+1)=~s/666(.*)/667$1/r-$1 (saved you a byte)(two more if you use say) - although the request was for a function so remove print+ and use sub{ ... } \$\endgroup\$
    – Altreus
    Commented Apr 30, 2014 at 12:06
0
\$\begingroup\$

C

#include <stdlib.h>
#include <stdio.h>

int next(int a)
{
    for(int b=a+1,c=0,d=0; b>665 ;b/=10, c++)
        if(b%1000==666) {d=c; a=b;}

    a++;
    while(d --> 0) a*=10;

    return a;
}

void main(int a, char *v[])
{
    int c = a>1?atoi(v[1]):0;

    printf("%d\n",next(c));
}

OK - no bounds checking and far too much whitespace but it's not golf. Also a fun bit of formatting in "while (d --> 0)".

\$\endgroup\$

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