# Overview

Some of you might be aware of the Kolakoski Sequence (A000002), a well know self-referential sequence that has the following property:

It is a sequence containing only 1's and 2's, and for each group of 1's and twos, if you add up the length of runs, it equals itself, only half the length. In other words, the Kolakoski sequence describes the length of runs in the sequence itself. It is the only sequence that does this except for the same sequence with the initial 1 deleted. (This is only true if you limit yourself to sequences made up of 1s and 2s - Martin Ender)

# The Challenge

The challenge is, given a list of integers:

• Output -1 if the list is NOT a working prefix of the Kolakoski sequence.
• Output the number of iterations before the sequence becomes [2].

# The Worked Out Example

Using the provided image as an example:

[1,2,2,1,1,2,1,2,2,1,2,2,1,1,2,1,1] # Iteration 0 (the input).
[1,2,2,1,1,2,1,2,2,1,2]             # Iteration 1.
[1,2,2,1,1,2,1,1]                   # Iteration 2.
[1,2,2,1,2]                         # Iteration 3.
[1,2,1,1]                           # Iteration 4.
[1,1,2]                             # Iteration 5.
[2,1]                               # Iteration 6.
[1,1]                               # Iteration 7.
[2]                                 # Iteration 8.


Therefore, the resultant number is 8 for an input of [1,2,2,1,1,2,1,2,2,1,2,2,1,1,2,1,1].

9 is also fine if you are 1-indexing.

# The Test Suite (You can test with sub-iterations too)

------------------------------------------+---------
Truthy Scenarios                          | Output
------------------------------------------+---------
[1,1]                                     | 1 or 2
[1,2,2,1,1,2,1,2,2,1]                     | 6 or 7
[1,2,2,1,1,2,1,2,2,1,2,2,1,1,2,1,1]       | 8 or 9
[1,2]                                     | 2 or 3
------------------------------------------+---------
Falsy Scenarios                           | Output
------------------------------------------+---------
[4,2,-2,1,0,3928,102904]                  | -1 or a unique falsy output.
[1,1,1]                                   | -1
[2,2,1,1,2,1,2] (Results in [2,3] @ i3)   | -1 (Trickiest example)
[]                                        | -1
[1]                                       | -1


If you're confused:

Truthy: It will eventually reach two without any intermediate step having any elements other than 1 and 2. – Einkorn Enchanter 20 hours ago

Falsy: Ending value is not [2]. Intermediate terms contain something other than something of the set [1,2]. A couple other things, see examples.

This is , lowest byte-count will be the victor.

• Can we use any falsey value instead of just -1? – mbomb007 Jun 28 '17 at 20:05
• What do you mean by "NOT a working prefix of the Kolakoski sequence"? I had assumed you meant the list does not eventually reach [2] until I saw the [2,2,1,1,2,1,2] test case. – ngenisis Jun 28 '17 at 21:42
• @ngenisis It will eventually reach two without any intermediate step having any elements other than 1 and 2. – Wheat Wizard Jun 29 '17 at 0:27
• Might be a good idea to add [1] as a test case. – Emigna Jun 29 '17 at 9:54
• @mbomb007 any distinct value is fine. A positive integer is not fine. If you're 1-indexing 0 is fine. "False" is fine. Erroring is fine. Any non-positive return value is fine, even -129.42910. – Magic Octopus Urn Jun 29 '17 at 15:33

39 bytes saved thanks to Ørjan Johansen

import Data.List
f[2]=0
f y@(_:_:_)|all(elem[1,2])y=1+f(length<$>group y)  Try it online! This errors on bad input. • f (and consequently !) can be shortened a lot by using lazy production + span/length instead of accumulators. Try it online! – Ørjan Johansen Jun 29 '17 at 2:41 • Seem to enter an infinite loop for [1] – Emigna Jun 29 '17 at 9:59 • @Emigna Darn. It costs me 6 bytes to fix it, but I've fixed it. – Wheat Wizard Jun 29 '17 at 14:32 • @ØrjanJohansen That seems like a good tip, but I'm not proficient enough in Haskell to understand whats going on there. If you want you can post it as your own answer but at least as long as I don't know how your solution works, I'm not going to add it to my answer. :) – Wheat Wizard Jun 29 '17 at 14:36 • I then realized this is a case where an import is actually shorter (and also simpler to understand): import Data.List;f l=length<$>group l. (<$> is a synonym for map here.) Also, instead of having two different -1 cases it is shorter to use a @(_:_:_) pattern to force the main case to only match length >=2 lists. Try it online! – Ørjan Johansen Jun 30 '17 at 0:44 # 05AB1E, 22 bytes [Dg2‹#γ€gM2›iX]2QJiNë®  Try it online! Explanation [ # start a loop D # duplicate current list g2‹# # break if the length is less than 2 γ # group into runs of consecutive equal elements €g # get length of each run M2›iX # if the maximum run-length is greater than 2, push 1 ] # end loop 2QJi # if the result is a list containing only 2 N # push the iteration counter from the loop ë® # else, push -1 # implicitly output top of stack  • Fails for [1,1,2,2,1,2,1,1,2,2,1,2,2,1,1,2,1,1] – Weijun Zhou Mar 24 '18 at 10:04 • @WeijunZhou: Thanks, fixed! – Emigna Mar 24 '18 at 10:50 • You may have forgotten to update the link ... – Weijun Zhou Mar 24 '18 at 10:56 • @WeijunZhou: Indeed I had. Thanks again :) – Emigna Mar 24 '18 at 10:58 # SCALA, 290(282?) chars, 290(282?) bytes It took me sooo loong ... But I'm finally done! with this code : var u=t var v=Array[Int]() var c= -1 var b=1 if(!u.isEmpty){while(u.forall(x=>x==1|x==2)){c+=1 if(u.size>1){var p=u.size-1 for(i<-0 to p){if(b==1){var k=u(i) v:+=(if(i==p)1 else if(u(i+1)==k){b=0 if(p-i>1&&u(i+2)==k)return-1 2}else 1)} else b=1} u=v v=v.take(0)}else if(u(0)==2)return c}} c  I don't know if I should count the var u=t into the bytes, considering I do not use t during the algorithm (the copy is just to get a modifyable var instead of the parameter t considered as val - thanks ScaLa). Please tell me if I should count it. Hard enough. Try it online! PS : I was thinking of doing it recursively, but I'll have to pass a counter as a parameter of the true recursive "subfunction" ; this fact makes me declare two functions, and these chars/bytes are nothing but lost. EDIT : I had to change (?) because we're not sure we should take in count [1] case. So here is the modified code : var u=t var v=Array[Int]() var c= -1 var b=1 if(!u.isEmpty){try{t(1)}catch{case _=>return if(t(0)==2)0 else -1} while(u.forall(x=>x==1|x==2)){c+=1 if(u.size>1){var p=u.size-1 for(i<-0 to p){if(b==1){var k=u(i) v:+=(if(i==p)1 else if(u(i+1)==k){b=0 if(p-i>1&&u(i+2)==k)return-1 2}else 1)} else b=1} u=v v=v.take(0)}else if(u(0)==2)return c}} c  It's not optimized (I have a duplicate "out" for the same conditions : when I get to [2] and when param is [2] is treated separatedly). NEW COST = 342 (I didn't modify the title on purpose) • Seem to enter an infinite loop for [1] – Emigna Jun 29 '17 at 10:01 • Yep, but as said by the OP (as I understood at least) : "with the initial 1 deleted" and "Output the number of iterations before the sequence becomes [2]" – V. Courtois Jun 29 '17 at 10:03 • To my understanding, [1] never reaches [2] and should thus return -1. – Emigna Jun 29 '17 at 10:06 • I see. So do you think I should put a litte condition at start? Thanks for your advice. – V. Courtois Jun 29 '17 at 10:09 • I don't know scala but I assume you can just modify the loop to stop when the length of the list is smaller than 2. You already seem to have the check that the element is 2 at the end. – Emigna Jun 29 '17 at 10:11 # Jelly, 26252221 20 bytes FQœ-2R¤ ŒgL€µÐĿṖ-LÇ?  Try it online! This code actually wasn't working correctly until 20 bytes and I didn't even notice; it was failing on the [2,2] test case. Should work perfectly now. # Jelly, 17 bytes ŒgL€$ÐĿµẎḟ1,2ȯL_2


Try it online!

# JavaScript, 146 142 bytes

First try in code golfing, it seems that the "return" in the larger function is quite tedious...

Also, the checking of b=1 and b=2 takes up some bytes...

Here's the code:

f=y=>{i=t=!y[0];while(y[1]){r=[];c=j=0;y.map(b=>{t|=b-1&&b-2;if(b-c){if(j>0)r.push(j);c=b;j=0}j++});(y=r).push(j);i++}return t||y[0]-2?-1:0^i}


Explanation

f=y=>{/*1*/}                                        //function definition

//Inside /*1*/:
i=t=!y[0];                                        //initialization
//if the first one is 0 or undefined,
//set t=1 so that it will return -1
//eventually, otherwise i=0
while(y[1]){/*2*/}                                //if there are 2+ items, start the loop

//Inside /*2*/:
r=[];c=j=0;                                     //initialization
y.map(b=>{/*3*/});                              //another function definition

//Inside /*3*/:
t|=b-1&&b-2;                                  //if b==1 or b==2, set t=1 so that the
//entire function returns -1
if(b-c){if(j>0)r.push(j);c=b;j=0}             //if b!=c, and j!=0, then push the
//count to the array and reset counter
j++                                           //counting duplicate numbers

(y=r).push(j);i++                               //push the remaining count to the array
//and proceed to another stage

return t||y[0]-2?-1:0^i                           //if the remaining element is not 2, or
//t==1 (means falsy), return -1,
//otherwise return the counter i


Test data (using the given test data)

l=[[1,1],[1,2,2,1,1,2,1,2,2,1],[1,2,2,1,1,2,1,2,2,1,2,2,1,1,2,1,1],[1,2],[4,2,-2,1,0,3928,102904],[1,1,1],[2,2,1,1,2,1,2],[]];
console.log(l.map(f));
//Output: (8) [1, 6, 8, 2, -1, -1, -1, -1]


Edit 1: 146 -> 142: Revoking my edit on reducing bytes, because this affects the output; and some edit on the last statement

• f=a=>{for(i=t=!a[0];a[1];)r=[],c=j=0,a.map(a=>{t|=a-1&&a-2;a-c&&(0<j&&r.push(j),c=a,j=0);j++}),(a=r).push(j),i++;return t||a[0]-2?-1:0^i} saves 5 bytes (for loop instead of while; commas vs braces; && vs if). You can use google's closure compiler (closure-compiler.appspot.com) to get these optimisations done for you – Oki Jun 29 '17 at 12:05

## JavaScript (ES6), 12712695 80 bytes

g=(a,i,p,b=[])=>a.map(x=>3>x&0<x?(x==p?b[0]++:b=[1,...b],p=x):H)==2?i:g(b,~~i+1)


0-indexed. Throws "ReferenceError: X is not defined" and "InternalError: too much recursion" on bad input.

### Test cases

g=(a,i,p,b=[])=>a.map(x=>3>x&0<x?(x==p?b[0]++:b=[1,...b],p=x):H)==2?i:g(b,~~i+1)

function wrapper(testcase) {
try {console.log(g(testcase))} catch(e) {
console.log("Error")
}
}

wrapper([1,1])
wrapper([1,2,2,1,1,2,1,2,2,1])
wrapper([1,2,2,1,1,2,1,2,2,1,2,2,1,1,2,1,1])
wrapper([1,2])
wrapper([4,2,-2,1,0,3928,102904])
wrapper([1,1,1])
wrapper([2,2,1,1,2,1,2])
wrapper([])
wrapper([1])

## Clojure, 110 bytes

#(if-not(#{[][1]}%)(loop[c % i 0](if(every? #{1 2}c)(if(=[2]c)i(recur(map count(partition-by + c))(inc i))))))


A basic loop with a pre-check on edge cases. Returns nil for invalid inputs. I did not know (= [2] '(2)) is true :o

# Python 2, 146 bytes (function only)

f=lambda l,i=0:i if l==[1]else 0if max(l)>2or min(l)<1else f([len(x)+1for x in"".join(v!=l[i+1][0]for i,v in enumerate(l[:-1])).split("T")],i+1)


Returns 0 on falsy input (ok since it's 1-indexed). Simply use it like this:

print(f([1,2,2,1,1,2,1,2,2,1,2,2,1,1,2,1,1]))


## Mathematica, 82 bytes

FixedPointList[#/.{{2}->T,{(1|2)..}:>Length/@Split@#,_->0}&,#]~FirstPosition~T-1&


Function which repeatedly replaces {2} with the undefined symbol T, a list of (one or more) 1s and 2s with the next iteration, and anything else with 0 until a fixed point is reached, then returns the FirstPosition of the symbol T in the resulting FixedPointList minus 1. Output is {n} where n is the (1-indexed) number of iterations needed to reach {2} for the truthy case and -1+Missing["NotFound"] for the falsy case.

If the output must be n rather than {n}, it costs three more bytes:

Position[FixedPointList[#/.{{2}->T,{(1|2)..}:>Length/@Split@#,_->0}&,#],T][[1,1]]-1&


# Python 2, 184 163 156 bytes

• @Felipe Nardi Batista saved 21 bytes!!!! thanks a lot!!!!
• Halvard Hummel saved 7 bytes!! thanks

# Python 2, 156 bytes

a,c=input(),0
t=a==[]
while 1<len(a)and~-t:
r,i=[],0
while i<len(a):
j=i
while[a[j]]==a[i:i+1]:i+=1
r+=[i-j]
a=r;c+=1;t=any(x>2for x in a)
print~c*t+c


Try it online!

Explanation:

a,c=input(),0                             #input and initialize main-counter

t=a==[]                                   #set t to 1 if list's empty.

while len(a)>1:                           #loop until list's length is 1.

r,i=[],0                                 #Initialize temp. list and
#list-element-pointer

while i<len(a):                          #loop for the element in list

j=0                                     #set consecutive-item-counter to 0

while(i+j)<len(a)and a[i]==a[i+j]:j+=1  #increase the consec.-counter

r+=[j];i+=j                             #add the value to a list, move the
#list-element-pointer

a=r;c+=1;t=any(x>2for x in a)            #update the main list, increase t
#the counter, check if any number
if t:break;                              #exceeds 2 (if yes, exit the loop)

print[c,-1][t]                            #print -1 if t or else the
#counter's
#value


# R, 122 bytes

a=scan()
i=0
f=function(x)if(!all(x%in%c(1,2)))stop()
while(length(a)>1){f(a)
a=rle(a)$l f(a) i=i+1} if(a==2)i else stop()  Passes all test cases. Throws one or more errors otherwise. I hate validity checks; this code could have been so golfed if the inputs were nice; it would be shorter even in case the input were a sequence of 1’s and 2’s, not necessarily a prefix of the Kolakoski sequence. Here, we have to check both the initial vector (otherwise the test case [-2,1]) would have passed) and the resulting vector (otherwise [1,1,1] would have passed). # Python 2, 122 bytes def f(s,c=2,j=0): w=[1] for i in s[1:]:w+=[1]*(i!=s[j]);w[-1]+=i==s[j];j+=1 return(w==[2])*c-({1,2}!=set(s))or f(w,c+1)  Try it online! # Python 3, 120 bytes def f(s,c=2,j=0): w=[1] for i in s[1:]:w+=[1]*(i!=s[j]);w[-1]+=i==s[j];j+=1 return(w==[2])*c-({1,2}!={*s})or f(w,c+1)  Try it online! # Explanation A new sequence (w) is initialized to store the next iteration of the reduction. A counter (c) is initalized to keep track of the number of iterations. Every item in the original sequence (s) is compared to the previous value. If they are the same, the value of the last item of (w) is increased with 1. If they are different, the sequence (w) is extended with [1]. If w==[2], the counter (c) is returned. Else, if the original sequence (s) contains other items than 1 and 2, a value -1 is returned. If neither is the case, the function is called recursively with the new sequence (w) as (s) and the counter (c) increased by 1. • To save a byte, I'm trying to combine the first two lines into def f(s,c=2,j=0,w=[1]):, but that gives a different result. Could anybody explain why that is? – Jitse Jul 24 '19 at 8:14 • Mutable default arguments will stay mutated – Jo King Jul 24 '19 at 11:02 • @JoKing That makes perfect sense, thanks! – Jitse Jul 24 '19 at 11:05 # Stax, 26 bytes äE⌐+É7∩ΦΓyr╔ßΣ·φƒÇe►ef%I»  Run and debug it Tried with a generator, but it seems like a while loop is shorter. # R, 93 92 bytes Edit: -1 byte thanks to Giuseppe f=function(x)if(sum(x|1)<2,(-1)^(sum(x)!=2),if(!all(x%in%1:2),-1,(y=f(rle(x)$l))+(y>0)))


Try it online!

Returns 1-based number of iterations for truthy input, and -1 for all falsy inputs. This needed quite careful input testing, especially for the last two test cases...

Commented:

f=function(x)           # recursive function with argument x
if(sum(x|1)<2,        # if there's one (or less) element left
(-1)^(sum(x)!=2),     # return 1 if it's equal to 2, -1 otherwise
if(!all(x%in%1:2),  # if any element isn't 1 or 2
-1,                 # return -1
(y=f(               # otherwise recursively call self with
rle(x)$l)) # lengths of groups of digits in x +(y>0))) # if result is positive, return result +1 # otherwise return result (which must be -1)  # R, 74 66 bytes f=function(x)if(sum(x)==2&x==2,1,if(all(x%in%1:2))f(rle(x)$l)+1)


Try it online!

...but then I read the comments more carefully and realised that it's Ok to output nothing, or rubbish, or to error for falsy inputs. That makes it much easier!

• in your first answer, length(x) should be sum(x|1), and in your second, I think sum(x)==2 can be shortened to sum(x)<3. – Giuseppe Nov 30 '20 at 15:28
• @Giuseppe - I thought I'd tried both of those... doesn't sum(x|1) fail for zero-length vectors, and sum(x)<3 fail for vectors containing negative elements? – Dominic van Essen Nov 30 '20 at 15:44
• I think the sum(x|1) still works for 0-length vectors, but I guess I hadn't thought about negative elements. – Giuseppe Nov 30 '20 at 15:45
• @Giuseppe - You're right re:sum(x|1)! Thanks! I'd made the mistake of using c() for test case 8 (which returns NULL and fails) instead of numeric() to properly make a zero-length vector. – Dominic van Essen Nov 30 '20 at 15:59

# Jelly, 13 bytes

ŒɠƬµFfƑ1,2aL’


Try it online!

Returns 0 or -1 for falsey cases. +2 bytes to consistently return -1

## How it works

ŒɠƬµFfƑ1,2aL’ - Main link. Takes a list L on the left
Ƭ           - Until reaching a fixed-point:
Œɠ            - Take lengths of runs
µ          - Call this list of lengths W
F         - Flatten
Ƒ       - Is this unchanged after:
f        - Removing everything except:
1,2    - 1s and 2s?
L  - Yield the length of W (i.e. number of iterations)
a   - If unchanged, return the length. Else, return 0
’ - Decrement


# Ruby, 81 77 bytes

f=->a,i=1{a[1]&&a-[1,2]==[]?f[a.chunk{|x|x}.map{|x,y|y.size},i+1]:a==[2]?i:0}


Try it online!

Edit: Saved 4 bytes by converting to recursive lambda.

Returns 1-indexed number of iterations or 0 as falsey.

Makes use of Ruby enumerable's chunk method, which does exactly what we need - grouping together consecutive runs of identical numbers. The lengths of the runs constitute the array for the next iteration. Keeps iterating while the array is longer than 1 element and no numbers other than 1 and 2 have been encountered.

# Pyth, 45 bytes

L?||qb]1!lb-{b,1 2_1?q]2b1Z.V0IKy~QhMrQ8*KhbB


Try it online!

This is probably still golfable. It's definitely golfable if .? worked the way I hoped it would (being an else for the innermost structure instead of the outermost)

L?||qb]1!lb-{b,1 2_1?q]2b1Z # A lambda function for testing an iteration of the shortening
L                           # y=lambda b:
?                          # if
qb]1                    #    b == [1]
|    !lb                 #      or !len(b)
|         {b              #        or b.deduplicate()
-  ,1 2          #             .difference([1,2]):
_1        #               return -1
?q]2b1Z # else: return 1 if [2] == b else Z (=0)

.V0                         # for b in range(0,infinity):
IKy~Q                    # if K:=y(Q :=        (applies y to old value of Q)
hM                  #    map(_[0],
rQ8               #               run_length_encode(Q)):
*Khb           #    print(K*(b+1))
B          #    break


# Perl 5-p, 71 bytes

$_.=$";s/(. )\1*/$&=~y|12||.$"/ge&$.++while/^([12] ){2,}$/;$_=/^2$/*\$.


Try it online!

1-indexed. Outputs 0 for falsy.

# Scala 3 (compile-time), 460 bytes

This may be the longest answer here, but it's also the fastest one here...because it works at compile time.

import compiletime.ops.int._
type r[T,P]=T match{case h*:t=>r[t,h*:P]case E=>P}
type E=EmptyTuple
type F[K,R,L,S,P,I]=K match{case E=>L-S match{case 0=>R match{case E=>0 case _=>F[r[R,E],E,0,0,0,I+1]}case _=>0}case P*:_=>0
case 1*:1*:t=>F[t,2*:R,L+2,S+2,1,I]case 1*:t=>(t,R)match{case(E,E)=>0 case _=>F[t,1*:R,L+1,S+1,1,I]}case 2*:2*:t=>F[t,2*:R,L+2,S+2,2,I]case 2*:t=>(t,R)match{case(E,E)=>I+1 case _=>F[t,1*:R,L+1,S+1,2,I]}case _=>0}
type G[K]=F[K,E,0,0,0,0]


Try it in online!

You can invoke it as G[1 *: 2 *: EmptyTuple] (actually, just G[(1, 2)] should also work, but for whatever reason, it's not working right now. I'll fix it later, though). It's 1-indexed, and it returns 0 for falsy inputs.