# Climbing the Bookshelf

## Introduction

You're making a robot that can navigate a set of books of varying heights. It can climb books and jump off books, but if the distance is too big it will stop to prevent damage. To firgure out the ideal design, you're writing a simulator.

Your program will take as input a list of numbers, representing the heights of the books in the bookshelf, as well as a number indicating the durability of the robot. Starting from the first item of the list, your robot will traverse the bookshelf. If the robot comes across a change in height, it will only be able to continue if the change is less than or equal to the robot's durability. Your job is to output which book the robot is on when it stops, starting from either 0 or 1. You may safely assume that the height of the first book the robot is on will be equal to or less than the robot's durability.

## Scoring

This is code-golf, so shortest answer wins.

## Examples (starting from 1)

[1, 1, 1], 1 -> 3
[0, 1, 0], 0 -> 1
[1, 2, 3, 2], 1 -> 4
[1, 3, 4, 4, 0], 2 -> 4
[1, 3, 4, 4, 0, 1], 2 -> 4

• @solid.py Good point. I've clarified the examples. Jan 31 at 18:57
• Suggest test case [1, 3, 4, 4, 0, 1], 2 -> 4. Currently, an algorithm that simply counts the number of elements less than or equal to durability in the absolute differences of heights returns the correct output for all test cases, but it will fail on this one. Jan 31 at 19:24
• And that statement is sort of a non-sequitur anyway, since we don't care about the absolute height of the books, only the relative heights. Feb 1 at 23:37
• @chunes Does this start from 0 or 1? Feb 2 at 12:40
• @Lynn Sorry, fixed. Feb 2 at 12:41

# Wolfram Language (Mathematica), 33 bytes

dIf[Abs[#2-#]>d,0,1+#0@##2,0]&


Try it online!

Input [durability][heights...]. Returns 0-indexed.

If[Abs[#2-#]>d             ]    is the next height difference out of limits?
,0                  yes: 0
,1+#0@##2         no : recurse on tail and add 1
,0       err: 0 (input len <2)


# Octave / MATLAB, 37 35 bytes

2 bytes saved thanks to @Giuseppe!

@(x,d)sum(cumprod(abs(diff(x))<=d))


Output is 0-based.

Try it online!

# Vyxal, 7 bytes

¯ȧ<1JTh


Try it Online!

¯ȧ      # Get absolute differences
<     # Find all less than the input
1J   # Append a 1
h # Get the first...
T  # Index of a 1


# JavaScript (ES7), 41 bytes

-6 thanks to @emanresu A

d=>f=([a,...x])=>(a-x[0])**2<=d*d&&-~f(x)


# JavaScript (ES7), 42 bytes

d=>f=([a,...x])=>(a-x[0])**2<=d*d?f(x)+1:1


Recursive solution. Takes input via currying, robot durability first.

Relies on NaN <= x always being false, saving a check to see if x is long enough.

• @emanresuA Nope, due to the NaN trick that causes infinite recursion if the robot wouldn't break Jan 31 at 18:13

# Emojicode, 272 bytes

🏁🍇💯🆕🔡👂🏼❗️❗️➡️d🎶🆕🔡👂🏼❗️❗️➡️l l➡️🖍🆕a 0➡️🖍🆕c🐨a 0❗️🔂v a🍇↪️🍺💯v❗️➖🍺💯🐽l c❗️❗️▶🙌🍺d🍇🚪🐇💻c❗️🍉c⬅️➕1🍉🚪🐇💻c❗️🍉


Try it online!

• I still don't understand what compelled me to do this. Mar 19 at 15:03

# Python 3, 80 bytes

Returns 0-based index.

lambda l,n:next((i for i,(a,b)in enumerate(zip(l,l[1:]))if abs(a-b)>n),len(l)-1)


Try it online!

# Jelly, 7 bytes

5 if we may output 1-indexed and modular (i.e. yield 0 for the rightmost) - remove ;1

IA>;1TḢ


A dyadic Link accepting a list and an integer that yields the 1-indexed stopping point.

Try it online!

### How???

IA>;1TḢ - Link: list, B; integer, D
I       - incremental differences of B
A      - absolute values
>     - greater than D?
;1   - concatenate a one
T  - truthy 1-indexed indices

• Hm, exactly the same as my Vyxal. Feb 1 at 5:47
• I suppose ạƝ rather than IA would make it exactly the same, but yep! Feb 1 at 12:04

(a:b:r)!s|s<abs(a-b)=1
(h:t)!s=1+t!s
x!_=0


Try it online!

Three definitions of infix !

• 1st: guards against big step stopping the robot.
• 2nd: step was fine, continue.
• 3rd: end of list.
Due to 1 indexing it was possible to save something by reaching end of list instead of ending at a single element e.g. [x]!_=0

# Factor, 50 43 bytes

[ differences vabs [ >= ] with count-head ]


count-head postdates build 1525, the one TIO uses, so here's a screenshot running this in Factor's REPL:

## Explanation

Takes input as durability heights. 0-indexed. count-head is a combinator that applies a quotation to each element of a sequence, counting how many times the quotation returns t and stopping once an f is encountered.

                        ! 2 { 1 3 4 4 0 }
differences             ! 2 { 2 1 0 -4 }
vabs                    ! 2 { 2 1 0 4 }
[ >= ] with count-head  ! 3


# 05AB1E, 7 bytes

¥Ä‹1ª1k


0-based.

Explanation:

¥        # Get the deltas/forward-differences of the first (implicit) input-list
Ä       # Convert each to its absolute value
‹      # Check for each integer in the list whether the second (implicit)
# input-integer is smaller than it
1ª    # Append a trailing 1
1k  # Pop the list, and push the (0-based) index of the first 1
# (which is output implicitly as result)


Could be 5 bytes if we're allowed to output a modular index, so it'll output -1 if it's able to travel across all books:

¥ÄÅΔ‹


Explanation:

¥Ä     # Same as above
ÅΔ   # Push the first 0-based index which is truthy for
# (or -1 if none were truthy)
‹  #  Check if the second (implicit) input-integer is smaller than the
#  current integer
# (after which the found index is output implicitly as result)


# C (gcc), 56 51 49 bytes

f(a,n,d)int*a;{n=!--n||(*a-*++a)/~d?:1+f(a,n,d);}


Try it online!

Saved 5 bytes thanks to att!!!
Saved 2 bytes thanks to AZTECCO!!!

Inputs a pointer to an array of integers, its length (because pointers in C carry no length info), and the durability of the robot.
Returns to the number of the book (starting at $$\1\$$) that the robot stops at.

• 51 bytes
– att
Feb 1 at 0:08
• @att Very nice - thanks! :D Feb 1 at 10:37
• 49 Feb 1 at 13:34
• @AZTECCO Clever way around abs - thanks! :D Feb 1 at 14:40

# Python 3, 53 bytes

s=lambda d,f,*t,p=0:d<abs(f-p)or t==()or-~s(d,*t,p=f)


Try it online!

Input is taken as varargs. Surprisingly the 1-based indexing makes the code shorter, since "or" is a byte shorter than "and".

# Japt, 10 bytes

I am ridiculously out of practice! 0-indexed.

äa pVÄ b>V


Try it

# Wolfram Language (Mathematica), 40 bytes

Output is 0-base

LengthWhile[Abs@Differences@#-#2,#<=0&]&


Try it online!

# Charcoal, 20 bytes

Ｉ⌕Ｅθ∨⁼κ⊖Ｌθ‹η↔⁻ι§θ⊕κ¹


Try it online! Link is to verbose version of code. 0-indexed. Explanation:

   θ                    Input list
Ｅ                     Map over values
κ                 Current index
⁼                  Equals
θ              Input list
Ｌ               Length
⊖                Decremented
∨                   Logical Or
η            Input durability
‹             Is less than
ι         Current value
↔⁻          Absolute difference with
θ       Input list
§        Indexed by
κ     Current index
⊕      Incremented
⌕                      Find index of
¹    Literal integer 1
Ｉ                       Cast to string
Implicitly print


# K (ngn/k), 21 bytes

{*&(y<x|-x:1_-':x),1}


Try it online!

# Julia 1.0, 37 bytes

h/r=findfirst(abs.(diff([h;Inf])).>r)


Try it online!

35 bytes porting @LuisMendo's Octave solution: h/r=sum(cumprod(abs.(diff(h)).<=r))

# Python 3, 71 bytes

lambda h,d:([abs(h[i+1]-h[i])>d for i in range(len(h)-1)]+[1]).index(1)


Try it online!

• -2. There's an easier way to get 69, but this is cooler :P Jan 31 at 22:15
• Jan 31 at 22:20
• @UnrelatedString 53 bytes if taking input as varargs. Feb 1 at 19:53
• @AnttiP That might be worth posting as your own solution. Feb 1 at 19:56

# APL+WIN, 12 14 bytes

Plus 2 bytes to accomodate new example suggested by @chunes

Prompts for heights then durability. Index = 1

+/^\1,⎕≥|-2-/⎕


Try it online! Thanks to Dyalog Classic

# Retina 0.8.2, 58 bytes

\d+
$* ,(1*)(1*)(?=,\1(1*)) ,$2$3 (1*)(,(?!1\1)1*)*,.*$#2


Try it online! Link includes test cases. 0-indexed. Takes the durability first followed by the list of heights. Explanation:

\d+
$*  Convert to unary. ,(1*)(1*)(?=,\1(1*)) ,$2$3  Take the absolute difference between each height and the next ($2 is for the positive difference, $3 for the negative). Note that the last height remains in the input. (1*)(,(?!1\1)1*)*,.*$#2


Match the durability and as many differences that don't exceed the durability, then replace everything with the count of those differences. (The comma is necessary to avoid matching the last height.)

# x86-16 machine code, 17 bytes

00000000: 33ff 47ac 2a04 7302 f6d8 3ac4 7702 e2f2  3.G.*.s...:.w...
00000010: c3                                       .


Listing:

33 FF       XOR  DI, DI         ; zero jump counter
BOOK_LOOP:
47          INC  DI             ; increment jump counter
AC          LODSB               ; AL = current height
2A 04       SUB  AL, [SI]       ; AL = AL - next height
73 02       JAE  IS_POS         ; is positive?
F6 D8       NEG  AL             ; if not, negate to get abs value
IS_POS:
3A C4       CMP  AL, AH         ; over threshold?
77 02       JA   DONE           ; if so, push the AZ-5 button
E2 F2       LOOP BOOK_LOOP      ; otherwise, keep plugging
DONE:


Input list at [SI], length in CX, threshold in AH. Output stopping index (1 based) in DI.

About as vanilla asm as you can get. Any time I tried to get clever it was more bytes...

• "Any time I tried to get clever it was more bytes..." Yup, that's pretty much par for the course, in my experience. That's why it's often much more fun (not to mention more practical) to optimize for speed. As a case in point, the shortest way to get an absolute value is always going to be test-and-branch, as you've done here, but it's almost never going to be the most efficient way to do so. That's the crazy (and, in some ways, fun) thing about CISC insn sets like x86 (and, to a lesser extent, even pure RISC ISAs): more bytes of code can counterintuitively net a huge performance win. Feb 3 at 3:38

# Desmos, 9650 47 bytes

- a whopping 46 bytes thanks to Aiden Chow
- 3 bytes thanks to Aiden Chow again

L=l.length
\min(\{(l[2...]-l)^2>aa:[1...L],L\})


Probably not the right language, but I had a lot of fun coding this.
Receives a list l and durability a as input.
Online Version

• Directly pasting this into Desmos will break the code. You need a backslash in front of every { and }. Feb 2 at 1:38
• Also, you can remove the commas for the list ranges (,..., -> ...). Feb 2 at 1:42
• length(l-1) is the same as length(l). Maybe you meant to write length(l)-1 instead? Feb 2 at 1:43
• Other tiny golfs: You can remove the :1 part in piecewise expressions. So, \{(condition):1,0\} can be replaced with \{(condition),0\} and it will do the same thing. The space between for and i can also be removed. If you write f(L)=L.length and then replace all the length functions in your code to f, you can shave off a byte. \le  can be replaced with <=. Feb 2 at 1:45
• You can visit the Desmos Tips Page, where you will find many of the tips I've just described here plus some more tips. Feb 2 at 1:52

# R, 43 42 bytes

Edit: -1 byte thanks to pajonk (who anyway found a better approach...)

function(x,y)which(c(abs(diff(x))>y,T))[1]


Try it online!

• Indexing to seq looked weird - which feels better I think: -1 byte. Feb 5 at 20:01
• But if we want something weird-looking, here's something using match for another -1 byte, Feb 5 at 20:03
• @pajonk - Great. You should post the match one. I was uselessly trying a match(x,,nomatch=length(x), and completely missed your trick. Well done (and I've no idea how i made the seq instead of which blunder...) Feb 6 at 7:33
• Posted, thanks! Feb 6 at 8:29

# R, 41 bytes

function(x,y)match(T,c(abs(diff(x))>y,T))


Try it online!

Based on @Dominic van Essen's answer, so test harness taken from there.

The idea emerged when golfing Dominic's answer and using which: "hmm, we need the first index and I remember that there's a function that returns only the first index (which is annoying in some challenges). Oh, it's match!"