# Tape Measure String

Motivation: Sometimes you need to know where you are in a string. You want to be able to look at any part of a string and know exactly where you are, as far as possible.

Challenge: write a program to output a tape measure string of a given length. A tape measure string self describes its length-so-far as often as possible along it's own length.

Rules:

1. Your program must take one positive integer parameter, for the total length of the tape measure string
2. For each contiguous string of digits in the output, these digits must accurately report the length of the output so far - inclusive!
1. Lengths are measured from the start of the string to the end of each number
3. As many length numbers as possible should be included in the string
4. Avoid ambiguity. Separators/delimiters can be used to avoid numbers being juxtaposed, i.e. 12 says twelve not one, two.
5. The string must always accurately report its total length at its end, with no trailing separators
6. You may need multiple separators to keep the lengths accurate, e.g. here's an example tape measure string of length 4: 1--4

Non prescriptive/exhaustive examples:

• tape measure string of length 1: 1
• tape measure string of length 2: -2
• tape measure string of length 3: 1-3
• tape measure string of length 4: 1--4 or -2-4 (both report lengths as often as possible, i.e. twice, and end with the correct total length)
• tape measure string of length 10: 1-3-5-7-10
• tape measure string of length 11: 1-3-5-7--11 or 1-3-5--8-11 or 1-3--6-8-11 or 1--4-6-8-11 or -2-4-6-8-11 (all have as many length numbers as possible, and finish with the total string length)
• So every digit in the string is non-adjacent to another digit, the string is composed entirely of dashes -, and you need to have as many length marks as you possibly can in the string? – Rɪᴋᴇʀ Jan 14 '17 at 15:34
• Can we use 0 based indexing? – Rɪᴋᴇʀ Jan 14 '17 at 15:38
• @EasterlyIrk Rule 3 is as many numbers as possible must be fit into the string. – Wheat Wizard Jan 14 '17 at 15:39
• Related. – Martin Ender Jan 14 '17 at 15:58
• @EasterlyIrk you can't have all dashes as that fails to meet the motivation and breaks rules 3 and 5. There is no indexing. Just lengths. So no, a tape measure string of length one, can't be 0. – Tom Viner Jan 14 '17 at 18:56

# Python, 504847 46 bytes

f=lambda x:x*"1"if x<2else f(x-len(-x))+-x


# Explanation

Pretty simple recursive lambda solution

Our base cases are 1 and 0 which are covered by "1"*x otherwise we get the string of -x with -x and prepend the result of calling the function on len(-x) less.

• Can you save bytes by stringifying -x? – Martin Ender Jan 14 '17 at 19:04
• @MartinEnder Ok I got it to work. Thanks for the tip! I feel kind of dumb for not noticing that earlier. – Wheat Wizard Jan 14 '17 at 19:33

# Mathematica, 67 57 bytes

Thanks to Martin Ender for jettisoning 10 bytes!

""["1"][[#]]/._@__:>#0[#-1-IntegerLength@#]<>ToString@-#&


Unnamed function taking a nonnegative integer argument and returning a string. Pretty much the obvious recursive algorithm: make sure the string ends with the input number preceded by a "-", and then call the function again using #0.

But there's golfy fun to be had in implementing the algorithm. ""["1"][[#]] denotes the #th argument of the expression ""["1"]: the 0th argument is the head "" and the 1st argument is visibly "1", which provides the base cases of the recursion. If # exceeds 1, then ""["1"][[#]] throws an error message and remains as an unevaluated function. But then /._@__:> is a rule that takes any unevaluated function and transforms it into the expression that comes next, which is the recursive call to the original function.

Original submission:

If[#<2,""["1"][[#]],#0[#-1-IntegerLength@#]<>"-"<>IntegerString@#]&

• ""["1"][[#]]/._@__:>#0[#-1-IntegerLength@#]<>ToString@-#& saves one byte by avoiding the If and a bunch of bytes by avoiding IntegerString and "-"<>. – Martin Ender Jan 15 '17 at 11:51
• omg, _@__ is evil magic – Greg Martin Jan 15 '17 at 18:00

## JavaScript (ES6), 49 bytes

f=(n,s='',t=''+-n)=>n>1?f(n-t.length,t+s):n?n+s:s
<input type=number oninput=o.value=f(this.value)><br><textarea id=o></textarea>

• I think you need to define f – Tom Viner Jan 14 '17 at 22:33
• @TomViner I'm always doing that. (At least I had the right byte count.) – Neil Jan 15 '17 at 0:12

# Pyth, 23 bytes

L?<b2*"1"b+y-bl+""_bs_b


Blatantly stole the recursive solution from Wheat wizard's answer. Also, I believe this is not golfed properly.

Try it here!

# Perl 6, 43 bytes

{[R~](-$_,{$_+.comb}...^*>-1).&{S/^\-1/1/}}


Explanation:

{                                         }  # A lambda.
...                      # Generate a sequence...
-$_ # starting from the negated lambda argument, ,{ } # continuing iteratively using the formula:$_+.comb                          #     Last element plus length of last element.
*>-1                 #   until we hit 0 or higher,
^                         end-point not inclusive.
[R~](                      )                # Reverse and concatenate the number sequence.
.&{         }   # Apply to this the transformation:
S/^\-1/1/    #   Remove the sign from a leading "-1".


So for example for input 10, it generates the sequence (-10, -7, -5, -3, -1), and from that the string -1-3-5-7-10, and from that the final string 1-3-5-7-10.