7 people like it.

Game of 2048

Simple implementation of the popular game "2048". Can you add up the tiles and reach 2048? The game can be played in fsi or you can add the GUI which is so far missing.

 ``` 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: ``` ``````/// This is a simple implementation of the 2048 game /// It's playable in fsi, I might hook it up to an app later using Xamarin's tooling. /// But so far it was just funny to implement the rules. namespace T2048 module Game = type Row = List type Board = List type Direction = LEFT | RIGHT | UP | DOWN let NEW_TILES = [2; 4] let mutable theScore = 0 let addScore s = theScore <- theScore + s // Here is the main logic of the game, moving the tiles and combining identical neighbours // We always move from right to left, other directions are performed by turning the board first let rec moveRow r = match r with | [] -> [] | 0::bs -> moveRow bs | [a] -> [a] | a::b::bs when b=0 -> moveRow(a::bs) | a::b::bs when a=b -> addScore(a+b) ; (a+b)::moveRow bs | a::b::bs -> a::moveRow(b::bs) let pad elem toLen bs = let padLen = toLen - List.length bs if padLen<=0 then bs else let newTail = [for i in 1 .. padLen -> elem] bs @ newTail let moveBoard b = let size = List.length b let moveAndPad = moveRow >> (pad 0 size) List.map moveAndPad b let reverseBoard = List.map List.rev let rec transposeBoard b = match b with | [] -> [] | []::_ -> [] | _ -> let heads = List.map List.head b let tails = List.map List.tail b heads :: transposeBoard tails // Turn the board, move left, and turn back let moveDirection d = match d with | LEFT -> moveBoard | RIGHT -> reverseBoard >> moveBoard >> reverseBoard | UP -> transposeBoard >> moveBoard >> transposeBoard | DOWN -> transposeBoard >> reverseBoard >> moveBoard >> transposeBoard >> List.rev let emptySlots b = let slot i j v = ((i,j),v) let numberRow f row = List.mapi f row let numberBoard = List.mapi (fun i -> numberRow (slot i)) let empties = List.choose (fun (a,b) -> if b=0 then Some(a) else None) b |> numberBoard |> List.concat |> empties let rnd = new System.Random() let oneOf vs = let i = rnd.Next(List.length vs) List.nth vs i let updateBoard coords v board = let (posRow,posCol) = coords let updateRow pos v row = List.mapi (fun i b -> if i=pos then v else b) row List.mapi (fun i row -> if i=posRow then updateRow posCol v row else row) board let addNewTile b = let empties = emptySlots b let slotCoords = oneOf empties let v = oneOf NEW_TILES updateBoard slotCoords v b // To detect "game over", try a direction which is 90 degress from the current one and see if any tiles can move let otherDirection d = match d with | LEFT -> UP | RIGHT -> UP | UP -> LEFT | DOWN -> LEFT // Perform a move let nextMove b d = let newBoard = b |> (moveDirection d) |> addNewTile let gameOver = newBoard=b && (moveDirection (otherDirection d) b)=b (newBoard, gameOver) // Install a pretty printer if we are running in fsi let buildString sep l = List.foldBack (fun a acc -> sprintf "%4i %s %s" a sep acc) l "" let printBoard (b:Board) = b |> List.map (buildString "|") |> List.reduce (fun a b -> a+"\n"+b) #if INTERACTIVE fsi.AddPrinter printBoard #endif // Here is the current state let mutable theBoard:Board = [] // Start a new game let reset () = let _ = theScore <- 0 let _ = theBoard <- [[0;0;0;0]; [0;0;0;0]; [0;0;0;0]; [0;0;0;0]] |> addNewTile theBoard // Make a move and update the current state let move d = let (newBoard, gameOver) = nextMove theBoard d let _ = if gameOver then printf "Game over, score=%i" theScore let _ = theBoard <- newBoard theBoard ``````
type Row = List<int>

Full name: T2048.Game.Row
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
| ( [] )
| ( :: ) of Head: 'T * Tail: 'T list
interface IEnumerable
interface IEnumerable<'T>
member Head : 'T
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
member Tail : 'T list
static member Cons : head:'T * tail:'T list -> 'T list
static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
type Board = List<Row>

Full name: T2048.Game.Board
type Direction =
| LEFT
| RIGHT
| UP
| DOWN

Full name: T2048.Game.Direction
union case Direction.LEFT: Direction
union case Direction.RIGHT: Direction
union case Direction.UP: Direction
union case Direction.DOWN: Direction
val NEW_TILES : int list

Full name: T2048.Game.NEW_TILES
val mutable theScore : int

Full name: T2048.Game.theScore
val addScore : s:int -> unit

val s : int
val moveRow : r:int list -> int list

Full name: T2048.Game.moveRow
val r : int list
val bs : int list
val a : int
val b : int
val pad : elem:'a -> toLen:int -> bs:'a list -> 'a list

val elem : 'a
val toLen : int
val bs : 'a list
val padLen : int
val length : list:'T list -> int

Full name: Microsoft.FSharp.Collections.List.length
val newTail : 'a list
val i : int
val moveBoard : b:int list list -> int list list

Full name: T2048.Game.moveBoard
val b : int list list
val size : int
val moveAndPad : (int list -> int list)
val map : mapping:('T -> 'U) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.map
val reverseBoard : (int list list -> int list list)

Full name: T2048.Game.reverseBoard
val rev : list:'T list -> 'T list

Full name: Microsoft.FSharp.Collections.List.rev
val transposeBoard : b:'a list list -> 'a list list

Full name: T2048.Game.transposeBoard
val b : 'a list list
val heads : 'a list
val head : list:'T list -> 'T

val tails : 'a list list
val tail : list:'T list -> 'T list

Full name: Microsoft.FSharp.Collections.List.tail
val moveDirection : d:Direction -> (int list list -> int list list)

Full name: T2048.Game.moveDirection
val d : Direction
val emptySlots : b:int list list -> (int * int) list

Full name: T2048.Game.emptySlots
val slot : ('a -> 'b -> 'c -> ('a * 'b) * 'c)
val i : 'a
val j : 'b
val v : 'c
val numberRow : ((int -> 'a -> 'b) -> 'a list -> 'b list)
val f : (int -> 'a -> 'b)
val row : 'a list
val mapi : mapping:(int -> 'T -> 'U) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.mapi
val numberBoard : (int list list -> ((int * int) * int) list list)
val empties : (((int * int) * int) list -> (int * int) list)
val choose : chooser:('T -> 'U option) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.choose
val a : int * int
union case Option.Some: Value: 'T -> Option<'T>
union case Option.None: Option<'T>
val concat : lists:seq<'T list> -> 'T list

Full name: Microsoft.FSharp.Collections.List.concat
val rnd : System.Random

Full name: T2048.Game.rnd
namespace System
Multiple items
type Random =
new : unit -> Random + 1 overload
member Next : unit -> int + 2 overloads
member NextBytes : buffer:byte[] -> unit
member NextDouble : unit -> float

Full name: System.Random

--------------------
System.Random() : unit
System.Random(Seed: int) : unit
val oneOf : vs:'a list -> 'a

Full name: T2048.Game.oneOf
val vs : 'a list
System.Random.Next() : int
System.Random.Next(maxValue: int) : int
System.Random.Next(minValue: int, maxValue: int) : int
val nth : list:'T list -> index:int -> 'T

Full name: Microsoft.FSharp.Collections.List.nth
val updateBoard : int * int -> v:'a -> board:'a list list -> 'a list list

Full name: T2048.Game.updateBoard
val coords : int * int
val v : 'a
val board : 'a list list
val posRow : int
val posCol : int
val updateRow : (int -> 'b -> 'b list -> 'b list)
val pos : int
val v : 'b
val row : 'b list
val b : 'b
val addNewTile : b:int list list -> int list list

val empties : (int * int) list
val slotCoords : int * int
val v : int
val otherDirection : d:Direction -> Direction

Full name: T2048.Game.otherDirection
val nextMove : b:int list list -> d:Direction -> int list list * bool

Full name: T2048.Game.nextMove
val newBoard : int list list
val gameOver : bool
val buildString : sep:string -> l:int list -> string

Full name: T2048.Game.buildString
val sep : string
val l : int list
val foldBack : folder:('T -> 'State -> 'State) -> list:'T list -> state:'State -> 'State

Full name: Microsoft.FSharp.Collections.List.foldBack
val acc : string
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
val printBoard : b:Board -> string

Full name: T2048.Game.printBoard
val b : Board
val reduce : reduction:('T -> 'T -> 'T) -> list:'T list -> 'T

Full name: Microsoft.FSharp.Collections.List.reduce
val a : string
val b : string
val mutable theBoard : Board

Full name: T2048.Game.theBoard
val reset : unit -> Board

Full name: T2048.Game.reset
val move : d:Direction -> Board

Full name: T2048.Game.move
val printf : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printf