# 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? 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. Jun 28 '17 at 21:42
• @ngenisis It will eventually reach two without any intermediate step having any elements other than 1 and 2. Jun 29 '17 at 0:27
• Might be a good idea to add [1] as a test case. 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. 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! Jun 29 '17 at 2:41 • Seem to enter an infinite loop for [1] Jun 29 '17 at 9:59 • @Emigna Darn. It costs me 6 bytes to fix it, but I've fixed it. 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. :) 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! 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] Mar 24 '18 at 10:04 • @WeijunZhou: Thanks, fixed! Mar 24 '18 at 10:50 • You may have forgotten to update the link ... Mar 24 '18 at 10:56 • @WeijunZhou: Indeed I had. Thanks again :) Mar 24 '18 at 10:58 # Jelly, 17 bytes ŒgL€$ÐĿµẎḟ1,2ȯL_2


Try it online!

# 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] 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]" Jun 29 '17 at 10:03
• To my understanding, [1] never reaches [2] and should thus return -1. Jun 29 '17 at 10:06
• I see. So do you think I should put a litte condition at start? Thanks for your advice. 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. 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, 12 bytes

ŒɠƬµ2Wea’ỊȦƊ


Try it online!

## How it works

ŒɠƬµ2Wea’ỊȦƊ - Main link. Takes a list L on the left
Ƭ          - Until reaching a fixed point, keeping each step:
Œɠ           -   Get the lengths of consectuively equal groups of elements
µ         - Call this list S and use it as the argument
2W       - Yield [2]
e      - Is [2] in S?
’    -   Decrement every integer in S
Ị   -   Insignificant? Replace 0 and 1 with 1, everything else 0
Ȧ  -   Any and all? S is non-empty and has no zeros
a     - Both are true?


# 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])

# 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.

## 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

• 156 bytes Sep 3 '17 at 9:14

# 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? 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! 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. 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? 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. 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. Nov 30 '20 at 15:59

λĠvL&›Dƛ2>;A$Ḣ∧[x|u£];†h2=[¥|u  Try it Online! A big mess. # 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.