[Question]
  [
Given a level from a simple platform game, your task is to make a program or function to determine if a level is winnable. Platform game levels are 4 characters tall and any number of characters wide. There is exactly one platform for each horizontal space in a level:
```
           =======    =     
==    =           =         
   ===                 =====
  =    ====        ===      
```
The game consists of jumps. Jumps start from the space above the platform which is being jumped from, and end in the space above the platform which is being jumped to (these can be above the 4 platform height levels). To complete a jump, it must be possible to move from the start point to the end point in four or less (including the start/end points) up, down, left, and right moves which do not pass through a platform. Here are some examples (marked with A for start platform and B for end platform):
```
 >>>
 ^ B
=A
  =
```
```
 >>>>
=A  B=
```
```
>>
^B
A
```
Horizontal moves along a platform are just jumps which only move in one direction:
```
  >>
==AB===
```
The player would start on the leftmost platform, and wins by standing on the rightmost one (marked with `v`s):
```
v  === v
===   ==
```
## Test cases
Winnable:
```
 ===      ==
=    =====  
    =       
```
```
    ==      
=         ==
 ===  ====  
```
```
   ==== =   
===         
       =    
         ===
```
```
  ==  ==  = 
=           
 =  ==  == =
```
Unwinnable:
```
      ======
======      
```
```
 =======   =
=         =
         =
        =
```
```
           =
   =        
=     =     
 == == ==== 
```
## Rules
Your program should output one distinct value if a level is winnable, and a different one if it isn't. It can take input in any reasonable form, such as an ASCII art with any two distinct characters, a matrix, or a 2d array.
Code golf, so shortest answer per language wins.
  
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), ~~23~~ 22 bytes
```
ŒṪạþ`§<4NA1¦A»/T$¦ÐLṪṀ
```
[Try it online!](https://tio.run/##VZCxCsIwEIb3e4ogjooIbnqCuzi56OTiUsTdrbq4iq46iFBBnEQCVXC4oO/RvEhMkzQkoaR3yX/f/blkvlislPrui/xWvM7iM6NrrzMatCkb0Ls1rlMmdsPyMk@VXH9qtUTs5Oae6LhBvCvTI3HW7DPiMj11xXZSh@@hyC/6njjx4v2cLuWai@3v4crKY6VYsIAhog0RAe3fHIGJK5nNsCoKCehDTbA4RwBHMxjwjQICxjgtAfBhmcVeo7bOp7OHPsfQUQgPCOjeZM3GuvhNZkRe6O1ZCgQjqorQz9V@ejOdnNwJseKyPw "Jelly – Try It Online")
New version, which now efficiently handles moves backwards. Takes input as a boolean matrix (row major). Returns 1 for winnable and 0 for not. 
Thanks to @AZTECCO for first suggesting using the indices of platforms, and @tsh for a test case that made me rethink my approach. 
## Explanation
```
ŒṪ                     | Multidimensional truthy indices of each
  ạþ`                  | Outer table using absolute difference and with the same argument on both sides:
     §                 | Sum innermost lists
      <4               | - Less than 4
        N              | Negate
         A1¦           | Absolute top row
                  ÐL   | Apply the following until no changes:
            A   $¦     | Absolute the rows indicated by the following:
             »/        | - Max of each column
               T       | - Truthy indices (i.e. where there’s a 1 in the column)
                    Ṫ  | Finally take the last row
                     Ṁ | Max
```
## Step b step
(each matrix shown collapsed as a grid, with - = -1):
### 1. Input
```
0010
0001
1000
0010
0001
1000
```
### 2.`ŒṪ`
Multidimensional indices.
```
[[1, 3], [2, 4], [3, 1], [4, 3], [5, 4], [6, 1]]
```
### 3. `ạþ`§<4N`
Convert to initial outer table with -1 for possible moves between columns and 0 where no move possible.
```
--0-00
--0--0
00--0-
-----0
0-0--0
00-00-
```
### 4. `A1¦A»/T$¦ÐL`
Absolute first row, then iteratively take each column with at least one 1 in it, and absolute the rows at those indices; results after each iteration shown.
```
Absolute row 1 ->
110100
--0--0
00--0-
-----0
0-0--0
00-00-
-> Absolute rows 1, 2, 4 ->
110100
110110
00--0-
111110
0-0--0
00-00-
-> Absolute rows 1, 2, 3, 4, 5 ->
110100
110110
001101
111110
010110
00-00-
-> Absolute rows 1, 2, 3, 4, 5, 6 ->
110100
110110
001101
111110
010110
001001
```
### 5. `ṪṀ`
Finally, take the max of the last row
```
1
```
My [previous 61 byte version](https://tio.run/##VZCxasMwEIb3ewoTPNbUhmYyl6VToU@QrUMWE9q5mewuHroEOjiBZipkabqUIuoaMuhIoY8hvYh7sWQhGSP9J/369OuKxXL52Pe63KZyr9ptJg/UTKmZZTFwScecx7@GNglbdPWt2g/ZXbK4o/ohhntdiVO3Sm@oSa7k@@9nJvfXtEmLWFc/@umwSqmm9e08Ud3zdNHr6jiZFLTmnYL1hRS5Ll@liJJZJIUudznVcHpR7RvvSiGF6r7YS7U9cF7q@8j7IEJEIxEBzTwswaBHm6lwPOQT0EkmGJwlgKUNGHAXeQQMcWwBcPJchVmDa21OGw9djX4iH@4R0L7JhA194ZuGFjmji2co4LVoPISur@bn4R8 "Jelly – Try It Online") has explanation in the [edit history](https://codegolf.stackexchange.com/posts/196602/revisions "Edit history"); thanks to @JonathanAllan for golfing 3 bytes off that one!
[Answer]
# JavaScript (ES6), ~~129~~ 126 bytes
Takes input as a binary matrix. Returns either \$0\$ or \$1\$.
```
f=(a,x=0,m,d=4,g=d=>k=a.findIndex(r=>r[x+d]))=>!~g(1)|[...'1350531'].some(v=>~g(--d)&&m^(M=m|1<<x+d)&&(k-=g``)*k<v&f(a,x+d,M))
```
[Try it online!](https://tio.run/##nZM9b4MwEIZ3fgVdwG4M4pRmw@wdMlYdKFVIDIgCpoKIUCnqX6eUJMUQvlRZQtiv7/yc7/WHW7j5IQs/jxpPmVdVPkUuKalBEsLoEwkoo1ZEXd0POXvmzCtRRq3MLlfMwZhaD98BAny2dV1XYb0xNmtQHT1PEw8V1KpFTWNYUZJ3tKXJGUyzDqznKNJosNvhx8gsFP/3xBUjW4yrQ8rzNPb0OA2Qar@GnLv72HNULImKj2xJlm2DDA6HXERohijV84sI4lK78RZ5k7pppbriKYzead1kg4wwIP0xigWIjNMY7U7ontS/i1FGmCugyTWJIWJfU/7zNjrtvE99xehwqG/cfuGn5dZpLQALKGdK6PhpgXWA3MfAlDsm2jLKCAsd3IsSk8F8z2D4CYrf5m@kZ7fHLu@/5CQtQh7IsecfT27G8tEuCs@jpZ1ysIgtXkv1Aw "JavaScript (Node.js) – Try It Online")
### How?
Given the current column \$x\$ and a horizontal jump distance \$dx\$, the helper function \$g\$ returns the 0-indexed row of the platform at column \$x+dx\$, or \$-1\$ if \$x+dx\$ is outside the playfield.
```
g = d =>             // d = dx
  k =                // save the result in k
    a.findIndex(r => // for each row r in a[]:
      r[x + d]       //   test whether r[x + dx] is truthy
    )                // end of findIndex()
```
Starting with \$x=0\$, the recursive function \$f\$ attempts to find a way to the last column by trying all valid jumps and keeping track of visited columns.
```
f = (                // f is a recursive function taking:
  a,                 //   a[] = input matrix
  x = 0,             //   x = current column
  m,                 //   m = bit-mask of visited columns
  d = 4,             //   d = dx
  g = …              //   g = helper function (see above)
) =>                 //
  !~g(1) |           // success if g(1) is equal to -1
  [...'1350531']     // list of exclusive upper bounds for dy²
                     // corresponding to dx = +3, +2, +1, 0, -1, -2, -3
  .some(v =>         // for each upper bound v:
    ~g(--d) &&       //   decrement d; success if g(d) is not equal to -1
    m ^ (            //   AND m is different from
      M = m |        //     the new bit-mask M
          1 << x + d //     where the bit corresponding to x + d is set
    ) &&             //   AND
    (k -= g``) * k   //   dy² = (g(d) - g(0))²
    < v &            //   is less than v
    f(a, x + d, M)   //   AND a recursive call at the new position is also true
  )                  // end of some()
```
[Answer]
# [Japt](https://github.com/ETHproductions/japt), 42 [bytes](https://en.wikipedia.org/wiki/ISO/IEC_8859-1)
```
Õcð í
o
v
à cá ®pV uWÃd_äÈcY ó x_raÃ<4 Ãr*
```
[Try it](https://petershaggynoble.github.io/Japt-Interpreter/?v=1.4.6&code=1WPwIO0Kbwp2CuAgY%2bEgrnBWIHVXw2Rf5MhjWSDzIHhfcmHDPDQgw3Iq&input=WwoKW1swLDAsMSwwLDAsMV0sCiBbMCwwLDAsMCwwLDBdLAogWzEsMCwwLDEsMCwwXSwKIFswLDEsMCwwLDEsMF1dCgpdCi1t)
[Test 1](https://petershaggynoble.github.io/Japt-Interpreter/?v=1.4.6&code=1WPwIO0Kbwp2CuEgY%2bAgrnBWIHVXw2Rf5MhjWSDzIHhfcmHDPDQgw3Iq&input=W1swLDAsMCwxLDBdLAogWzEsMSwxLDAsMF0sCiBbMCwwLDAsMCwwXSwKIFswLDAsMCwwLDFdXQ)
[Test 2](https://petershaggynoble.github.io/Japt-Interpreter/?v=1.4.6&code=1WPwIO0Kbwp2CuEgY%2bAgrnBWIHVXw2Rf5MhjWSDzIHhfcmHDPDQgw3Iq&input=W1swLDAsMCwwLDFdLAogWzEsMSwwLDAsMF0sCiBbMCwwLDEsMCwwXSwKIFswLDAsMCwxLDBdXQ)
[Test 3](https://petershaggynoble.github.io/Japt-Interpreter/?v=1.4.6&code=1WPwIO0Kbwp2CuEgY%2bAgrnBWIHVXw2Rf5MhjWSDzIHhfcmHDPDQgw3Iq&input=W1swLDAsMSwxLDAsMCwxLDBdLAogWzAsMCwwLDAsMCwwLDAsMF0sCiBbMSwwLDAsMCwwLDAsMCwwXSwKIFswLDEsMCwwLDEsMSwwLDFdXQ)
Temporarily fixed by using permutations to allow backwards jumps (really inefficient) , going to try @Nick Kennedy solution soon.
```
z cð í  // get each column height and pair with column index
o       // save end position and remove from array
v       // same for start pos
à  cá        // combinations of permutations 
  ®pV uWÃ  // restore end and start
d          // return true if any returns true to..
 _  ...  Ãr* // reduce result
  ä          // pass each consecutive x,y
   ÈcY ó     // 'reshape~transpose' => [ platform pair, index pair]
         x_raÃ // sum of absolute difference of each pair
               <4 // return if less for each pair
```
Saved 2 thanks to @Embodiment of Ignorance 
# [Japt](https://github.com/ETHproductions/japt) [`-Q`](https://codegolf.meta.stackexchange.com/a/14339/), 76 [bytes](https://en.wikipedia.org/wiki/ISO/IEC_8859-1)
```
Õcð í ïÈcY ó x_raÃ<4Ã®*JÃòUÎl
g0_ma
@T=Uc x UgUy_x_>0}Ãð _maÃT¥Uc x}a
o x >0
```
[Try it](https://petershaggynoble.github.io/Japt-Interpreter/?v=1.4.6&flags=LVE&code=1WPwIO0g78hjWSDzIHhfcmHDPDTDripKw/JVzmwKZzBfbWEKQFQ9VWMgeCBVZ1V5X3hfPjB9w/AgX21hw1SlVWMgeH1hCm8geCA%2bMA&input=WwpbWzAsMCwxLDAsMCwxXSwKIFswLDAsMCwwLDAsMF0sCiBbMSwwLDAsMSwwLDBdLAogWzAsMSwwLDAsMSwwXQpdLApbWzAsMCwwLDEsMF0sCiBbMSwxLDEsMCwwXSwKIFswLDAsMCwwLDBdLAogWzAsMCwwLDAsMV0KXSwKW1swLDAsMCwwLDFdLAogWzEsMSwwLDAsMF0sCiBbMCwwLDEsMCwwXSwKIFswLDAsMCwxLDBdCl0sCltbMCwxLDEsMSwwLDAsMCwwLDAsMCwxLDFdLAogWzEsMCwwLDAsMCwxLDEsMSwxLDEsMCwwXSwKIFswLDAsMCwwLDEsMCwwLDAsMCwwLDAsMF0KXSwKW1swLDAsMSwxLDAsMCwxLDEsMCwwLDEsMF0sCiBbMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDBdLAogWzEsMCwwLDAsMCwwLDAsMCwwLDAsMCwwXSwKIFswLDEsMCwwLDEsMSwwLDAsMSwxLDAsMV0KXSwKW1swLDAsMCwxLDEsMSwxLDAsMSwwLDAsMF0sCiBbMSwxLDEsMCwwLDAsMCwwLDAsMCwwLDBdLAogWzAsMCwwLDAsMCwwLDAsMSwwLDAsMCwwXSwKIFswLDAsMCwwLDAsMCwwLDAsMCwxLDEsMV0KXSwKW1swLDEsMSwxLDEsMSwxLDEsMCwwLDAsMV0sCiBbMSwwLDAsMCwwLDAsMCwwLDAsMCwxLDBdLAogWzAsMCwwLDAsMCwwLDAsMCwwLDEsMCwwXSwKIFswLDAsMCwwLDAsMCwwLDAsMSwwLDAsMF0KXQpbWzAsMCwwLDAsMCwwLDAsMCwwLDAsMCwxXSwKIFswLDAsMCwxLDAsMCwwLDAsMCwwLDAsMF0sCiBbMSwwLDAsMCwwLDAsMSwwLDAsMCwwLDBdLAogWzAsMSwxLDAsMSwxLDAsMSwxLDEsMSwwXV0sCl0KLW0)
Translation of  [Jelly answer](https://codegolf.stackexchange.com/a/196602/84844)  of @Nick Kennedy , a lot more efficient but longer , I think it can be shortened.
## Explanation / translation Jelly => Japt (taken from Nick answer)
```
ŒṪ  => Õcð í        M ultidimensional truthy indices of each
ạþ` => ïÈcY  òUÎl   O uter table using absolute difference and with the same argument on both sides:
§   => ó x_ra       Sum innermost lists
<4  => Ã<4Ã         Less than 4
N   => ®*JÃ         Negate
A1¦ => g0_ma        Absolute top row
ÐL  => @T=Uc x...T¥Uc x}a     Apply the following until no changes: 
   On my side I used T to store the total of the whole matrix to check if it changed because g() modify the original matrix.
A $¦ => Ug..._maÃ   Absolute the rows indicated by the following:
»/   => Uy_x_>0}    Max of each column : 
   on my side I rotated the table and reduced to get the positive rows
T    => Ãð          Truthy indices (i.e. where there’s a 1 in the column)
Ṫ    => o           Finally take the last row
Ṁ    => x >0        Max : on my side >0
```
[Answer]
# [R](https://www.r-project.org/), ~~137~~ 136 bytes
```
function(a,e=abs(outer(b<-which(a,T),b,`-`)),g=-(e[,1,,1]+e[,2,,2]<4),h=1){while(any(g<{g[h,]=abs(g[h,]);g}))h=colSums(g>0)>0;rev(g)[1]}
```
[Try it online!](https://tio.run/##lVTLboMwELz3KyyfvOpSZaPeEvIT7S1FiiEGLBFAQFpFUb6dujTpA5tHJB@cZbw7M7vZqo3Z2mvjYx41usiFROXLsBbFsVGVCNfeR6qj1IRfAUPceTsATHxPqC0SIgWP5rJEXAbrZ8DUJzibB5kSMj@JZH1OtikGXcLuBqvkApD6UZG9HA8muFnAZrGq1LtIYEvBpY2LSmimc5bpuhEPjFWhzvciEgtkEweQdTC6HRvzFe9gZMd7D2/Z/mJcRQEHSLo5WGlHtNAo5keLLdnS4ibZg5FVfcjGSS10j@RroWEnnT2ie5ycb7hjEkbbTa7zy3leH@dYNKmFRmfSHo/51efPZO9vOFJ6st19df9J0p0kaXRX2JfrzwEnnZScBGjYE5P8AYCdTYFINkKWZXYS2mzVUtaNQrMiM1nWyuccsFalz99yDgZcN0UlE/V0KPZKaDDbm/GsSHQkM37NxZm3YRxZbL4j@354aT8B "R – Try It Online")
Essentially an R translation of [my Jelly answer](https://codegolf.stackexchange.com/a/196602/42248), but with some R golfs to take advantage of the way `outer` works on arrays. A function that takes as its argument a logical matrix with the rows corresponding to the rows of the original question. Returns 1 for winnable and -1 for non-winnable.
[Answer]
# [Python 3](https://docs.python.org/3/), 198 bytes
A messy solution with NumPy, takes a list of strings as input:
```
w=lambda l:t(g(array(where((array(list(map(list,l)))=='=').T)).T))
from numpy import*
g=lambda p:abs(p[:,None]-p).sum(2)<4
t=lambda m,x=0:x+1==len(m)or max([t(m,p)for p in where(m[x])[0]if p>x]+[0])
```
[Try it online!](https://tio.run/##hVJNb4MwDL37V@RGsrGq@ziheT9hp90Qh1SjLVISopQK@utZGiCYlmoIotjYz/bzs5fmWJv3vm9RSb37lUxlDT9w6Zy88PZYupKPhqpODdfShkuqhBCICSZi8yPCB3tXa2bO2l5YpW3tmic4TKg2k7sTt3mWftemLF6s2JzOmr@Jzw9opiCddrjNuudXRFUarkXtmJYdz33d1Iq9Ny2rDBva0nlXiHxbVHtmv7ri2V9F31bGyJ0qGbIcWJ4w8iQp@IMh4mD79oMHByP4x5irY8oq0gloSpyDltAY7Ql6KDZCR6Bg45yGeNvjiLJSzAdHoAH7Gvd/R/P4Mc8DQQFwNuukBUbwEfJKrZFCShpGJ95RdDfZLTQu2Z@8MQjXZsXlqofXH2FW6yrT8LzlSrCrmlRQ0zh9Idb/z/x4ffV0bqBaAiojoAoCoOKBBQKVDFC1hKQoFKAaASoPoMoAoKtbVlqWJbsCoGuiHVFwgoDjTLP8Hs0UKJr1BjQutIc3SRh5jYv7Aw "Python 3 – Try It Online")
This assumes that no levels exist for which the bolded part here is of importance:
> 
> To complete a jump, it must be possible to move from the start point to the end point in four or less (including the start/end points) up, down, left, and right moves **which do not pass through a platform**.
> 
> 
> 
I have been unable to imagine such a level and none are given as a test case. ~~Likewise I can't imagine a level that requires a leftwards move so an appropriate test case there would be welcome also, if I'm mistaken.~~ Thanks to Nitrodon for pointing me in the right direciton.
# [Python 3](https://docs.python.org/3/), 214 bytes
```
lambda l:t(g(array(where((array(list(map(list,l)))=='=').T)).T),[])
from numpy import*
g=lambda p:abs(p[:,None]-p).sum(2)<4
t=lambda m,v,x=0:x+1==len(m)or max([t(m,v+[x],p)for p in where(m[x])[0]if x not in v]+[0])
```
[Try it online!](https://tio.run/##hVNNb4MwDL37V/hGsmZV93FC81/YaTfGgWq0QyIhorSlv74LAYJpqValqH7Yz/bLq700v5V5u57p@1pmevuTYRk3Yi@yus4u4vyb17kYgrI4NEJn1v9QpZSSKKJIrr9k91VJKmFXVxrNUdsLFtpWdfMEexqIbZxtD8ImsfqsTJ4@W7k@HLV4lR/v0IxJWp1US5u4Xb0QlbkRWlY16qwViWuuTqukTZWVOwdaLAz2E2qHymSTFjts0VRN9@aUrhwir@fCmGxb5kiYACYRsk@kwD2QiPrYLeQR6gOPDzkdMFalaiQaC6ekOTWFeKTumw3UgcjHNJUR3c44sCw0c8mBqOfu8v6faFo/1DEidzhFKKZZGUaAKaQAR7OssxeRHg2zMN6gOteZAkh3qt6JcUtN8wsb0ZBES/LQ3B39cY8wEY7nbo8HAAUaR9IJZuvCNCI5i1Ji5@bSu3nQ0P2TFt9PKjtjX7l6wE0M3L/ArQvAXQszBu5V4Db1RcGhwM0J3JfALQnADTDvNG/LbhyAXzafiJMzBhp2mnz/aCcv0WR04Hl@PLopoqBruP4/ "Python 3 – Try It Online")
A solution that incorporates leftwards movement, with tsh's test cases included. This cost quite a few bytes, I'll have to sleep on it to golf it more.
]