The Ship of Theseus is an old question that goes something like:

If a ship has had all of its original parts replaced, is it still the same ship?

For this golf, we're going to slowly replace "parts" on a "ship", and see how long it takes to get a whole new ship.


A ship is comprised of at least two parts. The parts are given as an array of positive (non-zero) integers, representing the part's condition.

On each cycle, randomly choose one part from the list in a uniform fashion. That part's condition will be reduced by one. When a part's condition reaches zero, it is replaced by a new part. The new part starts with the same condition value as the original did.

On the first cycle where all parts have been replaced (at least) once, stop and output the number of cycles it took.

For example (assume I'm choosing parts randomly here):

2 2 3  <- starting part conditions (input)
2 1 3  <- second part reduced
2 1 2  ...
2 1 1 
2 2 1  <- second part reduced to zero, replaced
1 2 1 
1 2 3  <- third part replaced
1 1 3 
2 1 3  <- first part replaced

Output for this example would be 8, since it took eight cycles for all parts to be replaced. Exact output should differ for each run.


The only input is the list/array of integers for part condition. The only output is a number of cycles. You can take/give these values in any of the usual ways: STDIO, function arguments/returns, etc.

Test Cases

Since output is not fixed, you could use whatever you want to test, but here's a couple for standardization purposes:

1 2 3 4

617 734 248 546 780 809 917 168 130 418

19384 74801 37917 81706 67361 50163 22708 78574 39406 4051 78099 7260 2241 45333 92463 45166 68932 54318 17365 36432 71329 4258 22026 23615 44939 74894 19257 49875 39764 62550 23750 4731 54121 8386 45639 54604 77456 58661 34476 49875 35689 5311 19954 80976 9299 59229 95748 42368 13721 49790
  • 1
    \$\begingroup\$ Am I missing something, or does it not matter that when a part reaches 0, it is replaced by a new part? \$\endgroup\$
    – xnor
    Commented Apr 30, 2015 at 0:20
  • \$\begingroup\$ @xnor Well it doesn't matter to get the answer, no (and it seems to be the thing to do to skip it). But thematically, the ship's parts need replacing :P \$\endgroup\$
    – Geobits
    Commented Apr 30, 2015 at 0:56

4 Answers 4


GolfScript (26 24 bytes) / CJam (20 18 bytes)



Online demo

CJam (same idea but slightly different implementation):


Online demo

Input is on stdin in the form [2 2 3].

This is one of those rare occasions where GolfScript's unfold operator is useful. It allows us to accumulate the states which the ship passes through, and then count them at the end. Note that the array which is counted includes the initial (input) state but not the final state in which the last element has been reduced to 0.

However, although CJam doesn't have unfold its ability to shuffle an array uniformly for only 2 chars counts for a lot and allows it to come out on top.


Pyth, 12 bytes



How it works:

This is based around Pyth's infinite filter, which tests an expression with increasing inputs until it returns something truthy, then returns the input which caused this to happen. However, the expression that will be tested will not use the input value.

Instead, the expression will modify the input list by decrementing a random entry. This is accomplished via the expression XOUQQtZ. This means increase the index OUQ in the list Q by tZ. OUQ is a random index in the length of Q, and tZ is -1. Q is initialized to the input list.

After modifying Q in this fashion, we take its current value, which X returns, take its maximum entry with eS, and take the logical not of that value with !. This returns a truthy value for the first time when every element of Q has been reduced to 0 or below for the first time.

To ensure that the number returned will be exactly the number of times that Q was modified, we will start the count at 1, indicating the the first time this is called, there has been 1 modification. To see what Q looks like after each iteration of the code, check out the version here.


Python 3, 91 71 bytes

20(!) bytes saved thanks to @xnor.

from random import*
def f(p):shuffle(p);p[0]-=1;return max(p)<1or-~f(p)

Recursive function calling itself with smaller piece-values until all piece-values are 0 or negative and every function returns the return value of its child + 1 and the lastly called one returns 1.

  • \$\begingroup\$ You can check for the presence of a positive number with max(p)>0. \$\endgroup\$
    – xnor
    Commented Apr 30, 2015 at 0:23
  • \$\begingroup\$ And negating the condition as max(p)<1or-~f(p) lets you avoid the or 1, since True==1. \$\endgroup\$
    – xnor
    Commented Apr 30, 2015 at 0:33
  • \$\begingroup\$ You can effectively decrement a random element of p with shuffle(p);p[0]-=1. \$\endgroup\$
    – xnor
    Commented Apr 30, 2015 at 1:00
  • \$\begingroup\$ @xnor Wow, thanks! These are all great! \$\endgroup\$
    – randomra
    Commented Apr 30, 2015 at 7:51

Python 3, 175 bytes

import random
p,t=input().split(),0;f,r=[int(i)for i in p],[0]*len(p)
while 0 in r:
 for x in range(len(f)):

Not especially well golfed.

Try it online here

  • \$\begingroup\$ Self destruct comment \$\endgroup\$
    – Tim
    Commented May 10, 2015 at 16:39

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.