# Is it a good 2048 board?

This is my first question here, so any suggestions in the comments would be appreciated! Thanks ;)

# Introduction

One very common strategy for the 2048 game is never ever swiping down. This positions all the big numbers at the top, and the lower ones in the bottom. So, if you apply this strategy correctly, your board will always match the following pattern:

Your submission should be either a full program or a function which returns a truthy value if the board can be described like this: Going down each column of the board, the first number should be the highest of the column, the second number should be less than or equal to the first number, etc. A good 2048-board is defined as a board where the highest numbers are all on the top. This is code-golf, so the shortest Code per language (in bytes) wins.

# I/O

The input can be taken in any appropriate way, for example an array of 4 arrays, each containing 4 numbers, or an array of 16 numbers. In total, it will be always 16 numbers, representing the 4x4 board The output should be a truthy value of the input is a "good 2048-board", and a falsy value otherwise.

# Examples

Truthy:

|-------------------|
| 16 |    | 64 |  8 |
|-------------------|
|  8 |    | 32 |  8 |
|-------------------|
|  4 |    | 32 |  2 |
|-------------------|
|  2 |    |    |    |
|-------------------|

|-------------------|
| 16 | 128| 64 | 32 |
|-------------------|
|  8 | 128| 32 |  8 |
|-------------------|
|  4 | 16 |  8 |  2 |
|-------------------|
|  4 |    |    |    |
|-------------------|


Falsy:

|-------------------|
| 16 |    | 64 |  8 |
|-------------------|
|  8 |    | 32 | 16 |
|-------------------|
| 32 |    | 128|  2 |
|-------------------|
|  2 |    |    |    |
|-------------------|

|-------------------|
| 16 | 128| 64 | 32 |
|-------------------|
|  8 |  32|    |  8 |
|-------------------|
|  4 | 16 |  8 |  2 |
|-------------------|
|  4 |    |    |    |
|-------------------|


# Note

Look at the 2nd falsy test case: When there is an empty value (or a 0) somewhere and even when it's followed by a value which is higher than the last non-zero number, this should be falsy, because the next value after the zero would be higher than the 0 itself, which makes it invalid.

Good luck!

• Comments are not for extended discussion; this conversation has been moved to chat. – Martin Ender Sep 3 '17 at 13:14

all$scanr1 max>>=(==)  Try it online! Takes a list of columns, with empty spaces as 0. • Gives the wrong output for [[16,8,4,0],[16,0,4,4],[16,4,4,4],[16,4,4,4]]. – Jonathan Allan Aug 1 '17 at 13:39 • @JonathanAllan It returns false as it should, your 2nd column is [16,0,4,4] which is not monotonic. Or am I missing something? – I want to make games Aug 1 '17 at 14:07 • 0 is your placeholder for an empty cell, not a value of 0. – Jonathan Allan Aug 1 '17 at 14:09 • @Iwanttomakegames that comment was meant for you (replace "your" with "the"). – Jonathan Allan Aug 1 '17 at 15:12 • @JonathanAllan I am sorry for all the confusion, but 0 should indeed, while representing an empty cell, count as the value 0. Empty cells should be treated like the value '0'. – dv02 Aug 1 '17 at 16:52 # 05AB1E, 4 bytes €{íQ  Try it online! Same as my other two answers. I promise this is my last one until others have answered :) # APL (Dyalog), 7 4 bytes Takes 4-by-4 matrix, using 0 for blanks, as argument. ⊢≡⌊⍀  Try it online! ⌊⍀ is the vertical cumulative minimum ≡ identical to ⊢ the unmodified argument? • Amazing golf! (I expected that from someone who works for Dyalog and has programmed APL for a long time). And, yes, MY does have a lot of APL symbols, though they're not APL symbols. Alpha, Iota, Omega are all greek, not APL technically. They came to mind first when thinking of one-character commands. Hence MY's increment and decrement are Jelly's, because that came to mind first. (Just to notify you, I'm suspended from chat, hence the response here.) – Zacharý Aug 2 '17 at 23:45 # Jelly, 4 bytes Ṣ€U⁼  Try it online! Input as an array of columns. Works with arbitrary-sized grids. • What is the representation of an empty cell? (e.g. 3rd col of 2nd falsey test case) - "in total it will be always 16 numbers". It would work with zeros if you filter them out first. – Jonathan Allan Aug 1 '17 at 12:16 • @JonathanAllan According to the specs, I think this is valid too – HyperNeutrino Aug 1 '17 at 14:22 • Yet that will now fail my suggested test case returning 0 rather than 1. – Jonathan Allan Aug 1 '17 at 14:35 • @JonathanAllan How do you filter in Jelly ._. I'd expect this to work but ḟ0 doesn't work – HyperNeutrino Aug 1 '17 at 15:05 • @DirtyDev That's alright, we're here to enjoy the challenges and help new users get used to this place :) I hope you're enjoying the community – HyperNeutrino Aug 1 '17 at 17:35 # R (+pryr), 23 bytes pryr::f(all(diff(x))<1)  Which evaluates to the function function (x) all(diff(x)) < 1  Which takes a matrix as input:  [,1] [,2] [,3] [,4] [1,] 16 0 64 8 [2,] 8 0 32 8 [3,] 4 0 32 2 [4,] 2 0 0 0  When given a matrix, diff automatically calculates the differences within rows (surprisingly. I didn't know of this feature until I tried it for this challenge).  [,1] [,2] [,3] [,4] [1,] -8 0 -32 0 [2,] -4 0 0 -6 [3,] -2 0 -32 -2  None of these values can be 1 or higher in a good board, so we test for <1 and see if all values of the matrix comply.  [,1] [,2] [,3] [,4] [1,] TRUE TRUE TRUE TRUE [2,] TRUE TRUE TRUE TRUE [3,] TRUE TRUE TRUE TRUE [1] TRUE  # JavaScript, 37 bytes x=>''+x==x.map(v=>v.sort((x,y)=>y-x))  Call it like this: |-------------------| | 16 | | 64 | 8 | |-------------------| | 8 | | 32 | 8 | |-------------------| | 4 | | 32 | 2 | |-------------------| | 2 | | | | |-------------------| f([[8,8,2,0],[64,32,32,0],[0,0,0,0],[16,8,4,2]])  Tested on Firefox, Chrome, JavaScript Shell, and, Node.js. • Why do you turn the result into a string? (''+) – Zacharý Aug 1 '17 at 17:37 • @Zacharý sort is mutable method, which will mutate the array. first convert to string will save a copy of the array. converting to string also make the equal operation works by (string) value instead of reference. – tsh Aug 2 '17 at 1:34 # Python 3, 42 bytes lambda l:all(x==sorted(x)[::-1]for x in l)  Try it online! Same algorithm as my Jelly answer • -8 bytes in Python 3 or -14 bytes in Python 2. – notjagan Aug 1 '17 at 15:43 • @notjagan thanks – HyperNeutrino Aug 1 '17 at 15:50 # C# (.NET Core), 71 bytes i=>{for(int n=3;++n<i.Length;)if(i[n]>i[n-4])return false;return true;}  Try it online! The BORING way. Expects input flattened into a linear array. Alternatively the explicitly forbidden way: i=>{for(int n=3;i[++n]<=i[n-4];);}  Try it online! Throws an IndexOutOfBoundsException to indicate true, ends normally to indicate false. I tried a version that included conversion from exception/no exception to true/false, but it ended up just as long as the regular version. # JavaScript, 34, 32 bytes v=>!v.some((x,i)=>i%4&&x>v[i-1])  Call by passing in a single array containing the first column, followed by the 2nd, 3rd, and 4th. Compares each number to the previous number except for the first number of each column and returns true if all are true. ## Test f=v=>!v.some((x,i)=>i%4&&x>v[i-1]) f([16,8,4,2,0,0,0,0,64,32,32,0,8,8,2,0]) f([16,8,4,4,128,128,16,0,64,32,8,0,32,8,2,0]) f([16,8,32,2,0,0,0,0,64,32,128,0,8,16,2,0]) f([16,8,4,4,128,32,16,0,64,0,8,0,32,8,2,0])  Edit: saved 2 bytes thanks to tsh • after some boolean transform: v=>!v.some((x,i)=>i%4&&x>v[i-1]) – tsh Aug 3 '17 at 7:04 # Haskell, 28 bytes all$and.(zipWith(>=)=<<tail)


There's also

all$(==)=<<sort  with 15 bytes but it requires import Data.List when working with the Prelude only. Alternatively, all$(==)=<<Data.List.sort


with 25 bytes works in GHCI.

# Gaia, 3 6 bytes

+3 bytes because apparently I didn't know how my language worked

ọ¦_ẏ⁇!


This is a function accepting a list of columns and leaving the result on the stack.

A few other 6 byte solutions exist including 0+¦o¦ẏ and ọ¦_ẏ¦ỵ.

Try it online!

### Explanation

ọ¦      Deltas of each column
_     Flatten
ẏ⁇   Keep only positive numbers
!  Negate (is it empty?)

• Can't downvote, but using an operator added to the language after the challenge was posted doesn't seem fair to me.Also it seems to be forbidden by default according to this. – Cinaski Aug 2 '17 at 13:57
• @Cinaski We've kind of moved away from that rule, as seen here. Either way, my alternative solutions only use operators that definitely existed before the challenge. – Business Cat Aug 2 '17 at 14:01
• I'll just change it to one of the others I guess – Business Cat Aug 2 '17 at 14:02
• Never mind, I was not aware of that new rule. – Cinaski Aug 2 '17 at 14:07

# TI-BASIC, 25 bytes

Takes input as a 4x4 matrix in Ans.

For(R,1,3
*row+(-1,Ans,R+1,R
End
Ans=abs(Ans


# Explanation

For(R,1,3             Loop from row 1 to 3.

*row+(-1,Ans,R+1,R    Multiply row R+1 by -1 and add it to row R in-place.
Effectively, this subtracts row R+1 from row R.

End                   Now the first 3 rows contain the row differences,
and the 4th row is non-negative assuming valid input.

Ans=abs(Ans           Check whether every element in the matrix is equal to its
absolute value, or in other words, contains no negative values.


f[x]=1>0
f(a:b:c)|a<b=1<0|1>0=f$b:c all f  Try it online! Defines the point-free function all f, where f determines if a list is sorted. • Darn, this beats Python by 1 byte ;P – HyperNeutrino Aug 1 '17 at 2:22 • @HyperNeutrino Well the xnor's beats python by 21. :P – Ad Hoc Garf Hunter Aug 1 '17 at 3:17 • You can also define f as f(a:b:c)=a>=b&&f(b:c) – Cristian Lupascu Aug 1 '17 at 11:03 # JavaScript (ES6), 42 bytes Takes an array of columns; returns a (truthy) number or false. a=>a.every(c=>c.reduce((r,n)=>r&&n<=r&&n))  # JavaScript (ES6), 54 47 bytes First attempt. Takes an array of columns; returns true or false. a=>a.every(c=>c.slice(1).every((n,i)=>n<=c[i]))  • Which value are you expecting for empty cells? – Arnauld Aug 1 '17 at 9:02 # MATL, 4 bytes SGX=  Try it online! Input as an array of rows, upside down. S % sort columns GX= % compare with input % true if arrays are numerically equal % (implicit) convert to string and display  • Does not work for cases that should return truthy which have zeros between column elements like this for example. – Jonathan Allan Aug 1 '17 at 12:29 • You're right, I'm working on a solution. BTW I'm not the only one having problems with empty cells ;) – Cinaski Aug 1 '17 at 12:57 • Yeah, I can see that. I suggested a test case for it too. Ping when fixed and you'll get an upvote from me :) – Jonathan Allan Aug 1 '17 at 13:02 • @JonathanAllan wait, who said that it should return truthy when there are zeros between column elements? Look at my second falsy test case, an empty cell / a 0 followed by a higher value when going down is invalid. – dv02 Aug 1 '17 at 16:27 • @DirtyDev FYI with the wording originally given, and its sensible interpretation, your second falsey case would still be falsey; it's just my suggested test case would be truthy. – Jonathan Allan Aug 1 '17 at 16:55 # Swift 4, 84 77 bytes func f(l:[[Int]]){print(l.filter{$0.reversed()==\$0.sorted()}.count==l.count)}


Try it online!

# Dyalog APL, 2119 15 bytes

∧/{⍵≡⍵[⍒⍵]}¨↓⍉⎕


Try it online! (modified so it will run in tryapl)

Takes input as a 2D array.

## How?

• ⎕ input
• ⍉ transpose
• ↓ 2D array => 1D vector of 1D vectors
• { ... }¨ apply this to each member (argument ⍵):
• ⍵[⍒⍵] ⍵ sorted descending
• ⍵≡ equality with ⍵
• ∧/ whether every element is 1.

# Japt, 7 bytes

Tried a few different methods for this one but, in the end, the shortest I could come up with ended up being a port of tsh's JS solution.

Takes an array of columns as input. Empty cells can be 0 or omitted if there are no other numbers in the column.

P+U¥®n§


Test it

## Explanation

Implicit input of array U.

P+U


Prepend U with an empty string, converting the array to a string.

¥


Check for equality, which casts the right hand side to a string, too.

®


Map over U.

n§


Sort (n) by <=.

Implicitly output boolean result.

• Nice arrangement to skip the second U. You could do nn at the end as well ;) – ETHproductions Aug 1 '17 at 13:32
• I was surprised to find that omitting the second U worked in this case, @ETHproductions; I thought it would only work if the variable was the only thing to the left of the ==. I'll have to remember it for future use. – Shaggy Aug 1 '17 at 13:34

# Clojure, 30 bytes

(partial every? #(apply >= %))


try it online

• Welcome to PPCG, and nice first post! – Zacharý Aug 6 '17 at 15:33

# Java 8, 69 bytes

b->{for(int[]c:b)for(int i=0,f=1;i<3;)if(c[i]<c[++i])f=0;return f>0;}


Well, as of this writing this beats the Swift solution, so there's that! Utterly straightforward. Input is an array of integer arrays, the inner arrays being columns of the board (upper squares first). Cast to Function<int[][], Boolean>.

# MY, 6662 20 bytes (noncompeting)

ω⍉ω⍉A6ǵ'ƒ⇹(E8ǵ'ƒ⇹(Π←


Try it online!

The reason this is non competing is that I recently implemented 8E (≡), which is equivalent to APL ≡.

## How?

• ω⍉ The first command line argument transposed
• ω⍉ The first command line argument transposed
• A6ǵ' push chr(0x6A) (⍖ in the codepage, which sorts descending)
• ƒ as a function, rather than a string
• ⇹ push a function that maps a popped function over each argument
• ( apply
• E8ǵ'ƒ⇹( the same thing, except with chr(0x8E), which is the match command (≡).
• Π product
• ← output with no newline

Yes, a lot of MY's symbols are exactly the same or similar to APL's. The explanation is that they came to mind when I wanted a 1-character command. (I don't know why I didn't use T for transpose)

# Mathematica, 27 bytes

t=Thread;-t[Sort/@-t@#]==#&

## Explanation:

• Thread is a weird general transpose-like operation that happens to take the transpose when given a matrix.
• t=Thread; lets me use t twice instead of Thread twice to save bytes.
• Sort sorts a list (in increasing order).
• Sort\@ maps the Sort function to each element of a list individually; when applied to a matrix, it sorts the rows.
• t@# applies the transpose function to the input # of the main function.
• - takes the negative of all of the entries so that sorting the rows of the transposed matrix (the columns of the original) sorts them in the desired way.
• The outer -t[...] undoes the negative and the transpose, so all we really did was sort the columns largest-to-smallest.
• ==# tests to see if this new column-sorted matrix is equal to the original input.
• & ends the anonymous function with input # we defined.

You can try it online in the Wolfram Cloud sandbox by pasting code like the following and clicking Gear->"Evaluate cell" or hitting Shift+Enter or the numpad Enter:

t=Thread;-t[Sort/@-t@#]==#&@{{16,128,64,32},{8,32,0,8},{4,16,8,2},{4,0,0,0}}


Or for all test cases:

t=Thread;-t[Sort/@-t@#]==#&//Map[#,{{{16,0,64,8},{8,0,32,8},{4,0,32,2},{2,0,0,0}},{{16,128,64,32},{8,128,32,8},{4,16,8,2},{4,0,0,0}},{{16,0,64,8},{8,0,32,16},{32,0,128,2},{2,0,0,0}},{{16,128,64,32},{8,32,0,8},{4,16,8,2},{4,0,0,0}}}]&