2048: Difference between revisions

204,811 bytes added ,  30 days ago
m
→‎{{header|FutureBasic}}: Remove FutureBasic 'Output' label
m (→‎{{header|FutureBasic}}: Remove FutureBasic 'Output' label)
 
(62 intermediate revisions by 28 users not shown)
Line 6:
Implement a 2D sliding block puzzle game where blocks with numbers are combined to add their values.
 
 
The rules are that on each turn the player must choose a direction (up, down, left or right) and all tiles move as far as possible in that direction, some more than others. Two adjacent tiles (in that direction only) with matching numbers combine into one bearing the sum of those numbers. A move is valid when at least one tile can be moved, if only by combination. A new tile with the value of 2 is spawned at the end of each turn at a randomly chosen empty square, if there is one. To win the player must create a tile with the number 2048. The player loses if no valid moves are possible.
;Rules of the game:
:*   The rules are that on each turn the player must choose a direction   (up, down, left or right).
:*   All tiles move as far as possible in that direction, some move more than others.
:*   Two adjacent tiles (in that direction only) with matching numbers combine into one bearing the sum of those numbers.
:*   A move is valid when at least one tile can be moved, including by combination.
:*   A new tile is spawned at the end of each turn at a randomly chosen empty square   (if there is one).
:*   Most of the time, a new '''2''' is to be added, but occasionally ('''10%''' of the time), a '''4'''.
:*   To win, the player must create a tile with the number '''2048'''.
:*   The player loses if no valid moves are possible.
 
 
The name comes from the popular open-source implementation of this game mechanic, [https://gabrielecirulli.github.io/2048/ 2048].
 
Requirements:
* "Non-greedy" movement. The tiles that were created by combining other tiles should not be combined again during the same turn (move). That is to say that moving the tile row of
 
;Requirements:
[2][2][2][2]
* &nbsp; "Non-greedy" movement.<br>&nbsp; The tiles that were created by combining other tiles should not be combined again during the same turn (move).<br>&nbsp; That is to say, that moving the tile row of:
 
<big><big> [2][2][2][2] </big></big>
 
:: to the right should result in:
 
<big><big> ......[4][4] </big></big>
 
:: and not:
to the right should result in
 
<big><big> .........[8] </big></big>
......[4][4]
 
* &nbsp; "Move direction priority".<br>&nbsp; If more than one variant of combining is possible, move direction shall indicate which combination will take effect. <br>&nbsp; For example, moving the tile row of:
and not
 
<big><big> ...[2][2][2] </big></big>
.........[8]
 
:: to the right should result in:
* "Move direction priority". If more than one variant of combining is possible, move direction shows one that will take effect. For example, moving the tile row of
 
<big><big> ......[2][4] </big></big>
...[2][2][2]
 
:: and not:
to the right should result in
 
<big><big> ......[24][42] </big></big>
 
and not
 
......[4][2]
 
* Adding&nbsp; aCheck newfor tilevalid onmoves. aThe blankplayer space.shouldn't Mostbe ofable theto timegain new "2"tile isby totrying bea addedmove andthat occasionallydoesn't (10% ofchange the time) - "4"board.
* &nbsp; Check for a win condition.
* Check for valid moves. The player shouldn't be able to skip their turn by trying a move that doesn't change the board.
* Win&nbsp; Check for a lose condition.
* Lose condition.
<br><br>
 
=={{header|AArch64 Assembly}}==
{{works with|as|Raspberry Pi 3B version Buster 64 bits}}
<syntaxhighlight lang="aarch64 assembly">
/* ARM assembly AARCH64 Raspberry PI 3B */
/* program 2048_64.s */
 
/*******************************************/
/* Constantes file */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"
.equ SIZE, 4
.equ TOTAL, 2048
.equ BUFFERSIZE, 80
 
.equ KEYSIZE, 8
.equ IOCTL, 0x1D // Linux syscall
.equ SIGACTION, 0x86 // Linux syscall
.equ SYSPOLL, 0x16 // Linux syscall
.equ CREATPOLL, 0x14 // Linux syscall
.equ CTLPOLL, 0x15 // Linux syscall
.equ TCGETS, 0x5401
.equ TCSETS, 0x5402
.equ ICANON, 2
.equ ECHO, 10
.equ POLLIN, 1
.equ EPOLL_CTL_ADD, 1
.equ SIGINT, 2 // Issued if the user sends an interrupt signal (Ctrl + C)
.equ SIGQUIT, 3 // Issued if the user sends a quit signal (Ctrl + D)
.equ SIGTERM, 15 // Software termination signal (sent by kill by default)
.equ SIGTTOU, 22
 
/*******************************************/
/* Structures */
/********************************************/
/* structure termios see doc linux*/
.struct 0
term_c_iflag: // input modes
.struct term_c_iflag + 4
term_c_oflag: // output modes
.struct term_c_oflag + 4
term_c_cflag: // control modes
.struct term_c_cflag + 4
term_c_lflag: // local modes
.struct term_c_lflag + 4
term_c_cc: // special characters
.struct term_c_cc + 40 // see length if necessary
term_fin:
/* structure sigaction see doc linux */
.struct 0
sa_handler:
.struct sa_handler + 8
sa_mask:
.struct sa_mask + 8
sa_flags:
.struct sa_flags + 8
sa_sigaction:
.struct sa_sigaction + 8
sa_fin:
/* structure poll see doc linux */
.struct 0
poll_event: // events mask
.struct poll_event + 8
poll_fd: // events returned
.struct poll_fd + 8
poll_fin:
/*********************************/
/* Initialized data */
/*********************************/
.data
szMessOK: .asciz "Bravo !! You win. \n"
szMessNotOK: .asciz "You lost !! \n"
szMessNewGame: .asciz "New game (y/n) ? \n"
szMessErreur: .asciz "Error detected.\n"
szMessErrInitTerm: .asciz "Error terminal init.\n"
szMessErrInitPoll: .asciz "Error poll init.\n"
szMessErreurKey: .asciz "Error read key.\n"
szMessErr: .asciz "Error code hexa : @ décimal : @ \n"
szCarriageReturn: .asciz "\n"
szMess0: .asciz " "
szMess2: .asciz " 2 "
szMess4: .asciz " 4 "
szMess8: .asciz " 8 "
szMess16: .asciz " 16 "
szMess32: .asciz " 32 "
szMess64: .asciz " 64 "
szMess128: .asciz " 128 "
szMess256: .asciz " 256 "
szMess512: .asciz " 512 "
szMess1024: .asciz " 1024 "
szMess2048: .asciz " 2048 "
szCleax1: .byte 0x1B
.byte 'c' // other console clear
.byte 0
 
szLineH: .asciz "-----------------------------\n"
szLineV: .asciz "|"
szLineVT: .asciz "| | | | |\n"
.align 4
qGraine: .quad 123456
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
.align 4
sZoneConv: .skip 24
sBuffer: .skip BUFFERSIZE
qTbCase: .skip 8 * SIZE * SIZE
qEnd: .skip 8 // 0 loop 1 = end loop
qTouche: .skip KEYSIZE // value key pressed
stOldtio: .skip term_fin // old terminal state
stCurtio: .skip term_fin // current terminal state
stSigAction: .skip sa_fin // area signal structure
stSigAction1: .skip sa_fin
stSigAction2: .skip sa_fin
stSigAction3: .skip sa_fin
stPoll1: .skip poll_fin // area poll structure
stPoll2: .skip poll_fin
stevents: .skip 16
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: // entry of program
mov x0,#0
bl initTerm // terminal init
cmp x0,0 // error ?
blt 100f
bl initPoll // epoll instance init
cmp x0,0
blt 99f
mov x22,x0 // save epfd
1: // begin game loop
ldr x0,qAdrszCleax1
bl affichageMess
bl razTable
2:
bl addDigit
cmp x0,#-1
beq 5f // end game
bl displayGame
3:
mov x0,x22
bl waitKey
cmp x0,0
beq 3b
bl readKey
cmp x0,#-1
beq 99f // error
bl keyMove
cmp x0,#0
beq 3b // no change -> loop
cmp x0,#2 // last addition = 2048 ?
beq 4f
cmp x0,#-1 // quit ?
bne 2b // loop
b 10f
4: // last addition = 2048
ldr x0,qAdrszMessOK
bl affichageMess
b 10f
5: // display message no solution
ldr x0,qAdrszMessNotOK
bl affichageMess
 
10: // display new game ?
ldr x0,qAdrszCarriageReturn
bl affichageMess
ldr x0,qAdrszMessNewGame
bl affichageMess
11:
mov x0,x22
bl waitKey
cmp x0,0
beq 11b
bl readKey
ldr x0,qAdrqTouche
ldrb w0,[x0]
cmp w0,#'y'
beq 1b
cmp w0,#'Y'
beq 1b
99:
bl restauTerm // terminal restaur
100: // standard end of the program
mov x0, #0 // return code
mov x8, #EXIT // request to exit program
svc #0 // perform the system call
qAdrszCarriageReturn: .quad szCarriageReturn
qAdrszMessNotOK: .quad szMessNotOK
qAdrszMessOK: .quad szMessOK
qAdrszMessNewGame: .quad szMessNewGame
qAdrsZoneConv: .quad sZoneConv
qAdrszCleax1: .quad szCleax1
qAdrszMessErrInitTerm: .quad szMessErrInitTerm
qAdrszMessErrInitPoll: .quad szMessErrInitPoll
qAdrszMessErreurKey: .quad szMessErreurKey
qAdrstOldtio: .quad stOldtio
qAdrstCurtio: .quad stCurtio
qAdrstSigAction: .quad stSigAction
qAdrstSigAction1: .quad stSigAction1
qAdrSIG_IGN: .quad 1
qAdrqEnd: .quad qEnd
qAdrqTouche: .quad qTouche
qAdrstevents: .quad stevents
/******************************************************************/
/* raz table cases */
/******************************************************************/
razTable:
stp x0,lr,[sp,-16]! // save registres
stp x1,x2,[sp,-16]! // save registres
ldr x1,qAdrqTbCase
mov x2,#0
1:
str xzr,[x1,x2,lsl #3]
add x2,x2,#1
cmp x2,#SIZE * SIZE
blt 1b
100:
ldp x1,x2,[sp],16 // restaur des 2 registres
ldp x0,lr,[sp],16 // restaur des 2 registres
ret
/******************************************************************/
/* key move */
/******************************************************************/
/* x0 contains key value */
keyMove:
stp x1,lr,[sp,-16]! // save registres
lsr x0,x0,#16
cmp x0,#0x42 // down arrow
bne 1f
bl moveDown
b 100f
1:
cmp x0,#0x41 // high arrow
bne 2f
bl moveUp
b 100f
2:
cmp x0,#0x43 // right arrow
bne 3f
bl moveRight
b 100f
3:
cmp x0,#0x44 // left arrow
bne 4f
bl moveLeft
b 100f
4:
ldr x0,qAdrqTouche
ldrb w0,[x0]
cmp w0,#'q' // quit game
bne 5f
mov x0,#-1
b 100f
5:
cmp w0,#'Q' // quit game
bne 100f
mov x0,#-1
b 100f
 
100:
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
/******************************************************************/
/* move left */
/******************************************************************/
/* x0 return -1 if ok */
moveLeft:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
stp x4,x5,[sp,-16]! // save registres
stp x6,x7,[sp,-16]! // save registres
stp x8,x9,[sp,-16]! // save registres
stp x10,x11,[sp,-16]! // save registres
ldr x1,qAdrqTbCase
mov x0,#0 // top move Ok
mov x2,#0 // line indice
1:
mov x6,#0 // counter empty case
mov x7,#0 // first digit
mov x10,#0 // last digit to add
mov x3,#0 // column indice
2:
lsl x5,x2,#2 // change this if size <> 4
add x5,x5,x3 // compute table indice
ldr x4,[x1,x5,lsl #3]
cmp x4,#0
cinc x6,x6,eq // positions vides
beq 5f
cmp x6,#0
beq 3f // no empty left case
mov x8,#0
str x8,[x1,x5,lsl #3] // raz digit
sub x5,x5,x6
str x4,[x1,x5,lsl #3] // and store to left empty position
mov x0,#1 // move Ok
3:
cmp x7,#0 // first digit
beq 4f
cmp x10,x4 // prec digit have to add
beq 4f
sub x8,x5,#1 // prec digit
ldr x9,[x1,x8,lsl #3]
cmp x4,x9 // equal ?
bne 4f
mov x10,x4 // save digit
add x4,x4,x9 // yes -> add
str x4,[x1,x8,lsl #3]
cmp x4,#TOTAL
beq 6f
mov x4,#0
str x4,[x1,x5,lsl #3]
add x6,x6,#1 // empty case + 1
mov x0,#1 // move Ok
4:
add x7,x7,#1 // no first digit
 
5: // and loop
add x3,x3,#1
cmp x3,#SIZE
blt 2b
add x2,x2,#1
cmp x2,#SIZE
blt 1b
b 100f
6:
mov x0,#2 // total = 2048
100:
ldp x10,x11,[sp],16 // restaur des 2 registres
ldp x8,x9,[sp],16 // restaur des 2 registres
ldp x6,x7,[sp],16 // restaur des 2 registres
ldp x4,x5,[sp],16 // restaur des 2 registres
ldp x2,x3,[sp],16 // restaur des 2 registres
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
/******************************************************************/
/* move right */
/******************************************************************/
/* x0 return -1 if ok */
moveRight:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
stp x4,x5,[sp,-16]! // save registres
stp x6,x7,[sp,-16]! // save registres
stp x8,x9,[sp,-16]! // save registres
stp x10,x11,[sp,-16]! // save registres
ldr x1,qAdrqTbCase
mov x0,#0
mov x2,#0
1:
mov x6,#0
mov x7,#0
mov x10,#0
mov x3,#SIZE-1
2:
lsl x5,x2,#2 // change this if size <> 4
add x5,x5,x3
ldr x4,[x1,x5,lsl #3]
cmp x4,#0
cinc x6,x6,eq // positions vides
beq 5f
 
cmp x6,#0
beq 3f // no empty right case
mov x0,#0
str x0,[x1,x5,lsl #3] // raz digit
add x5,x5,x6
str x4,[x1,x5,lsl #3] // and store to right empty position
mov x0,#1
3:
cmp x7,#0 // first digit
beq 4f
add x8,x5,#1 // next digit
ldr x9,[x1,x8,lsl #3]
cmp x4,x9 // equal ?
bne 4f
cmp x10,x4
beq 4f
mov x10,x4
add x4,x4,x9 // yes -> add
str x4,[x1,x8,lsl #3]
cmp x4,#TOTAL
beq 6f
mov x4,#0
str x4,[x1,x5,lsl #3]
add x6,x6,#1 // empty case + 1
mov x0,#1
4:
add x7,x7,#1 // no first digit
 
5: // and loop
sub x3,x3,#1
cmp x3,#0
bge 2b
add x2,x2,#1
cmp x2,#SIZE
blt 1b
b 100f
6:
mov x0,#2
100:
ldp x10,x11,[sp],16 // restaur des 2 registres
ldp x8,x9,[sp],16 // restaur des 2 registres
ldp x6,x7,[sp],16 // restaur des 2 registres
ldp x4,x5,[sp],16 // restaur des 2 registres
ldp x2,x3,[sp],16 // restaur des 2 registres
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
/******************************************************************/
/* move down */
/******************************************************************/
/* x0 return -1 if ok */
moveDown:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
stp x4,x5,[sp,-16]! // save registres
stp x6,x7,[sp,-16]! // save registres
stp x8,x9,[sp,-16]! // save registres
stp x10,x11,[sp,-16]! // save registres
ldr x1,qAdrqTbCase
mov x0,#0
mov x3,#0
1:
mov x6,#0
mov x7,#0
mov x10,#0
mov x2,#SIZE-1
2:
lsl x5,x2,#2 // change this if size <> 4
add x5,x5,x3
ldr x4,[x1,x5,lsl #3]
cmp x4,#0
cinc x6,x6,eq // positions vides
beq 5f
cmp x6,#0
beq 3f // no empty right case
mov x0,#0
str x0,[x1,x5,lsl #3] // raz digit
lsl x0,x6,#2
add x5,x5,x0
str x4,[x1,x5,lsl #3] // and store to right empty position
mov x0,#1
3:
cmp x7,#0 // first digit
beq 4f
add x8,x5,#SIZE // down digit
ldr x9,[x1,x8,lsl #3]
cmp x4,x9 // equal ?
bne 4f
cmp x10,x4
beq 4f
mov x10,x4
add x4,x4,x9 // yes -> add
str x4,[x1,x8,lsl #3]
cmp x4,#TOTAL
beq 6f
mov x4,#0
str x4,[x1,x5,lsl #3]
add x6,x6,#1 // empty case + 1
mov x0,#1
4:
add x7,x7,#1 // no first digit
 
5: // and loop
sub x2,x2,#1
cmp x2,#0
bge 2b
add x3,x3,#1
cmp x3,#SIZE
blt 1b
b 100f
6:
mov x0,#2
100:
ldp x10,x11,[sp],16 // restaur des 2 registres
ldp x8,x9,[sp],16 // restaur des 2 registres
ldp x6,x7,[sp],16 // restaur des 2 registres
ldp x4,x5,[sp],16 // restaur des 2 registres
ldp x2,x3,[sp],16 // restaur des 2 registres
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
/******************************************************************/
/* move up */
/******************************************************************/
/* x0 return -1 if ok */
moveUp:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
stp x4,x5,[sp,-16]! // save registres
stp x6,x7,[sp,-16]! // save registres
stp x8,x9,[sp,-16]! // save registres
stp x10,x11,[sp,-16]! // save registres
ldr x1,qAdrqTbCase
mov x0,#0
mov x3,#0
1:
mov x6,#0
mov x7,#0
mov x10,#0
mov x2,#0
2:
lsl x5,x2,#2 // change this if size <> 4
add x5,x5,x3
ldr x4,[x1,x5,lsl #3]
cmp x4,#0
cinc x6,x6,eq // positions vides
beq 5f
cmp x6,#0
beq 3f // no empty right case
mov x0,#0
str x0,[x1,x5,lsl #3] // raz digit
lsl x0,x6,#2
sub x5,x5,x0
str x4,[x1,x5,lsl #3] // and store to right empty position
mov x0,#1
3:
cmp x7,#0 // first digit
beq 4f
sub x8,x5,#SIZE // up digit
ldr x9,[x1,x8,lsl #3]
cmp x4,x9 // equal ?
bne 4f
cmp x10,x4
beq 4f
mov x10,x4
add x4,x4,x9 // yes -> add
str x4,[x1,x8,lsl #3]
cmp x4,#TOTAL
beq 6f
mov x4,#0
str x4,[x1,x5,lsl #3]
add x6,x6,#1 // empty case + 1
mov x0,#1
4:
add x7,x7,#1 // no first digit
 
5: // and loop
add x2,x2,#1
cmp x2,#SIZE
blt 2b
add x3,x3,#1
cmp x3,#SIZE
blt 1b
b 100f
6:
mov x0,#2
100:
ldp x10,x11,[sp],16 // restaur des 2 registres
ldp x8,x9,[sp],16 // restaur des 2 registres
ldp x6,x7,[sp],16 // restaur des 2 registres
ldp x4,x5,[sp],16 // restaur des 2 registres
ldp x2,x3,[sp],16 // restaur des 2 registres
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
/******************************************************************/
/* add new digit on game */
/******************************************************************/
/* x0 return -1 if ok */
addDigit:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
stp x4,x5,[sp,-16]! // save registres
sub sp,sp,#8 * SIZE*SIZE
mov fp,sp
mov x0,#100
bl genereraleas
cmp x0,#10
mov x1,#4
mov x5,#2
csel x5,x5,x1,ge
// movlt x5,#4
//movge x5,#2
ldr x1,qAdrqTbCase
mov x3,#0
mov x4,#0
1:
ldr x2,[x1,x3,lsl 3]
cmp x2,#0
bne 2f
str x3,[fp,x4,lsl 3]
add x4,x4,#1
2:
add x3,x3,#1
cmp x3,#SIZE*SIZE
blt 1b
cmp x4,#0 // no empty case
beq 4f
cmp x4,#1
bne 3f
ldr x2,[fp] // one case
str x5,[x1,x2,lsl 3]
mov x0,#0
b 100f
3: // multiple case
sub x0,x4,#1
bl genereraleas
ldr x2,[fp,x0,lsl 3]
str x5,[x1,x2,lsl 3]
mov x0,#0
b 100f
4:
mov x0,#-1
100:
add sp,sp,#8* (SIZE*SIZE) // stack alignement
ldp x4,x5,[sp],16 // restaur des 2 registres
ldp x2,x3,[sp],16 // restaur des 2 registres
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
qAdrqTbCase: .quad qTbCase
/******************************************************************/
/* display game */
/******************************************************************/
displayGame:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
ldr x0,qAdrszCleax1
bl affichageMess
ldr x0,qAdrszLineH
bl affichageMess
ldr x0,qAdrszLineVT
bl affichageMess
ldr x0,qAdrszLineV
bl affichageMess
ldr x1,qAdrqTbCase
mov x2,#0
1:
ldr x0,[x1,x2,lsl #3]
bl digitString
bl affichageMess
ldr x0,qAdrszLineV
bl affichageMess
add x2,x2,#1
cmp x2,#SIZE
blt 1b
ldr x0,qAdrszCarriageReturn
bl affichageMess
ldr x0,qAdrszLineVT
bl affichageMess
ldr x0,qAdrszLineH
bl affichageMess
ldr x0,qAdrszLineVT
bl affichageMess
ldr x0,qAdrszLineV
bl affichageMess
2:
ldr x0,[x1,x2,lsl #3]
bl digitString
bl affichageMess
ldr x0,qAdrszLineV
bl affichageMess
add x2,x2,#1
cmp x2,#SIZE*2
blt 2b
ldr x0,qAdrszCarriageReturn
bl affichageMess
ldr x0,qAdrszLineVT
bl affichageMess
ldr x0,qAdrszLineH
bl affichageMess
ldr x0,qAdrszLineVT
bl affichageMess
ldr x0,qAdrszLineV
bl affichageMess
3:
ldr x0,[x1,x2,lsl #3]
bl digitString
bl affichageMess
ldr x0,qAdrszLineV
bl affichageMess
add x2,x2,#1
cmp x2,#SIZE*3
blt 3b
ldr x0,qAdrszCarriageReturn
bl affichageMess
ldr x0,qAdrszLineVT
bl affichageMess
ldr x0,qAdrszLineH
bl affichageMess
ldr x0,qAdrszLineVT
bl affichageMess
ldr x0,qAdrszLineV
bl affichageMess
4:
ldr x0,[x1,x2,lsl #3]
bl digitString
bl affichageMess
ldr x0,qAdrszLineV
bl affichageMess
add x2,x2,#1
cmp x2,#SIZE*4
blt 4b
ldr x0,qAdrszCarriageReturn
bl affichageMess
ldr x0,qAdrszLineVT
bl affichageMess
ldr x0,qAdrszLineH
bl affichageMess
 
100:
ldp x2,x3,[sp],16 // restaur des 2 registres
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
qAdrszLineH: .quad szLineH
qAdrszLineV: .quad szLineV
qAdrszLineVT: .quad szLineVT
/******************************************************************/
/* digits string */
/******************************************************************/
/* x0 contains number */
/* x0 return address string */
digitString:
stp x1,lr,[sp,-16]! // save registres
cmp x0,#0
bne 1f
ldr x0,qAdrszMess0
b 100f
1:
cmp x0,#2
bne 2f
ldr x0,qAdrszMess2
b 100f
2:
cmp x0,#4
bne 3f
ldr x0,qAdrszMess4
b 100f
3:
cmp x0,#8
bne 4f
ldr x0,qAdrszMess8
b 100f
4:
cmp x0,#16
bne 5f
ldr x0,qAdrszMess16
b 100f
5:
cmp x0,#32
bne 6f
ldr x0,qAdrszMess32
b 100f
6:
cmp x0,#64
bne 7f
ldr x0,qAdrszMess64
b 100f
7:
cmp x0,#128
bne 8f
ldr x0,qAdrszMess128
b 100f
8:
cmp x0,#256
bne 9f
ldr x0,qAdrszMess256
b 100f
9:
cmp x0,#512
bne 10f
ldr x0,qAdrszMess512
b 100f
10:
cmp x0,#1024
bne 11f
ldr x0,qAdrszMess1024
b 100f
11:
cmp x0,#2048
bne 12f
ldr x0,qAdrszMess2048
b 100f
12:
ldr x1,qAdrszMessErreur // error message
bl displayError
100:
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
qAdrszMess0: .quad szMess0
qAdrszMess2: .quad szMess2
qAdrszMess4: .quad szMess4
qAdrszMess8: .quad szMess8
qAdrszMess16: .quad szMess16
qAdrszMess32: .quad szMess32
qAdrszMess64: .quad szMess64
qAdrszMess128: .quad szMess128
qAdrszMess256: .quad szMess256
qAdrszMess512: .quad szMess512
qAdrszMess1024: .quad szMess1024
qAdrszMess2048: .quad szMess2048
 
//qAdrsBuffer: .quad sBuffer
qAdrszMessErreur : .quad szMessErreur
 
/***************************************************/
/* Generation random number */
/***************************************************/
/* x0 contains limit */
genereraleas:
stp x1,lr,[sp,-16]! // save registers
stp x2,x3,[sp,-16]! // save registers
ldr x1,qAdrqGraine
ldr x2,[x1]
ldr x3,qNbDep1
mul x2,x3,x2
ldr x3,qNbDep2
add x2,x2,x3
str x2,[x1] // maj de la graine pour l appel suivant
cmp x0,#0
beq 100f
udiv x3,x2,x0
msub x0,x3,x0,x2 // résult = remainder
100: // end function
ldp x2,x3,[sp],16 // restaur 2 registers
ldp x1,lr,[sp],16 // restaur 2 registers
ret // return to address lr x30
/*****************************************************/
qAdrqGraine: .quad qGraine
qNbDep1: .quad 0x0019660d
qNbDep2: .quad 0x3c6ef35f
/******************************************************************/
/* traitement du signal */
/******************************************************************/
sighandler:
stp x0,lr,[sp,-16]! // save registers
str x1,[sp,-16]!
ldr x0,qAdrqEnd
mov x1,#1 // maj zone end
str x1,[x0]
ldr x1,[sp],16
ldp x0,lr,[sp],16 // restaur 2 registers
ret // return to address lr x30
/***************************************************/
/* display error message */
/***************************************************/
/* x0 contains error code x1 : message address */
displayError:
stp x2,lr,[sp,-16]! // save registers
mov x2,x0 // save error code
mov x0,x1
bl affichageMess
mov x0,x2 // error code
ldr x1,qAdrsZoneConv
bl conversion16 // conversion hexa
ldr x0,qAdrszMessErr // display error message
ldr x1,qAdrsZoneConv
bl strInsertAtCharInc // insert result at @ character
mov x3,x0
mov x0,x2 // error code
ldr x1,qAdrsZoneConv // result address
bl conversion10S // conversion decimale
mov x0,x3
ldr x1,qAdrsZoneConv
bl strInsertAtCharInc // insert result at @ character
bl affichageMess
100:
ldp x2,lr,[sp],16 // restaur 2 registers
ret // return to address lr x30
qAdrszMessErr: .quad szMessErr
/*********************************/
/* init terminal state */
/*********************************/
initTerm:
stp x1,lr,[sp,-16]! // save registers
/* read terminal state */
mov x0,STDIN // input console
mov x1,TCGETS
ldr x2,qAdrstOldtio
mov x8,IOCTL // call system Linux
svc 0
cbnz x0,98f // error ?
adr x0,sighandler // adresse routine traitement signal
ldr x1,qAdrstSigAction // adresse structure sigaction
str x0,[x1,sa_handler] // maj handler
mov x0,SIGINT // signal type
ldr x1,qAdrstSigAction
mov x2,0
mov x3,8
mov x8,SIGACTION // call system
svc 0
cmp x0,0 // error ?
bne 98f
mov x0,SIGQUIT
ldr x1,qAdrstSigAction
mov x2,0 // NULL
mov x8,SIGACTION // call system
svc 0
cmp x0,0 // error ?
bne 98f
mov x0,SIGTERM
ldr x1,qAdrstSigAction
mov x2,0 // NULL
mov x8,SIGACTION // appel systeme
svc 0
cmp x0,0
bne 98f
//
adr x0,qAdrSIG_IGN // address signal igonre function
ldr x1,qAdrstSigAction1
str x0,[x1,sa_handler]
mov x0,SIGTTOU //invalidate other process signal
ldr x1,qAdrstSigAction1
mov x2,0 // NULL
mov x8,SIGACTION // call system
svc 0
cmp x0,0
bne 98f
//
/* read terminal current state */
mov x0,STDIN
mov x1,TCGETS
ldr x2,qAdrstCurtio // address current termio
mov x8,IOCTL // call systeme
svc 0
cmp x0,0 // error ?
bne 98f
mov x2,ICANON | ECHO // no key pressed echo on display
mvn x2,x2 // and one key
ldr x1,qAdrstCurtio
ldr x3,[x1,#term_c_lflag]
and x3,x2,x2 // add flags
str x3,[x1,#term_c_lflag] // and store
mov x0,STDIN // maj terminal current state
mov x1,TCSETS
ldr x2,qAdrstCurtio
mov x8,IOCTL // call system
svc 0
cbz x0,100f
98: // error display
ldr x1,qAdrszMessErrInitTerm
bl displayError
mov x0,-1
100:
ldp x1,lr,[sp],16 // restaur 2 registers
ret // return to address lr x30
qAdrstSigAction2: .quad stSigAction2
qAdrstSigAction3: .quad stSigAction3
/*********************************/
/* init instance epool */
/*********************************/
initPoll:
stp x1,lr,[sp,-16]! // save registers
ldr x0,qAdrstevents
mov x1,STDIN // maj structure events
str x1,[x0,#poll_fd] // maj FD
mov x1,POLLIN // action code
str x1,[x0,#poll_event]
mov x0,0
mov x8,CREATPOLL // create epoll instance
svc 0
cmp x0,0 // error ?
ble 98f
mov x10,x0 // return FD epoll instance
mov x1,EPOLL_CTL_ADD
mov x2,STDIN // Fd to we want add
ldr x3,qAdrstevents // structure events address
mov x8,CTLPOLL // call system control epoll
svc 0
cmp x0,0 // error ?
blt 98f // no
mov x0,x10 // return FD epoll instance
b 100f
98: // error display
ldr x1,qAdrszMessErrInitPoll // error message
bl displayError
mov x0,-1
100:
ldp x1,lr,[sp],16 // restaur 2 registers
ret // return to address lr x30
/*********************************/
/* wait key */
/*********************************/
/* x0 contains FD poll */
waitKey:
stp x1,lr,[sp,-16]! // save registers
ldr x11,qAdrqTouche // key address
str xzr,[x11] // raz key
1:
ldr x1,qAdrqEnd // if signal ctrl-c -> end
ldr x1,[x1]
cbnz x1,100f
ldr x1,qAdrstevents
mov x2,12 // size events
mov x3,1 // timeout = 1 TODO: ??
mov x4,0
mov x8,SYSPOLL // call system wait POLL
svc 0
cmp x0,0 // key pressed ?
bge 100f
98: // error display
ldr x1,qAdrszMessErreurKey // error message
bl displayError
mov x0,-1
100:
ldp x1,lr,[sp],16 // restaur 2 registers
ret // return to address lr x30
/*********************************/
/* read key */
/*********************************/
/* x0 returns key value */
readKey:
stp x1,lr,[sp,-16]! // save registers
mov x0,STDIN // File Descriptor
ldr x1,qAdrqTouche // buffer address
mov x2,KEYSIZE // key size
mov x8,READ // read key
svc #0
cmp x0,0 // error ?
ble 98f
ldr x2,qAdrqTouche // key address
ldr x0,[x2]
b 100f
98: // error display
ldr x1,qAdrszMessErreur // error message
bl displayError
mov x0,-1
100:
ldp x1,lr,[sp],16 // restaur 2 registers
ret // return to address lr x30
/*********************************/
/* restaur terminal state */
/*********************************/
restauTerm:
stp x1,lr,[sp,-16]! // save registers
mov x0,STDIN // end then restaur begin state terminal
mov x1,TCSETS
ldr x2,qAdrstOldtio
mov x8,IOCTL // call system
svc 0
cbz x0,100f
ldr x1,qAdrszMessErreur // error message
bl displayError
100:
ldp x1,lr,[sp],16 // restaur 2 registers
ret // return to address lr x30
/********************************************************/
/* File Include fonctions */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"
</syntaxhighlight>
=={{header|Ada}}==
{{works with|GNAT}}
<langsyntaxhighlight Adalang="ada">with Ada.Text_IO; use Ada.Text_IO;
with System.Random_Numbers;
procedure Play_2048 is
Line 80 ⟶ 1,146:
when others => Invalid),
when others => Invalid);
 
-- ----- Game data
function Random_Int is new System.Random_Numbers.Random_Discrete(Integer);
Line 91 ⟶ 1,157:
Score : Natural;
Generator : System.Random_Numbers.Generator;
 
-- ----- Displaying the board
procedure Display_Board is
Line 110 ⟶ 1,176:
Put_Line("Score =" & Score'Img);
end Display_Board;
 
-- ----- Game mechanics
procedure Add_Block is
Line 129 ⟶ 1,195:
end loop;
end Add_Block;
 
procedure Reset_Game is
begin
Line 138 ⟶ 1,204:
Add_Block;
end Reset_Game;
 
-- Moving and merging will always be performed leftward, hence the following transforms
function HFlip (What : in t_Row) return t_Row is
Line 154 ⟶ 1,220:
end return;
end Transpose;
 
-- For moving/merging, recursive expression functions will be used, but they
-- can't contain statements, hence the following sub-function used by Merge
Line 163 ⟶ 1,229:
return (1 => 0);
end Add_Blank;
 
function Move_Row (What : in t_List) return t_List is
(if What'Length = 1 then What
Line 169 ⟶ 1,235:
then Move_Row(What(What'First+1..What'Last)) & (1 => 0)
else (1 => What(What'First)) & Move_Row(What(What'First+1..What'Last)));
 
function Merge (What : in t_List) return t_List is
(if What'Length <= 1 or else What(What'First) = 0 then What
Line 175 ⟶ 1,241:
then (1 => 2*What(What'First)) & Merge(What(What'First+2..What'Last)) & Add_Blank(What(What'First))
else (1 => What(What'First)) & Merge(What(What'First+1..What'Last)));
 
function Move (What : in t_Board) return t_Board is
(Merge(Move_Row(What(1))),Merge(Move_Row(What(2))),Merge(Move_Row(What(3))),Merge(Move_Row(What(4))));
 
begin
System.Random_Numbers.Reset(Generator);
Reset_Game;
Main_Game_LoopMain_Loop: loop
Display_BoardReset_Game;
Game_Loop: loop
case Get_Keystroke is
when Restart => Reset_Game;
when Quit => exit Main_Game_Loop;
when Left => New_Board := Move(Board);
when Right => New_Board := VFlip(Move(VFlip(Board)));
when Up => New_Board := Transpose(Move(Transpose(Board)));
when Down => New_Board := Transpose(VFlip(Move(VFlip(Transpose(Board)))));
when others => null;
end case;
 
if New_Board = Board then
Put_Line ("Invalid move...");
elsif (for some Row of New_Board => (for some Cell of Row => Cell = 2048)) then
Display_Board;
Put_Linecase ("WinGet_Keystroke !");is
when Restart => exit Main_Game_LoopGame_Loop;
when Quit => exit Main_Loop;
else
Board : when Left => New_Board := Move(Board);
when Right => New_Board := VFlip(Move(VFlip(Board)));
Add_Block; -- OK since the board has changed
when Up => New_Board := Transpose(Move(Transpose(Board)));
if Blanks = 0
andwhen thenDown (for all Row in=> 1..4New_Board :=> Transpose(VFlip(Move(VFlip(Transpose(Board)))));
when others (for all Column in 1..3 => null;
end case;
(Board(Row)(Column) /= Board(Row)(Column+1))))
and then (for all Row in 1..3 =>
if New_Board = Board then
(for all Column in 1..4 =>
Put_Line ("Invalid move...");
(Board(Row)(Column) /= Board(Row+1)(Column)))) then
elsif (for some Row of New_Board => (for some Cell of Row => Cell = 2048)) then
Display_Board;
Put_Line ("LostWin !");
exit Main_Game_LoopMain_Loop;
else
Board := New_Board;
Add_Block; -- OK since the board has changed
if Blanks = 0
and then (for all Row in 1..4 =>
(for all Column in 1..3 =>
(Board(Row)(Column) /= Board(Row)(Column+1))))
and then (for all Row in 1..3 =>
(for all Column in 1..4 =>
(Board(Row)(Column) /= Board(Row+1)(Column)))) then
Display_Board;
Put_Line ("Lost !");
exit Main_Loop;
end if;
end if;
end ifloop Game_Loop;
end loop Main_Game_LoopMain_Loop;
end Play_2048;</lang>
</syntaxhighlight>
{{out}}
<pre>+----+----+----+----+
Line 230 ⟶ 1,300:
 
=={{header|ALGOL 68}}==
<langsyntaxhighlight lang="algol68">
main:(
INT side = 4;
Line 373 ⟶ 1,443:
lose: print(("you lose!", new line))
)
</syntaxhighlight>
</lang>
=={{header|Amazing Hopper}}==
<pre>
VERSION 1: "Hopper" flavour.
</pre>
<syntaxhighlight lang="amazing hopper">
#context-free select Position of aleatory tail
#context-free show Table
#context-free chek Winner or Game Over
#context-free print Table structure
#proto MovingRightDown(_X_)
#proto MovingLeftUp(_X_)
#proto checkPointLeftUp(_X_)
#proto checkPointRightDown(_X_)
#proto checkMoveRightDown(_X_)
#proto checkMoveLeftUp(_X_)
#define KUP 5
#define KDOWN 24
#define KLEFT 19
#define KRIGHT 4
#define KESCAPE 27
#define MOVEHORZ 1
#define MOVEVERT 0
#define equaltables(_X_,_Y_) _I_=1,\
__LOOP_ROW__:,\
_J_=1,\
__LOOP_COL__:,\
[_I_,_J_]get(_X_),get(_Y_),neq? do{{0},jmp(__OUT__LOOP__)},\
++_J_,{4,_J_}jle(__LOOP_COL__),\
++_I_,{4,_I_}jle(__LOOP_ROW__),\
{1},__OUT__LOOP__:,clear mark
#include <hopper.h>
 
main:
.ctrl c
contador de movimientos=0
score=0
table=0,{4,4}zeros array(table) // create table
oldTable=0, show Structure=1
/* define initial positions */
{""}tok sep
select Position of aleatory tail
select Position of aleatory tail
home
hide cursor
show Table
c=0, go=1,swFin=1
 
/* game! */
__PLAY_GAME__:
if key pressed?
lastkey(c)
oldTable = table
switch(c)
case(KRIGHT) :: do{ _check Move Right Down(MOVEHORZ), exit }
case(KDOWN) :: do{ _check Move Right Down(MOVEVERT), exit }
case(KLEFT) :: do{ _check Move Left Up(MOVEHORZ), exit }
case(KUP) :: do{ _check Move Left Up(MOVEVERT), exit }
case(KESCAPE):: do{ go=0,swFin=0 }
end switch
kbfree
chek Winner or Game Over
{go}do{
if ( not( equal tables(oldTable, table) ) )
select Position of aleatory tail
++contador de movimientos
end if
show Table
}
end if
{go},jt(__PLAY_GAME__)
 
if ( {swFin} )
{" \LG","YOU WIN!!!\OFF"}
else
{" \LR","GAME OVER\OFF"}
end if
println
show cursor
exit(0)
 
.locals
Moving Right Down(tmpTab)
{tmpTab} compact,ht=0,cpy(ht), length,{4}sub,sizet=0,mov(sizet)
clear(tmpTab),{sizet}zerosarray(tmpTab)
{ht,tmpTab}array(CONCAT)
{tmpTab}
back
Moving Left Up(tmpTab)
{tmpTab} compact,clear(tmpTab),cpy(tmpTab), length,{4}sub,sizet=0,mov(sizet)
{sizet}zero?,not,do{ ht=0,{sizet}zerosarray(ht)
{ht,tmpTab}array(CONCAT) }
{tmpTab}
back
check Point Right Down(tmpTab)
v1=0,v2=0,tScore=0,totScore=0
for(k=4,{k}gthan(1),--k)
[k]get(tmpTab),mov(v1)
[{k}minus(1)]get(tmpTab),mov(v2)
if( {v1} eqto (v2) )
{v1,v2}add,cpy(tScore),[k]put(tmpTab),[{k}minus(1)]{0}put(tmpTab)
{tScore}plus(totScore),mov(totScore)
end if
next
{tmpTab,totScore}
back
check Move Right Down (_DIRECTION_)
tmpTab=0
for(i=1,{i}lethan(4),++i)
if ( {_DIRECTION_} ) // rows or cols??
[i,1:4] // rows!
else
[1:4,i] // cols!
end if
get(table), mov(tmpTab)
if( {tmpTab}stats(SUMMATORY) ) // exist numbers in the row??
clear mark
_Moving Right Down(tmpTab),mov(tmpTab) // move its!
clear mark
_check Point Right Down(tmpTab),plus(score),mov(score) // check score...
mov(tmpTab)
_Moving Right Down(tmpTab),mov(tmpTab) // move remanents!
if( {_DIRECTION_} )
[i,1:4]
else
[1:4,i]
end if
{tmpTab}, put(table)
end if
next
clear mark.
back
 
check Point Left Up(tmpTab)
v1=0,v2=0,tScore=0,totScore=0
for(k=1,{k}lthan(4),++k)
[k]get(tmpTab),mov(v1)
[{k}plus(1)]get(tmpTab),mov(v2)
if( {v1} eqto (v2) )
{v1,v2}add,cpy(tScore),[k]put(tmpTab),[{k}plus(1)]{0}put(tmpTab)
{tScore}plus(totScore),mov(totScore)
end if
next
{tmpTab,totScore}
back
 
check Move Left Up(_DIRECTION_)
tmpTab=0
for(i=1,{i}lethan(4),++i)
if( {_DIRECTION_} )
[i,1:4]
else
[1:4,i]
end if
get(table),mov(tmpTab)
if( {tmpTab}stats(SUMMATORY) ) // exist numbers in the row??
clear mark
_Moving Left Up(tmpTab),mov(tmpTab) // move its!
clear mark
_check Point Left Up(tmpTab),plus(score),mov(score) // check score...
mov(tmpTab)
_Moving Left Up(tmpTab),mov(tmpTab) // move remanents!
if( {_DIRECTION_} )
[i,1:4]
else
[1:4,i]
end if
{tmpTab},put(table)
end if
next
clear mark.
back
 
chek Winner or Game Over:
{table}gthan(0),xtonum,stats(SUMMATORY),{16} eq? do{{0}mov(go),{0}mov(swFin),back} // You loose!
{0}reshape(table),{2048,table}array(SCAN){0} neq? do{{0}mov(go),back} // you Win!
{4,4}reshape(table)
back
 
select Position of aleatory tail:
prec(-1)
__NO_VALID_POS__:
{10}rand, mulby(10),ceil,module(5),x=0,cpy(x),zero?,do{x=1}
{10}rand, mulby(10),ceil,module(5),y=0,cpy(y),zero?,do{y=1}
[x,y]get(table),jnz(__NO_VALID_POS__)
newTail=2
{1}rand,gthan(0.9), do{ newTail=4 }
{newTail},put(table), clear mark.
prec(0)
back
 
show Table:
tmpTable=0
{" ",6,table}xtostr,padcenter,mov(tmpTable)
// prepare colours of tiles
{"\BGLGR\BK \OFF"," 0 ",tmpTable} transform, mov(tmpTable)
{"\BGLGR\BK 2 \OFF"," 2 ",tmpTable} transform, mov(tmpTable)
{"\BGLGR\B 4 \OFF"," 4 ",tmpTable} transform, mov(tmpTable)
{"\BGLGR\B 8 \OFF"," 8 ",tmpTable} transform, mov(tmpTable)
{"\BGR\W 16 \OFF"," 16 ",tmpTable} transform, mov(tmpTable)
{"\BGY\BK 32 \OFF"," 32 ",tmpTable} transform, mov(tmpTable)
{"\BGB\W 64 \OFF"," 64 ",tmpTable} transform, mov(tmpTable)
{"\BGLM\BK 128 \OFF"," 128 ",tmpTable} transform, mov(tmpTable)
{"\BGG\W 256 \OFF"," 256 ",tmpTable} transform, mov(tmpTable)
{"\BGB\W 512 \OFF"," 512 ",tmpTable} transform, mov(tmpTable)
{"\BGR\W 1024 \OFF"," 1024 ",tmpTable} transform, mov(tmpTable)
{"\BGBK\W\ENF 2048 \OFF"," 2048 ",tmpTable} transform, mov(tmpTable)
 
// and PRINT!!
{show Structure} do{ print Table structure,{0} mov(show Structure) }
 
clear mark
scrx=2
for (i=1, {i}lethan(4),++i)
{2,scrx}goxy,[1,i]get(tmpTable),print
{4,scrx}goxy,[2,i]get(tmpTable),print
{6,scrx}goxy,[3,i]get(tmpTable),print
{8,scrx}goxy,[4,i]get(tmpTable),print
clear mark
scrx += 7
next
 
{"\BGB\W\ENF","\n\n\t 2 0 4 8 \OFF\n\n"}
{"Movimiento # ",contador de movimientos,", \INVSCORE=",score,"\OFF\n"}//,tmpTable}
println
 
back
 
print Table structure:
{"┌──────┬──────┬──────┬──────┐\n"},strtoutf8,
{"│ 2048 │ 2048 │ 2048 │ 2048 │\n"},strtoutf8,
{"├──────┼──────┼──────┼──────┤\n"},strtoutf8,
{"│ 2048 │ 2048 │ 2048 │ 2048 │\n"},strtoutf8,
{"├──────┼──────┼──────┼──────┤\n"},strtoutf8,
{"│ 2048 │ 2048 │ 2048 │ 2048 │\n"},strtoutf8,
{"├──────┼──────┼──────┼──────┤\n"},strtoutf8,
{"│ 2048 │ 2048 │ 2048 │ 2048 │\n"},strtoutf8,
{"└──────┴──────┴──────┴──────┘"},strtoutf8,
println
back
</syntaxhighlight>
{{out}}
<pre>
Begin play...
┌──────┬──────┬──────┬──────┐
│ │ │ 2 │ │
├──────┼──────┼──────┼──────┤
│ │ │ │ │
├──────┼──────┼──────┼──────┤
│ │ │ │ │
├──────┼──────┼──────┼──────┤
│ 2 │ │ │ │
└──────┴──────┴──────┴──────┘
2 0 4 8
 
Movimiento # 0, SCORE=0
 
</pre>
<pre>
Playing...
┌──────┬──────┬──────┬──────┐
│ │ 2 │ │ │
├──────┼──────┼──────┼──────┤
│ │ │ 2 │ 4 │
├──────┼──────┼──────┼──────┤
│ │ 2 │ 32 │ 128 │
├──────┼──────┼──────┼──────┤
│ │ 8 │ 4 │ 16 │
└──────┴──────┴──────┴──────┘
2 0 4 8
 
Movimiento # 90, SCORE=940
</pre>
<pre>
Game Over...
┌──────┬──────┬──────┬──────┐
│ 2 │ 16 │ 2 │ 4 │
├──────┼──────┼──────┼──────┤
│ 4 │ 128 │ 4 │ 8 │
├──────┼──────┼──────┼──────┤
│ 16 │ 8 │ 512 │ 4 │
├──────┼──────┼──────┼──────┤
│ 2 │ 4 │ 32 │ 2 │
└──────┴──────┴──────┴──────┘
2 0 4 8
 
Movimiento # 347, SCORE=5040
 
GAME OVER
$
</pre>
 
<pre>
VERSION 2: "Hopper-BASIC" flavour.
</pre>
<syntaxhighlight lang="amazing hopper">
 
// Definicion de "contextos"
#context-free select Position of aleatory tail
set Decimal (-1)
tSIZE=0,
Let( tSIZE := var(SIZE) Plus (1) )
__NO_VALID_POS__:
x=0, y=0
When( Is Zero? ( Ceil( Rand(10) Mul by(10) ) Module (tSIZE) » (x) )){ x = 1 }
When( Is Zero? ( Ceil( Rand(10) Mul by(10) ) Module (tSIZE) » (y) )){ y = 1 }
At Interval [x,y], Get (table), Goto If Not Zero(__NO_VALID_POS__)
newTail=2
When ( Rand(1) Is Gt (0.9) ) { newTail=4 }
Take( newTail ), and SPut(table).
set Decimal(0)
Return\\
 
#context-free check Winner or Game Over
When ( Summatory ( Val( var(table) Is Gt (0) ) ), Is Eq? ( var(SIZE) Mulby(SIZE) ) ) {
MStore( 0, go, swFin ), and Back // You loose!
}
ReDim( table, 0 ) // convierte en vector
When( Scan(1, 2048, table ) Is Not Eq? (0) ){
ReDim( table, SIZE, SIZE ), Let ( go:=0 ) and Back // You Win!
}
ReDim( table, SIZE, SIZE )
Return\\
 
#context-free show Table
tmpTable=0
Let ( tmpTable := CPad$(" ", 6, Str$(table)) )
Let ( tmpTable := Tran$("\BGLGR\BK \OFF"," 0 ", tmpTable) )
Let ( tmpTable := Tran$("\BGLGR\BK 2 \OFF"," 2 ", tmpTable) )
Let ( tmpTable := Tran$("\BGLGR\B 4 \OFF"," 4 ", tmpTable) )
Let ( tmpTable := Tran$("\BGLGR\B 8 \OFF"," 8 ", tmpTable) )
Let ( tmpTable := Tran$("\BGR\W 16 \OFF"," 16 ", tmpTable) )
Let ( tmpTable := Tran$("\BGY\BK 32 \OFF"," 32 ", tmpTable) )
Let ( tmpTable := Tran$("\BGB\W 64 \OFF"," 64 ", tmpTable) )
Let ( tmpTable := Tran$("\BGLM\BK 128 \OFF"," 128 ", tmpTable) )
Let ( tmpTable := Tran$("\BGG\W 256 \OFF"," 256 ", tmpTable) )
Let ( tmpTable := Tran$("\BGB\W 512 \OFF"," 512 ", tmpTable) )
Let ( tmpTable := Tran$("\BGR\W 1024 \OFF"," 1024 ", tmpTable) )
Let ( tmpTable := Tran$("\BGBK\W\ENF 2048 \OFF"," 2048 ", tmpTable) )
When( show Structure ) { print Table structure, and Let ( show Structure := 0 ) }
Clear Mark
scrx=2
For (i=1, var(i) Is Le (SIZE), ++i)
Locate in Column (scrx)
Locate in Row (2), At Interval [1,i], Print( Get (tmpTable) )
Locate in Row (4), At Interval [2,i], Print( Get (tmpTable) )
Locate in Row (6), At Interval [3,i], Print( Get (tmpTable) )
Locate in Row (8), At Interval [4,i], Print( Get (tmpTable) )
When( var(SIZE) Is Ge? (5) ) {Locate in Row (10), At Interval [5,i], Print( Get (tmpTable) )}
When( var(SIZE) Is Ge? (6) ) {Locate in Row (12), At Interval [6,i], Print( Get (tmpTable) )}
scrx += 7
Next
Clear Mark
Take( "\BGB\W\ENF","\n\n\t 2 0 4 8 \OFF\n\n",\
"Movimiento # ",contador de movimientos,", \INVSCORE=",score,"\OFF\n" )
and Print It
Return\\
 
#context-free print Table structure
Locate (1,1)
If ( var(SIZE) Is Eq? (4) )
Str2Utf8$("┌──────┬──────┬──────┬──────┐\n")
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │\n")
Str2Utf8$("├──────┼──────┼──────┼──────┤\n")
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │\n")
Str2Utf8$("├──────┼──────┼──────┼──────┤\n")
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │\n")
Str2Utf8$("├──────┼──────┼──────┼──────┤\n")
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │\n")
Str2Utf8$("└──────┴──────┴──────┴──────┘")
Else If( var(SIZE) Is Eq? (5) )
Str2Utf8$("┌──────┬──────┬──────┬──────┬──────┐\n")
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
Str2Utf8$("├──────┼──────┼──────┼──────┼──────┤\n")
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
Str2Utf8$("├──────┼──────┼──────┼──────┼──────┤\n")
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
Str2Utf8$("├──────┼──────┼──────┼──────┼──────┤\n")
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
Str2Utf8$("├──────┼──────┼──────┼──────┼──────┤\n")
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
Str2Utf8$("└──────┴──────┴──────┴──────┴──────┘")
Else If( var(SIZE) Is Eq? (6) )
Str2Utf8$("┌──────┬──────┬──────┬──────┬──────┬──────┐\n")
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
Str2Utf8$("├──────┼──────┼──────┼──────┼──────┼──────┤\n")
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
Str2Utf8$("├──────┼──────┼──────┼──────┼──────┼──────┤\n")
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
Str2Utf8$("├──────┼──────┼──────┼──────┼──────┼──────┤\n")
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
Str2Utf8$("├──────┼──────┼──────┼──────┼──────┼──────┤\n")
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
Str2Utf8$("├──────┼──────┼──────┼──────┼──────┼──────┤\n")
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
Str2Utf8$("└──────┴──────┴──────┴──────┴──────┴──────┘")
End If
now Print It
Return\\
 
// definicion de prototipos:
#proto MovingRightDown(_X_)
#proto MovingLeftUp(_X_)
#proto checkPointLeftUp(_X_)
#proto checkPointRightDown(_X_)
#proto checkMoveRightDown(_X_)
#proto checkMoveLeftUp(_X_)
 
// definiciones varias:
#define KUP 5
#define KDOWN 24
#define KLEFT 19
#define KRIGHT 4
#define KESCAPE 27
#define MOVEHORZ 1
#define MOVEVERT 0
 
// archivo de inclusión de macros H-BASIC:
#include <hbasic.h>
 
Begin
Option Ctrl+C
Option Stack 16
contador de movimientos=0
score=0, SIZE=4
When( ArgCount, Is Eq? (2) ){ get ArgNumber(2,SIZE) }
 
If ( var(SIZE) Is Not Between?(4,includ,6,includ) )
Print("Usage: hopper 2048.bas [4(default)-6]\n")
Stop
End If
Dim (SIZE,SIZE) for Zeros Array (table)
 
oldTable=0, show Structure=1
/* define initial positions */
Token Sep("")
select Position of aleatory tail
select Position of aleatory tail
Cls
Hide Cursor
show Table
c=0, go=1,swFin=1
 
/* game! */
While ( go )
Let ( c:=GetCh )
oldTable = table
Switch(c)
Case(KRIGHT) { _check Move Right Down(MOVEHORZ), Exit }
Case(KDOWN) { _check Move Right Down(MOVEVERT), Exit }
Case(KLEFT) { _check Move Left Up(MOVEHORZ), Exit }
Case(KUP) { _check Move Left Up(MOVEVERT), Exit }
Case(KESCAPE){ go=0, swFin=0 }
End Switch
 
check Winner or Game Over
When( go ){
If ( are Not EqArray? (oldTable, table) ) //( not( equal tables(oldTable, table) ) )
select Position of aleatory tail
++contador de movimientos
End If
show Table
}
Wend
 
If ( swFin )
show Table
Print(" \LG","YOU WIN!!!\OFF")
Else
Print(" \LR","GAME OVER\OFF")
End If
Put a Newl
Show Cursor
End
 
Subrutines
 
Moving Right Down(tmpTab)
ht=0, sizet=0
Let( sizet := var(SIZE) Minus ( Length( Compact(tmpTab), Copy to (ht) ) ) )
If ( Is Not Zero?(sizet) )
Clear(tmpTab)
Dim (sizet) for Zeros Array (tmpTab)
Concat( ht,tmpTab )
End If
Return (tmpTab)
 
Moving Left Up(tmpTab)
sizet=0
Compact( tmpTab ),Clear(tmpTab) and Copy to (tmpTab); get Length It, Subtracted from (SIZE); then Move to (sizet)
//When( Is Not Zero?(sizet) ){
When( var(sizet) Is Not Zero? ){
ht=0
Dim (sizet) for Zeros Array (ht)
Concat( ht, tmpTab )
}
Return (tmpTab)
 
check Point Right Down(tmpTab)
v1=0,v2=0,tScore=0,totScore=0
For(k=SIZE, var(k) Is Gt (1), --k)
Set Interval [k] and Get (tmpTab); then Move to (v1)
Set Interval [ var(k) Minus(1)], Get(tmpTab), and Move to (v2)
If( var(v1) Is Eq? (v2) )
Add(v1,v2), Copy to(tScore);
At Interval [k] Put(tmpTab)
At Interval [ var(k) Minus(1) ], now Take(0); then Put (tmpTab)
Let( totScore := var(tScore) Plus (totScore) )
End If
Next
Take(tmpTab,totScore) and Return
 
check Move Right Down (_DIRECTION_)
tmpTab=0
For(i=1, while var(i) Is Le (SIZE), ++i)
If ( _DIRECTION_ ) // rows or cols??
Set Interval [i,1:SIZE] // rows!
Else
Set Interval [1:SIZE,i] // cols!
End If
now Let( tmpTab := Get(table) )
If( Summatory ( tmpTab ) ) // exist numbers in the row??
Clear Mark
Let( tmpTab := _Moving Right Down(tmpTab) ) // move its!
Clear Mark
Store ( _check Point Right Down(tmpTab) Plus (score), tmpTab, score ) // check score...
Clear Mark
Let ( tmpTab := _Moving Right Down(tmpTab) ) // move remanents!
If( _DIRECTION_ )
Set Interval [i,1:SIZE]
Else
Set Interval [1:SIZE,i]
End If
Take( tmpTab ), and Put(table)
End If
Next
Clear(tmpTab) and Clear Mark.
Return
 
check Point Left Up(tmpTab)
v1=0,v2=0,tScore=0,totScore=0
For(k=1, while var(k) Is Lt (SIZE),++k)
At Interval [k] Get (tmpTab), and Move to (v1)
At Interval [ var(k) Plus(1) ] Get(tmpTab), and Move to (v2)
If( var(v1) Is Eq? (v2) )
Add(v1, v2),Copy to (tScore)
At Interval [k] Put(tmpTab), At Interval [ var(k) Plus(1)]; then Take(0) and Put(tmpTab)
Let( totScore := var(tScore) Plus (totScore) )
End If
Next
Take (tmpTab,totScore)
Return
 
check Move Left Up(_DIRECTION_)
tmpTab=0
For(i=1, while var(i) Is Le (SIZE),++i)
If( _DIRECTION_ )
Set Interval [i,1:SIZE]
Else
Set Interval [1:SIZE,i]
End If
now Get(table), and Move to (tmpTab)
If( Summatory (tmpTab) ) // exist numbers in the row??
Clear Mark
Let ( tmpTab := _Moving Left Up(tmpTab) ) // move its!
Clear Mark
Store ( _check Point Left Up(tmpTab) Plus (score), tmpTab, score ) // check score...
 
Clear Mark
Let ( tmpTab := _Moving Left Up(tmpTab) ) // move remanents!
If( _DIRECTION_ )
Set Interval [i,1:SIZE]
Else
Set Interval [1:SIZE,i]
End If
now Take (tmpTab), and Put(table)
End If
Next
Clear Mark.
Return
</syntaxhighlight>
{{out}}
<pre>
Se invoca como:
 
rxvt -g 79x38 -fn "xft:FantasqueSansMono-Regular:pixelsize=25" -e hopper bas/2048.bas
 
</pre>
[[File:Captura_de_pantalla_de_2022-10-07_14-43-23.png]]
 
=={{header|APPLESOFTApplesoft BASIC}}==
<langsyntaxhighlight Applesoftlang="applesoft">PRINT "Game 2048"
 
10 REM ************
Line 582 ⟶ 2,246:
 
 
</syntaxhighlight>
</lang>
 
=={{header|ARM Assembly}}==
{{works with|as|Raspberry Pi}}
<syntaxhighlight lang="arm assembly">
/* ARM assembly Raspberry PI */
/* program 2048.s */
 
/* REMARK 1 : this program use routines in a include file
see task Include a file language arm assembly
for the routine affichageMess conversion10
see at end of this program the instruction include */
/* for constantes see task include a file in arm assembly */
/************************************/
/* Constantes */
/************************************/
.include "../constantes.inc"
.equ STDIN, 0 @ Linux input console
.equ READ, 3 @ Linux syscall
.equ SIZE, 4
.equ TOTAL, 2048
.equ BUFFERSIZE, 80
 
.equ IOCTL, 0x36 @ Linux syscall
.equ SIGACTION, 0x43 @ Linux syscall
.equ SYSPOLL, 0xA8 @ Linux syscall
.equ TCGETS, 0x5401
.equ TCSETS, 0x5402
.equ ICANON, 2
.equ ECHO, 10
.equ POLLIN, 1
.equ SIGINT, 2 @ Issued if the user sends an interrupt signal (Ctrl + C)
.equ SIGQUIT, 3 @ Issued if the user sends a quit signal (Ctrl + D)
.equ SIGTERM, 15 @ Software termination signal (sent by kill by default)
.equ SIGTTOU, 22
 
/*******************************************/
/* Structures */
/********************************************/
/* structure termios see doc linux*/
.struct 0
term_c_iflag: @ input modes
.struct term_c_iflag + 4
term_c_oflag: @ output modes
.struct term_c_oflag + 4
term_c_cflag: @ control modes
.struct term_c_cflag + 4
term_c_lflag: @ local modes
.struct term_c_lflag + 4
term_c_cc: @ special characters
.struct term_c_cc + 20 @ see length if necessary
term_fin:
/* structure sigaction see doc linux */
.struct 0
sa_handler:
.struct sa_handler + 4
sa_mask:
.struct sa_mask + 4
sa_flags:
.struct sa_flags + 4
sa_sigaction:
.struct sa_sigaction + 4
sa_fin:
/* structure poll see doc linux */
.struct 0
poll_fd: @ File Descriptor
.struct poll_fd + 4
poll_events: @ events mask
.struct poll_events + 4
poll_revents: @ events returned
.struct poll_revents + 4
poll_fin:
/*********************************/
/* Initialized data */
/*********************************/
.data
szMessOK: .asciz "Bravo !! You win. \n"
szMessNotOK: .asciz "You lost !! \n"
szMessNewGame: .asciz "New game (y/n) ? \n"
szMessErreur: .asciz "Error detected.\n"
szCarriageReturn: .asciz "\n"
//szMessMovePos: .asciz "\033[00;00H"
szMess0: .asciz " "
szMess2: .asciz " 2 "
szMess4: .asciz " 4 "
szMess8: .asciz " 8 "
szMess16: .asciz " 16 "
szMess32: .asciz " 32 "
szMess64: .asciz " 64 "
szMess128: .asciz " 128 "
szMess256: .asciz " 256 "
szMess512: .asciz " 512 "
szMess1024: .asciz " 1024 "
szMess2048: .asciz " 2048 "
szClear1: .byte 0x1B
.byte 'c' @ other console clear
.byte 0
 
szLineH: .asciz "-----------------------------\n"
szLineV: .asciz "|"
szLineVT: .asciz "| | | | |\n"
.align 4
iGraine: .int 123456
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
.align 4
sZoneConv: .skip 24
sBuffer: .skip BUFFERSIZE
iTbCase: .skip 4 * SIZE * SIZE
iEnd: .skip 4 @ 0 loop 1 = end loop
iTouche: .skip 4 @ value key pressed
stOldtio: .skip term_fin @ old terminal state
stCurtio: .skip term_fin @ current terminal state
stSigAction: .skip sa_fin @ area signal structure
stSigAction1: .skip sa_fin
stPoll1: .skip poll_fin @ area poll structure
stPoll2: .skip poll_fin
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: @ entry of program
1: @ begin game loop
ldr r0,iAdrszClear1
bl affichageMess
bl razTable
2:
bl addDigit
cmp r0,#-1
beq 5f @ end game
bl displayGame
3:
bl readKey
cmp r0,#-1
beq 100f @ error or control-c
bl keyMove
cmp r0,#0
beq 3b @ no change -> loop
cmp r0,#2 @ last addition = 2048 ?
beq 4f
cmp r0,#-1 @ quit ?
bne 2b @ loop
b 10f
4: @ last addition = 2048
ldr r0,iAdrszMessOK
bl affichageMess
b 10f
5: @ display message no solution
ldr r0,iAdrszMessNotOK
bl affichageMess
 
10: @ display new game ?
ldr r0,iAdrszCarriageReturn
bl affichageMess
ldr r0,iAdrszMessNewGame
bl affichageMess
bl readKey
ldr r0,iAdriTouche
ldrb r0,[r0]
cmp r0,#'y'
beq 1b
cmp r0,#'Y'
beq 1b
100: @ standard end of the program
mov r0, #0 @ return code
mov r7, #EXIT @ request to exit program
svc #0 @ perform the system call
iAdrszCarriageReturn: .int szCarriageReturn
iAdrszMessNotOK: .int szMessNotOK
iAdrszMessOK: .int szMessOK
iAdrszMessNewGame: .int szMessNewGame
iAdrsZoneConv: .int sZoneConv
iAdrszClear1: .int szClear1
/******************************************************************/
/* raz table cases */
/******************************************************************/
razTable:
push {r0-r2,lr} @ save registers
ldr r1,iAdriTbCase
mov r0,#0
mov r2,#0
1:
str r0,[r1,r2,lsl #2]
add r2,r2,#1
cmp r2,#SIZE * SIZE
blt 1b
100:
pop {r0-r2,lr} @ restaur registers
bx lr @return
/******************************************************************/
/* key move */
/******************************************************************/
/* r0 contains key value */
keyMove:
push {r1,lr} @ save registers
cmp r0,#0x42 @ down arrow
bne 1f
bl moveDown
b 100f
1:
cmp r0,#0x41 @ high arrow
bne 2f
bl moveUp
b 100f
2:
cmp r0,#0x43 @ right arrow
bne 3f
bl moveRight
b 100f
3:
cmp r0,#0x44 @ left arrow
bne 4f
bl moveLeft
b 100f
4:
ldr r0,iAdriTouche
ldrb r0,[r0]
cmp r0,#'q' @ quit game
bne 5f
mov r0,#-1
b 100f
5:
cmp r0,#'Q' @ quit game
bne 100f
mov r0,#-1
b 100f
 
100:
pop {r1,lr} @ restaur registers
bx lr @return
/******************************************************************/
/* move left */
/******************************************************************/
/* r0 return -1 if ok */
moveLeft:
push {r1-r10,lr} @ save registers
ldr r1,iAdriTbCase
mov r0,#0 @ top move Ok
mov r2,#0 @ line indice
1:
mov r6,#0 @ counter empty case
mov r7,#0 @ first digit
mov r10,#0 @ last digit to add
mov r3,#0 @ column indice
2:
lsl r5,r2,#2 @ change this if size <> 4
add r5,r5,r3 @ compute table indice
ldr r4,[r1,r5,lsl #2]
cmp r4,#0
addeq r6,r6,#1 @ positions vides
beq 5f
cmp r6,#0
beq 3f @ no empty left case
mov r8,#0
str r8,[r1,r5,lsl #2] @ raz digit
sub r5,r5,r6
str r4,[r1,r5,lsl #2] @ and store to left empty position
mov r0,#1 @ move Ok
//sub r6,r6,#1
3:
cmp r7,#0 @ first digit
beq 4f
cmp r10,r4 @ prec digit have to add
beq 4f
sub r8,r5,#1 @ prec digit
ldr r9,[r1,r8,lsl #2]
cmp r4,r9 @ equal ?
bne 4f
mov r10,r4 @ save digit
add r4,r4,r9 @ yes -> add
str r4,[r1,r8,lsl #2]
cmp r4,#TOTAL
moveq r0,#2
beq 100f
mov r4,#0
str r4,[r1,r5,lsl #2]
add r6,r6,#1 @ empty case + 1
mov r0,#1 @ move Ok
4:
add r7,r7,#1 @ no first digit
 
5: @ and loop
add r3,r3,#1
cmp r3,#SIZE
blt 2b
add r2,r2,#1
cmp r2,#SIZE
blt 1b
100:
pop {r1-r12,lr}
bx lr @ return
/******************************************************************/
/* move right */
/******************************************************************/
/* r0 return -1 if ok */
moveRight:
push {r1-r5,lr} @ save registers
ldr r1,iAdriTbCase
mov r0,#0
mov r2,#0
1:
mov r6,#0
mov r7,#0
mov r10,#0
mov r3,#SIZE-1
2:
lsl r5,r2,#2 @ change this if size <> 4
add r5,r5,r3
ldr r4,[r1,r5,lsl #2]
cmp r4,#0
addeq r6,r6,#1 @ positions vides
beq 5f
 
cmp r6,#0
beq 3f @ no empty right case
mov r0,#0
str r0,[r1,r5,lsl #2] @ raz digit
add r5,r5,r6
str r4,[r1,r5,lsl #2] @ and store to right empty position
mov r0,#1
3:
cmp r7,#0 @ first digit
beq 4f
add r8,r5,#1 @ next digit
ldr r9,[r1,r8,lsl #2]
cmp r4,r9 @ equal ?
bne 4f
cmp r10,r4
beq 4f
mov r10,r4
add r4,r4,r9 @ yes -> add
str r4,[r1,r8,lsl #2]
cmp r4,#TOTAL
moveq r0,#2
beq 100f
mov r4,#0
str r4,[r1,r5,lsl #2]
add r6,r6,#1 @ empty case + 1
mov r0,#1
4:
add r7,r7,#1 @ no first digit
 
5: @ and loop
sub r3,r3,#1
cmp r3,#0
bge 2b
add r2,r2,#1
cmp r2,#SIZE
blt 1b
100:
pop {r1-r5,lr}
bx lr @ return
/******************************************************************/
/* move down */
/******************************************************************/
/* r0 return -1 if ok */
moveDown:
push {r1-r5,lr} @ save registers
ldr r1,iAdriTbCase
mov r0,#0
mov r3,#0
1:
mov r6,#0
mov r7,#0
mov r10,#0
mov r2,#SIZE-1
2:
lsl r5,r2,#2 @ change this if size <> 4
add r5,r5,r3
ldr r4,[r1,r5,lsl #2]
cmp r4,#0
addeq r6,r6,#1 @ positions vides
beq 5f
cmp r6,#0
beq 3f @ no empty right case
mov r0,#0
str r0,[r1,r5,lsl #2] @ raz digit
lsl r0,r6,#2
add r5,r5,r0
str r4,[r1,r5,lsl #2] @ and store to right empty position
mov r0,#1
3:
cmp r7,#0 @ first digit
beq 4f
add r8,r5,#SIZE @ down digit
ldr r9,[r1,r8,lsl #2]
cmp r4,r9 @ equal ?
bne 4f
cmp r10,r4
beq 4f
mov r10,r4
add r4,r4,r9 @ yes -> add
str r4,[r1,r8,lsl #2]
cmp r4,#TOTAL
moveq r0,#2
beq 100f
mov r4,#0
str r4,[r1,r5,lsl #2]
add r6,r6,#1 @ empty case + 1
mov r0,#1
4:
add r7,r7,#1 @ no first digit
 
5: @ and loop
sub r2,r2,#1
cmp r2,#0
bge 2b
add r3,r3,#1
cmp r3,#SIZE
blt 1b
 
100:
pop {r1-r5,lr}
bx lr @ return
/******************************************************************/
/* move up */
/******************************************************************/
/* r0 return -1 if ok */
moveUp:
push {r1-r5,lr} @ save registers
ldr r1,iAdriTbCase
mov r0,#0
mov r3,#0
1:
mov r6,#0
mov r7,#0
mov r10,#0
mov r2,#0
2:
lsl r5,r2,#2 @ change this if size <> 4
add r5,r5,r3
ldr r4,[r1,r5,lsl #2]
cmp r4,#0
addeq r6,r6,#1 @ positions vides
beq 5f
cmp r6,#0
beq 3f @ no empty right case
mov r0,#0
str r0,[r1,r5,lsl #2] @ raz digit
lsl r0,r6,#2
sub r5,r5,r0
str r4,[r1,r5,lsl #2] @ and store to right empty position
mov r0,#1
3:
cmp r7,#0 @ first digit
beq 4f
sub r8,r5,#SIZE @ up digit
ldr r9,[r1,r8,lsl #2]
cmp r4,r9 @ equal ?
bne 4f
cmp r10,r4
beq 4f
mov r10,r4
add r4,r4,r9 @ yes -> add
str r4,[r1,r8,lsl #2]
cmp r4,#TOTAL
moveq r0,#2
beq 100f
mov r4,#0
str r4,[r1,r5,lsl #2]
add r6,r6,#1 @ empty case + 1
mov r0,#1
4:
add r7,r7,#1 @ no first digit
 
5: @ and loop
add r2,r2,#1
cmp r2,#SIZE
blt 2b
add r3,r3,#1
cmp r3,#SIZE
blt 1b
 
100:
pop {r1-r5,lr}
bx lr @ return
/******************************************************************/
/* add new digit on game */
/******************************************************************/
/* r0 return -1 if ok */
addDigit:
push {r1-r5,lr} @ save registers
sub sp,#4 * SIZE*SIZE
mov fp,sp
mov r0,#100
bl genereraleas
cmp r0,#10
movlt r5,#4
movge r5,#2
ldr r1,iAdriTbCase
mov r3,#0
mov r4,#0
1:
ldr r2,[r1,r3,lsl #2]
cmp r2,#0
bne 2f
str r3,[fp,r4,lsl #2]
add r4,r4,#1
2:
add r3,r3,#1
cmp r3,#SIZE*SIZE
blt 1b
cmp r4,#0 @ no empty case
moveq r0,#-1
beq 100f
cmp r4,#1
bne 3f
ldr r2,[fp] @ one case
str r5,[r1,r2,lsl #2]
mov r0,#0
b 100f
3: @ multiple case
sub r0,r4,#1
bl genereraleas
ldr r2,[fp,r0,lsl #2]
str r5,[r1,r2,lsl #2]
mov r0,#0
100:
add sp,#4* (SIZE*SIZE) @ stack alignement
pop {r1-r5,lr}
bx lr @ return
iAdriTbCase: .int iTbCase
/******************************************************************/
/* display game */
/******************************************************************/
displayGame:
push {r1-r3,lr} @ save registers
ldr r0,iAdrszClear1
bl affichageMess
ldr r0,iAdrszLineH
bl affichageMess
ldr r0,iAdrszLineVT
bl affichageMess
ldr r0,iAdrszLineV
bl affichageMess
ldr r1,iAdriTbCase
mov r2,#0
1:
ldr r0,[r1,r2,lsl #2]
bl digitString
bl affichageMess
ldr r0,iAdrszLineV
bl affichageMess
add r2,r2,#1
cmp r2,#SIZE
blt 1b
ldr r0,iAdrszCarriageReturn
bl affichageMess
ldr r0,iAdrszLineVT
bl affichageMess
ldr r0,iAdrszLineH
bl affichageMess
ldr r0,iAdrszLineVT
bl affichageMess
ldr r0,iAdrszLineV
bl affichageMess
2:
ldr r0,[r1,r2,lsl #2]
bl digitString
bl affichageMess
ldr r0,iAdrszLineV
bl affichageMess
add r2,r2,#1
cmp r2,#SIZE*2
blt 2b
ldr r0,iAdrszCarriageReturn
bl affichageMess
ldr r0,iAdrszLineVT
bl affichageMess
ldr r0,iAdrszLineH
bl affichageMess
ldr r0,iAdrszLineVT
bl affichageMess
ldr r0,iAdrszLineV
bl affichageMess
3:
ldr r0,[r1,r2,lsl #2]
bl digitString
bl affichageMess
ldr r0,iAdrszLineV
bl affichageMess
add r2,r2,#1
cmp r2,#SIZE*3
blt 3b
ldr r0,iAdrszCarriageReturn
bl affichageMess
ldr r0,iAdrszLineVT
bl affichageMess
ldr r0,iAdrszLineH
bl affichageMess
ldr r0,iAdrszLineVT
bl affichageMess
ldr r0,iAdrszLineV
bl affichageMess
4:
ldr r0,[r1,r2,lsl #2]
bl digitString
bl affichageMess
ldr r0,iAdrszLineV
bl affichageMess
add r2,r2,#1
cmp r2,#SIZE*4
blt 4b
ldr r0,iAdrszCarriageReturn
bl affichageMess
ldr r0,iAdrszLineVT
bl affichageMess
ldr r0,iAdrszLineH
bl affichageMess
 
100:
pop {r1-r3,lr}
bx lr @ return
iAdrszLineH: .int szLineH
iAdrszLineV: .int szLineV
iAdrszLineVT: .int szLineVT
//iAdrszMessMovePos: .int szMessMovePos
/******************************************************************/
/* digits string */
/******************************************************************/
/* r0 contains number */
/* r0 return address string */
digitString:
push {r1,lr} @ save registers
cmp r0,#0
bne 1f
ldr r0,iAdrszMess0
b 100f
1:
cmp r0,#2
bne 2f
ldr r0,iAdrszMess2
b 100f
2:
cmp r0,#4
bne 3f
ldr r0,iAdrszMess4
b 100f
3:
cmp r0,#8
bne 4f
ldr r0,iAdrszMess8
b 100f
4:
cmp r0,#16
bne 5f
ldr r0,iAdrszMess16
b 100f
5:
cmp r0,#32
bne 6f
ldr r0,iAdrszMess32
b 100f
6:
cmp r0,#64
bne 7f
ldr r0,iAdrszMess64
b 100f
7:
cmp r0,#128
bne 8f
ldr r0,iAdrszMess128
b 100f
8:
cmp r0,#256
bne 9f
ldr r0,iAdrszMess256
b 100f
9:
cmp r0,#512
bne 10f
ldr r0,iAdrszMess512
b 100f
10:
cmp r0,#1024
bne 11f
ldr r0,iAdrszMess1024
b 100f
11:
cmp r0,#2048
bne 12f
ldr r0,iAdrszMess2048
b 100f
12:
ldr r1,iAdrszMessErreur @ error message
bl displayError
100:
pop {r1,lr}
bx lr @ return
iAdrszMess0: .int szMess0
iAdrszMess2: .int szMess2
iAdrszMess4: .int szMess4
iAdrszMess8: .int szMess8
iAdrszMess16: .int szMess16
iAdrszMess32: .int szMess32
iAdrszMess64: .int szMess64
iAdrszMess128: .int szMess128
iAdrszMess256: .int szMess256
iAdrszMess512: .int szMess512
iAdrszMess1024: .int szMess1024
iAdrszMess2048: .int szMess2048
 
//iAdrsBuffer: .int sBuffer
/***************************************************/
/* Generation random number */
/***************************************************/
/* r0 contains limit */
genereraleas:
push {r1-r4,lr} @ save registers
ldr r4,iAdriGraine
ldr r2,[r4]
ldr r3,iNbDep1
mul r2,r3,r2
ldr r3,iNbDep2
add r2,r2,r3
str r2,[r4] @ maj de la graine pour l appel suivant
cmp r0,#0
beq 100f
add r1,r0,#1 @ divisor
mov r0,r2 @ dividende
bl division
mov r0,r3 @ résult = remainder
100: @ end function
pop {r1-r4,lr} @ restaur registers
bx lr @ return
/*****************************************************/
iAdriGraine: .int iGraine
iNbDep1: .int 0x343FD
iNbDep2: .int 0x269EC3
/***************************************************/
/* read touch */
/***************************************************/
readKey:
push {r1-r7,lr}
mov r5,#0
ldr r1,iAdriTouche @ buffer address
str r5,[r1] @ raz 4 bytes iTouche
/* read terminal state */
mov r0,#STDIN @ input console
mov r1,#TCGETS
ldr r2,iAdrstOldtio
mov r7, #IOCTL @ call system Linux
svc #0
cmp r0,#0 @ error ?
beq 1f
ldr r1,iAdrszMessErreur @ error message
bl displayError
mov r0,#-1
b 100f
1:
adr r0,sighandler @ adresse routine traitement signal
ldr r1,iAdrstSigAction @ adresse structure sigaction
str r0,[r1,#sa_handler] @ maj handler
mov r0,#SIGINT @ signal type
ldr r1,iAdrstSigAction
mov r2,#0 @ NULL
mov r7, #SIGACTION @ call system
svc #0
cmp r0,#0 @ error ?
bne 97f
mov r0,#SIGQUIT
ldr r1,iAdrstSigAction
mov r2,#0 @ NULL
mov r7, #SIGACTION @ call system
svc #0
cmp r0,#0 @ error ?
bne 97f
mov r0,#SIGTERM
ldr r1,iAdrstSigAction
mov r2,#0 @ NULL
mov r7, #SIGACTION @ appel systeme
svc #0
cmp r0,#0
bne 97f
@
adr r0,iSIG_IGN @ address signal ignore function
ldr r1,iAdrstSigAction1
str r0,[r1,#sa_handler]
mov r0,#SIGTTOU @invalidate other process signal
ldr r1,iAdrstSigAction1
mov r2,#0 @ NULL
mov r7,#SIGACTION @ call system
svc #0
cmp r0,#0
bne 97f
@
/* read terminal current state */
mov r0,#STDIN
mov r1,#TCGETS
ldr r2,iAdrstCurtio @ address current termio
mov r7,#IOCTL @ call systeme
svc #0
cmp r0,#0 @ error ?
bne 97f
mov r2,#ICANON | ECHO @ no key pressed echo on display
mvn r2,r2 @ and one key
ldr r1,iAdrstCurtio
ldr r3,[r1,#term_c_lflag]
and r3,r2 @ add flags
str r3,[r1,#term_c_lflag] @ and store
mov r0,#STDIN @ maj terminal current state
mov r1,#TCSETS
ldr r2,iAdrstCurtio
mov r7, #IOCTL @ call system
svc #0
cmp r0,#0
bne 97f
@
2: @ loop waiting key
ldr r0,iAdriEnd @ if signal ctrl-c -> end
ldr r0,[r0]
cmp r0,#0
movne r5,#-1
bne 98f
ldr r0,iAdrstPoll1 @ address structure poll
mov r1,#STDIN
str r1,[r0,#poll_fd] @ maj FD
mov r1,#POLLIN @ action code
str r1,[r0,#poll_events]
mov r1,#1 @ items number structure poll
mov r2,#0 @ timeout = 0
mov r7,#SYSPOLL @ call system POLL
svc #0
cmp r0,#0 @ key pressed ?
ble 2b @ no key pressed -> loop
@ read key
mov r0,#STDIN @ File Descriptor
ldr r1,iAdriTouche @ buffer address
mov r2,#BUFFERSIZE @ buffer size
mov r7,#READ @ read key
svc #0
cmp r0,#0 @ error ?
bgt 98f
97: @ error detected
ldr r1,iAdrszMessErreur @ error message
bl displayError
mov r5,#-1
98: @ end then restaur begin state terminal
mov r0,#STDIN
mov r1,#TCSETS
ldr r2,iAdrstOldtio
mov r7,#IOCTL @ call system
svc #0
cmp r0,#0
beq 99f @ restaur ok
ldr r1,iAdrszMessErreur @ error message
bl displayError
mov r0,#-1
b 100f
99:
cmp r5,#0 @ no error or control-c ?
ldreq r2,iAdriTouche @ key address
ldreqb r0,[r2,#2] @ return key byte
movne r0,r5 @ or error
100:
pop {r1-r7, lr}
bx lr
iSIG_IGN: .int 1
iAdriEnd: .int iEnd
iAdrstPoll1: .int stPoll1
iAdriTouche: .int iTouche
iAdrstOldtio: .int stOldtio
iAdrstCurtio: .int stCurtio
iAdrstSigAction: .int stSigAction
iAdrstSigAction1: .int stSigAction1
iAdrszMessErreur : .int szMessErreur
/******************************************************************/
/* traitement du signal */
/******************************************************************/
sighandler:
push {r0,r1}
ldr r0,iAdriEnd
mov r1,#1 @ maj zone end
str r1,[r0]
pop {r0,r1}
bx lr
/***************************************************/
/* ROUTINES INCLUDE */
/***************************************************/
.include "../affichage.inc"
</syntaxhighlight>
{{Output}}
<pre>
-----------------------------
| | | | |
| 8 | 4 | 4 | 2 |
| | | | |
-----------------------------
| | | | |
| 64 | 16 | | |
| | | | |
-----------------------------
| | | | |
| 16 | | | 2 |
| | | | |
-----------------------------
| | | | |
| 2 | | | |
| | | | |
-----------------------------
</pre>
 
=={{header|AutoHotkey}}==
<langsyntaxhighlight AutoHotkeylang="autohotkey">Grid := [], s := 16, w := h := S * 4.5
Gui, font, s%s%
Gui, add, text, y1
Line 809 ⟶ 3,388:
Grid[StrSplit(rnd, ",").1, StrSplit(rnd, ",").2] := 2
}
;------------------------------</langsyntaxhighlight>
 
=={{header|Batch File}}==
<langsyntaxhighlight lang="dos">:: 2048 Game Task from RosettaCode.org
:: Batch File Implementation v2.0.1
 
@echo off
setlocal enabledelayedexpansion
cls
 
rem initialization
:begin_game
set "size=4" %== Setboard variablessize ==%
set "score=0" %== current score ==%
set "won=0" %== boolean for winning ==%
set "target=2048" %== as the game title says ==%
set "SUP_score=0"
for /l %%AR in (1,1,4%size%) do for /l %%BC in (1,1,4%size%) do set /a "X_%%AR_%%BC=0"
 
rem add two numbers in the board
call :addtile
call :addtile
 
%==rem Mainmain game loop ==%
:main_loop
set "changed=0"
call :display
echo(
echo Keys: WASD (Slide Movement^), N (New game^), P (Exit^)
 
%== Get Keypress ==%
set "key="
for /f "delims=" %%? in ('xcopy /w "%~f0" "%~f0" 2^>nul') do if not defined key set "key=%%?"
set "key=%key:~-1%"
 
%== Process keypress ==%
if /i "!key!"=="W" (
for /l %%? in (1,1,4) do call :slide X_1%%? X_2%%? X_3%%? X_4%%?
)
if /i "!key!"=="A" (
for /l %%? in (1,1,4) do call :slide X_%%?1 X_%%?2 X_%%?3 X_%%?4
)
if /i "!key!"=="S" (
for /l %%? in (1,1,4) do call :slide X_4%%? X_3%%? X_2%%? X_1%%?
)
if /i "!key!"=="D" (
for /l %%? in (1,1,4) do call :slide X_%%?4 X_%%?3 X_%%?2 X_%%?1
)
if /i "!key!"=="N" goto :begin_game
if /i "!key!"=="P" exit /b
 
%== Check if the board changed ==%
if %changed% neq 0 call :addtile
 
%== Check if already won ==%
if %won% equ 1 (
set "msg=Nice one... You WON^!^!"
goto :gameover
)
 
%== Check for lose condition ==%
set /a "real_blanks=blank_count-1"
if %real_blanks% leq 0 (
for /l %%A in (1,1,4) do for /l %%B in (1,1,4) do set "TRY_%%A%%B=!X_%%A%%B!"
set "TRY_changed=%changed%" & set "changed=0"
set "SUP_score=1"
for /l %%? in (1,1,4) do call :slide TRY_%%?1 TRY_%%?2 TRY_%%?3 TRY_%%?4
for /l %%? in (1,1,4) do call :slide TRY_1%%? TRY_2%%? TRY_3%%? TRY_4%%?
if !changed! equ 0 (
set "msg=No moves are possible... Game Over :("
goto :gameover
) else (set "changed=!TRY_changed!" & set "SUP_score=0")
)
goto main_loop
 
 
::~~~~~~~~~~~~~~~~~~~~ Sub Procedures ~~~~~~~~~~~~~~~~~~~~::
%== Game Over xD ==%
:gameover
call :display
echo(
echo(Keys: WASD (Slide Movement), N (New game), P (Exit)
echo(!msg!
echo(
echo(Keys: N (New game^), P (Exit^)
 
rem get keypress trick
:key_loop
set "key="
for /f "delims=" %%? in ('xcopy /w "%~f0" "%~f0" 2^>nul') do if not defined key set "key=%%?"
set "key=%key:~-1%"
if /i "!key!"=="N" goto :begin_game
if /i "!key!"=="P" exit /b
goto :key_loop
 
set "changed=0" %== boolean for changed board ==%
%== The main slider of numbers in tiles ==%
set "valid_key=0" %== boolean for pressing WASD ==%
:slide
rem process keypress
set "next="
if /i "!key!" equ "W" (set "valid_key=1" & call :slide "C" "1,1,%size%" "X")
set "slide_1="
if /i "!key!" equ "A" (set "valid_key=1" & call :slide "R" "1,1,%size%" "X")
set "slide_2="
if /i "!key!" equ "S" (set "valid_key=1" & call :slide "C" "%size%,-1,1" "X")
for %%? in (%*) do if !%%?! neq 0 set "slide_1=!slide_1! !%%?!"
if /i "!key!" equ "D" (set "valid_key=1" & call :slide "R" "%size%,-1,1" "X")
for %%? in (!slide_1!) do (
if /i "!key!" equ "N" goto begin_game
set "scan=%%?"
if /i "!scankey!"== equ "!next!P" (exit /b 0
if "%valid_key%" equ "0" goto main_loop
set /a "next*=2"
 
if !SUP_score! equ 0 set /a "score+=!next!"
rem check if the board changed
%== WINNING CONDITION!!! ==%
if %changed% neq 0 call :addtile
if "!next!" equ "2048" set "won=1"
 
set "scan="
rem check for win condition
)
if %won% equ 1 (
set "slide_2=!slide_2! !next!"
set "nextmsg=Nice one... You WON^!scan^!"
goto gameover
)
 
set "slide_2=!slide_2! !next!"
rem check for lose condition
for /l %%? in (1,1,4) do set "final_%%?=0"
if %blank_count% equ 0 (
set "cnt=0" & for %%? in (!slide_2!) do if !cnt! lss 4 (
for /l %%R in (1,1,%size%) do for /l %%C in (1,1,%size%) do set "LX_%%R_%%C=!X_%%R_%%C!"
set /a "cnt+=1"
set "save_changed=%changed%" & set "changed=0" %== save actual changed for test ==%
set "final_!cnt!=%%?"
call :slide "C" "1,1,%size%" "LX"
)
call :slide "R" "1,1,%size%" "LX"
if not "!%1!!%2!!%3!!%4!"=="!final_1!!final_2!!final_3!!final_4!" set "changed=1"
set "cnt=0" & for %%?if in!changed! (%*)equ do0 (
set "msg=No moves are possible... Game Over :("
set /a "cnt+=1"
goto gameover
set /a "%%?=final_!cnt!"
) else set "changed=!save_changed!"
)
goto :EOFmain_loop
 
%==rem Addadd number to tilea ==%random blank tile
:addtile
set "blank_count=0" %== blank tile counter ==%
set "blank_list="
set "new_tile=" %== clearing ==%
set "blank_count=0"
rem create pseudo-array blank_tiles
for /l %%A in (1,1,4) do for /l %%B in (1,1,4) do (
iffor /l !X_%%AR in (1,1,%size%B! equ) 0do (
for /l %%C in (1,1,%size%) do (
set "blank_list=!blank_list!X_%%A%%B"
if !X_%%R_%%C! equ 0 (
set /a blank_count+=1
set "blank_tiles[!blank_count!]=X_%%R_%%C"
)
set /a "blank_count+=1"
)
)
set /a "pick_tile=(%random% %% %blank_count%)*4"
)
set /a "rnd=%random%%%10+1"
)
set "tile_new=!blank_list:~%pick_tile%,4!"
if %blank_count% equ 0 goto :EOF
if %rnd%==5 (set !tile_new!=4) else (set !tile_new!=2)
set /a "pick_tile=%random%%%%blank_count%"
set "new_tile=!blank_tiles[%pick_tile%]!"
set /a "rnd_newnum=%random%%%10"
rem 10% chance new number is 4, 90% chance it's 2
if %rnd_newnum% equ 5 (set "%new_tile%=4") else (set "%new_tile%=2")
set /a "blank_count-=1" %== to be used for checking lose condition ==%
goto :EOF
 
%==rem Displaydisplay the table ==%board
:display
cls
echo (2048 Game in Batch
echo(
set "wall=+"
for /l %%A in (1,1,4) do (
for /l %%BC in (1,1,4%size%) do (set "wall=!wall!----+"
for /l %%R in (1,1,%size%) do (
set "DX_%%A%%B=!X_%%A%%B!"
set "disp_row=|"
if !tile_new!==X_%%A%%B (set "DX_%%A%%B= +!X_%%A%%B!") else (
for /l %%C in (1,1,%size%) do (
if !X_%%A%%B! lss 1000 set "DX_%%A%%B= !DX_%%A%%B!"
if "!new_tile!" equ "X_%%AR_%%B! lss 100C" (set "DX_%%AR_%%BC= +!DX_X_%%AR_%%BC!") else (
if !X_%%A%%B! lss 10 set "DX_%%AR_%%BC= !DX_X_%%AR_%%BC!"
if !X_%%AR_%%BC! equlss 01000 set "DX_%%AR_%%BC= !DX_%%R_%%C!"
if !X_%%R_%%C! lss 100 set "DX_%%R_%%C= !DX_%%R_%%C!"
)
if !X_%%R_%%C! lss 10 set "DX_%%R_%%C= !DX_%%R_%%C!"
)
if !X_%%R_%%C! equ 0 set "DX_%%R_%%C= "
echo +----+----+----+----+
)
echo ^|!DX_%%A1!^|!DX_%%A2!^|!DX_%%A3!^|!DX_%%A4!^|
set "disp_row=!disp_row!!DX_%%R_%%C!|"
)
echo(%wall%
echo(!disp_row!
)
echo(%wall%
echo +----+----+----+----+
echo(
echo(Score: %score%
goto :EOF
 
rem the main slider of numbers in tiles
:slide
rem %%A and %%B are used here because sliding direction is variable
for /l %%A in (1,1,%size%) do (
rem first slide: removing blank tiles in the middle
set "slide_1="
set "last_blank=0" %== boolean if last tile is blank ==%
for /l %%B in (%~2) do (
if "%~1" equ "R" (set "curr_tilenum=!%~3_%%A_%%B!"
) else if "%~1" equ "C" (set "curr_tilenum=!%~3_%%B_%%A!")
if !curr_tilenum! equ 0 (set "last_blank=1") else (
set "slide_1=!slide_1! !curr_tilenum!"
if !last_blank! equ 1 set "changed=1"
set "last_blank=0"
)
)
rem second slide: addition of numbered tiles
rem slide_2 would be pseudo-array
set "slide_2_count=0"
set "skip=1" %== boolean for skipping after previous summing ==%
if "!slide_1!" neq "" for %%S in (!slide_1! 0) do (
if !skip! equ 1 (
set "prev_tilenum=%%S" & set "skip=0"
) else if !skip! equ 0 (
if %%S equ !prev_tilenum! (
set /a "sum=%%S+!prev_tilenum!"
if "%~3" equ "X" set /a "score+=sum"
set "changed=1" & set "skip=1"
rem check for winning condition!
if !sum! equ !target! set "won=1"
) else (
set "sum=!prev_tilenum!"
set "prev_tilenum=%%S"
)
set "slide_2[!slide_2_count!]=!sum!"
set /a "slide_2_count+=1"
)
)
rem new values of tiles
set "slide_2_run=0" %== running counter for slide_2 ==%
for /l %%B in (%~2) do (
if "%~1" equ "R" (set "curr_tile=%~3_%%A_%%B"
) else if "%~1" equ "C" (set "curr_tile=%~3_%%B_%%A")
for %%? in ("!slide_2_run!") do (
if %%~? lss !slide_2_count! (set "!curr_tile!=!slide_2[%%~?]!"
) else (set "!curr_tile!=0")
)
set /a "slide_2_run+=1"
)
)
goto :EOF
 
rem game over xD
:gameover
call :display
echo(
echo(!msg!
echo(
echo(Press any key to exit . . .
echo Score: %score%
pause>nul
goto :EOF</lang>
exit /b 0</syntaxhighlight>
{{out}}
<pre>2048 Game in Batch
Line 984 ⟶ 3,579:
 
Keys: WASD (Slide Movement), N (New game), P (Exit)</pre>
 
 
=={{header|BASIC}}==
==={{header|QBasic}}===
El código es de MichD (https://github.com/michd/2048-qbasic)
 
Yo solo lo transcribo.
<syntaxhighlight lang="qbasic">
SCREEN 13
PALETTE 1, pColor(35, 33, 31)
PALETTE 2, pColor(46, 46, 51)
PALETTE 3, pColor(59, 56, 50)
PALETTE 4, pColor(61, 44, 30)
PALETTE 5, pColor(61, 37, 25)
PALETTE 6, pColor(62, 31, 24)
PALETTE 7, pColor(62, 24, 15)
PALETTE 8, pColor(59, 52, 29)
PALETTE 9, pColor(59, 51, 24)
PALETTE 10, pColor(59, 50, 20)
PALETTE 11, pColor(59, 49, 16)
PALETTE 12, pColor(59, 49, 12)
PALETTE 13, pColor(15, 15, 13)
PALETTE 14, pColor(23, 22, 20)
 
DIM SHARED gDebug
DIM SHARED gOriginX
DIM SHARED gOriginY
DIM SHARED gTextOriginX
DIM SHARED gTextOriginY
DIM SHARED gSquareSide
DIM SHARED gGridSize
 
gGridSize = 4 ' grid size (4 -> 4x4)
 
DIM SHARED gGrid(gGridSize, gGridSize)
DIM SHARED gScore
 
' Don't touch these numbers, seriously
 
gOriginX = 75 'pixel X of top left of grid
gOriginY = 12 'pixel Y of top right of grid
gTextOriginX = 11
gTextOriginY = 3
gSquareSide = 38 'width/height of block in pixels
 
 
'set up all the things!
gDebug = 0
 
RANDOMIZE TIMER
CLS
 
start:
initGrid
initGraphicGrid
renderGrid
updateScore
 
gScore = 0
 
LOCATE 23, 1
PRINT "Move with arrow keys. (R)estart, (Q)uit"
 
' keyboard input loop
DO
DO
k$ = INKEY$
LOOP UNTIL k$ <> ""
 
SELECT CASE k$
CASE CHR$(0) + CHR$(72) 'up
processMove ("u")
CASE CHR$(0) + CHR$(80) 'down
processMove ("d")
CASE CHR$(0) + CHR$(77) 'right
processMove ("r")
CASE CHR$(0) + CHR$(75) 'left
processMove ("l")
CASE CHR$(27) 'escape
GOTO programEnd
CASE "q"
GOTO programEnd
CASE "Q"
GOTO programEnd
CASE "r"
GOTO start
CASE "R"
GOTO start
END SELECT
LOOP
 
programEnd:
 
SUB addblock
DIM emptyCells(gGridSize * gGridSize, 2)
emptyCellCount = 0
 
FOR x = 0 TO gGridSize - 1
FOR y = 0 TO gGridSize - 1
IF gGrid(x, y) = 0 THEN
emptyCells(emptyCellCount, 0) = x
emptyCells(emptyCellCount, 1) = y
emptyCellCount = emptyCellCount + 1
END IF
NEXT y
NEXT x
 
IF emptyCellCount > 0 THEN
index = INT(RND * emptyCellCount)
num = CINT(RND + 1) * 2
gGrid(emptyCells(index, 0), emptyCells(index, 1)) = num
END IF
 
END SUB
 
SUB drawNumber (num, xPos, yPos)
SELECT CASE num
CASE 0: c = 16
CASE 2: c = 2
CASE 4: c = 3
CASE 8: c = 4
CASE 16: c = 5
CASE 32: c = 6
CASE 64: c = 7
CASE 128: c = 8
CASE 256: c = 9
CASE 512: c = 10
CASE 1024: c = 11
CASE 2048: c = 12
CASE 4096: c = 13
CASE 8192: c = 13
CASE ELSE: c = 13
END SELECT
 
x = xPos * (gSquareSide + 2) + gOriginX + 1
y = yPos * (gSquareSide + 2) + gOriginY + 1
LINE (x + 1, y + 1)-(x + gSquareSide - 1, y + gSquareSide - 1), c, BF
 
IF num > 0 THEN
LOCATE gTextOriginY + 1 + (yPos * 5), gTextOriginX + (xPos * 5)
PRINT " "
LOCATE gTextOriginY + 2 + (yPos * 5), gTextOriginX + (xPos * 5)
PRINT pad$(num)
LOCATE gTextOriginY + 3 + (yPos * 5), gTextOriginX + (xPos * 5)
'PRINT " "
END IF
 
END SUB
 
FUNCTION getAdjacentCell (x, y, d AS STRING)
 
IF (d = "l" AND x = 0) OR (d = "r" AND x = gGridSize - 1) OR (d = "u" AND y = 0) OR (d = "d" AND y = gGridSize - 1) THEN
getAdjacentCell = -1
ELSE
SELECT CASE d
CASE "l": getAdjacentCell = gGrid(x - 1, y)
CASE "r": getAdjacentCell = gGrid(x + 1, y)
 
CASE "u": getAdjacentCell = gGrid(x, y - 1)
CASE "d": getAdjacentCell = gGrid(x, y + 1)
END SELECT
END IF
 
END FUNCTION
 
'Draws the outside grid (doesn't render tiles)
SUB initGraphicGrid
 
gridSide = (gSquareSide + 2) * gGridSize
 
LINE (gOriginX, gOriginY)-(gOriginX + gridSide, gOriginY + gridSide), 14, BF 'outer square, 3 thick
LINE (gOriginX, gOriginY)-(gOriginX + gridSide, gOriginY + gridSide), 1, B 'outer square, 3 thick
LINE (gOriginX - 1, gOriginY - 1)-(gOriginX + gridSide + 1, gOriginY + gridSide + 1), 1, B
LINE (gOriginX - 2, gOriginY - 2)-(gOriginX + gridSide + 2, gOriginY + gridSide + 2), 1, B
 
FOR x = gOriginX + gSquareSide + 2 TO gOriginX + (gSquareSide + 2) * gGridSize STEP gSquareSide + 2 ' horizontal lines
LINE (x, gOriginY)-(x, gOriginY + gridSide), 1
NEXT x
 
FOR y = gOriginY + gSquareSide + 2 TO gOriginY + (gSquareSide + 2) * gGridSize STEP gSquareSide + 2 ' vertical lines
LINE (gOriginX, y)-(gOriginX + gridSide, y), 1
NEXT y
 
END SUB
 
'Init the (data) grid with 0s
SUB initGrid
FOR x = 0 TO 3
FOR y = 0 TO 3
gGrid(x, y) = 0
NEXT y
NEXT x
 
addblock
addblock
 
END SUB
 
SUB moveBlock (sourceX, sourceY, targetX, targetY, merge)
 
IF sourceX < 0 OR sourceX >= gGridSize OR sourceY < 0 OR sourceY >= gGridSize AND gDebug = 1 THEN
LOCATE 0, 0
PRINT "moveBlock: source coords out of bounds"
END IF
 
IF targetX < 0 OR targetX >= gGridSize OR targetY < 0 OR targetY >= gGridSize AND gDebug = 1 THEN
LOCATE 0, 0
PRINT "moveBlock: source coords out of bounds"
END IF
 
sourceSquareValue = gGrid(sourceX, sourceY)
targetSquareValue = gGrid(targetX, targetY)
 
IF merge = 1 THEN
 
IF sourceSquareValue = targetSquareValue THEN
gGrid(sourceX, sourceY) = 0
gGrid(targetX, targetY) = targetSquareValue * 2
gScore = gScore + targetSquareValue * 2 ' Points!
ELSEIF gDebug = 1 THEN
LOCATE 0, 0
PRINT "moveBlock: Attempted to merge unequal sqs"
END IF
 
ELSE
 
IF targetSquareValue = 0 THEN
gGrid(sourceX, sourceY) = 0
gGrid(targetX, targetY) = sourceSquareValue
ELSEIF gDebug = 1 THEN
LOCATE 0, 0
PRINT "moveBlock: Attempted to move to non-empty block"
END IF
 
END IF
 
END SUB
 
FUNCTION pad$ (num)
strNum$ = LTRIM$(STR$(num))
 
SELECT CASE LEN(strNum$)
CASE 1: pad = " " + strNum$ + " "
CASE 2: pad = " " + strNum$ + " "
CASE 3: pad = " " + strNum$
CASE 4: pad = strNum$
END SELECT
 
END FUNCTION
 
FUNCTION pColor (r, g, b)
pColor = (r + g * 256 + b * 65536)
END FUNCTION
 
SUB processMove (dir AS STRING)
' dir can be 'l', 'r', 'u', or 'd'
 
hasMoved = 0
 
IF dir = "l" THEN
 
FOR y = 0 TO gGridSize - 1
wasMerge = 0
FOR x = 0 TO gGridSize - 1
GOSUB processBlock
NEXT x
NEXT y
 
ELSEIF dir = "r" THEN
 
FOR y = 0 TO gGridSize - 1
wasMerge = 0
FOR x = gGridSize - 1 TO 0 STEP -1
GOSUB processBlock
NEXT x
NEXT y
 
ELSEIF dir = "u" THEN
FOR x = 0 TO gGridSize - 1
wasMerge = 0
FOR y = 0 TO gGridSize - 1
GOSUB processBlock
NEXT y
NEXT x
 
ELSEIF dir = "d" THEN
FOR x = 0 TO gGridSize - 1
wasMerge = 0
FOR y = gGridSize - 1 TO 0 STEP -1
GOSUB processBlock
NEXT y
NEXT x
 
END IF
 
GOTO processMoveEnd
 
moveToObstacle:
curX = x
curY = y
 
DO WHILE getAdjacentCell(curX, curY, dir) = 0
SELECT CASE dir
CASE "l": curX = curX - 1
CASE "r": curX = curX + 1
CASE "u": curY = curY - 1
CASE "d": curY = curY + 1
END SELECT
LOOP
RETURN
 
processBlock:
 
merge = 0
IF gGrid(x, y) <> 0 THEN ' have block
 
GOSUB moveToObstacle ' figure out where it can be moved to
IF getAdjacentCell(curX, curY, dir) = gGrid(x, y) AND wasMerge = 0 THEN ' obstacle can be merged with
merge = 1
wasMerge = 1
ELSE
wasMerge = 0
END IF
 
IF curX <> x OR curY <> y OR merge = 1 THEN
mergeDirX = 0
mergeDirY = 0
IF merge = 1 THEN
SELECT CASE dir
CASE "l": mergeDirX = -1
CASE "r": mergeDirX = 1
CASE "u": mergeDirY = -1
CASE "d": mergeDirY = 1
END SELECT
END IF
 
CALL moveBlock(x, y, curX + mergeDirX, curY + mergeDirY, merge) ' move to before obstacle or merge
hasMoved = 1
END IF
END IF
RETURN
 
processMoveEnd:
 
IF hasMoved = 1 THEN addblock
renderGrid
updateScore
 
END SUB
 
SUB renderGrid
FOR x = 0 TO gGridSize - 1
FOR y = 0 TO gGridSize - 1
CALL drawNumber(gGrid(x, y), x, y)
NEXT y
NEXT x
END SUB
 
SUB updateScore
LOCATE 1, 10
PRINT "Score:" + STR$(gScore)
END SUB
</syntaxhighlight>
 
=={{header|BBC BASIC}}==
{{works with|BBC BASIC for Windows}}
<langsyntaxhighlight lang="bbcbasic"> SIZE = 4 : MAX = SIZE-1
Won% = FALSE : Lost% = FALSE
@% = 5
Line 1,056 ⟶ 4,014:
IF Board(z DIV SIZE,z MOD SIZE) = 0 THEN Board(z DIV SIZE,z MOD SIZE) = 2-(RND(10)=1)*2 : EXIT FOR
NEXT
ENDPROC</langsyntaxhighlight>
{{out}}
<pre> _ _ _ _
Line 1,088 ⟶ 4,046:
--------------------
You lost :-(</pre>
 
=={{header|BQN}}==
<syntaxhighlight lang="bqn">
#!/usr/bin/env BQN
# 2048 game
# The game is controlled with the vim movement keys:
# h: left, j: down, k: up, l: right, q: quit
# needs a VT-100 compatible terminal
 
Merge←{𝕩 0⊸≠⊸/↩ ⋄ m←<`=⟜«𝕩 ⋄ 4↑(¬»m)/𝕩×1+m}⌾⌽ # Merge a single row to the right
Step←Merge˘ # Merges each row of the board
Up←Step⌾(⌽⍉∘⌽) # Each direction merges the board
Down←Step⌾⍉ # by rotating it to the correct orientation, merging the rows
Right←Step # and reversing the rotation
Left←Step⌾(⌽˘)
# Spawns a 2 or a 4 (10% chance) at a random empty position
Spawn←{i←•rand.Range∘≠⊸⊑(0⊸= /○⥊ ↕∘≢)𝕩 ⋄ (•rand.Range∘≠⊸⊑9‿1/2‿4)⌾(i⊸⊑) 𝕩}
Lose←Left∘Right∘Down∘Up⊸≡ # Losing condition, no moves change the board
Win←∨´·∨˝2048⊸= # Winning condition, 2048!
 
Quit←{•Out e∾"[?12l"∾e∾"[?25h" ⋄ •Exit 𝕩} # Restores the terminal and exits
Display←{ # Displays the board, score and controls
•Out e∾"[H"∾e∾"[2J" # Cursor to origin and clear screen
•Out "Controls: h: left, j: down, k: up, l: right, q: quit"
•Show 𝕩
•Out "score: "∾•Repr ⌈´⌈˝ 𝕩
}
 
board←Spawn 4‿4⥊0
e←@+27 # Escape character for the ANSI escape codes
•term.RawMode 1
•Out e∾"[?25l"∾e∾"[2J"∾e∾"[H" # Cursor to origin, hide it and clear screen
{𝕤⋄
Display board
{𝕤⋄•Out "You win!" ⋄ Quit 0}⍟Win board
{𝕤⋄•Out "You lose!"⋄ Quit 1}⍟Lose board
key←•term.CharB @ # Read key
⊑key∊"hjklq"? # Valid key?
{𝕤⋄ Quit 0}⍟(key='q')@ # Quit key?
move←⊑(key="hjkl")/Left‿Down‿Up‿Right # Get movement function from the key
{𝕤⋄board↩Spawn∘Move 𝕩}⍟(Move⊸≢) board # Generate the next board if the move is valid
; @
}•_While_{𝕤⋄1}@
</syntaxhighlight>
 
=={{header|C}}==
===Version 1===
Supports limited colours through vt100 escape codes. Requires a posix machine for <tt>termios.h</tt> and <tt>unistd.h</tt> headers. Provides simplistic animations when moving and merging blocks.
<syntaxhighlight lang="c">
<lang c>
#include <stdio.h>
#include <stdlib.h>
Line 1,372 ⟶ 4,374:
return 0;
}
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 1,389 ⟶ 4,391:
 
 
<syntaxhighlight lang="c">
<lang c>
 
#include <stdio.h>
Line 1,731 ⟶ 4,733:
return 0;
}
</syntaxhighlight>
</lang>
 
=={{header|C sharp|C#}}==
{{trans|C++}}
<langsyntaxhighlight lang="csharp">using System;
 
namespace g2048_csharp
Line 2,129 ⟶ 5,131:
}
}
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 2,149 ⟶ 5,151:
 
=={{header|C++}}==
<langsyntaxhighlight lang="cpp">
#include <time.h>
#include <iostream>
Line 2,343 ⟶ 5,345:
return system( "pause" );
}
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 2,362 ⟶ 5,364:
 
=={{header|Clojure}}==
<langsyntaxhighlight lang="clojure">
(ns 2048
(:require [clojure.string :as str]))
Line 2,481 ⟶ 5,483:
:default (recur (handle-turn field)))))
 
(play-2048)</langsyntaxhighlight>
 
{{out}}
Line 2,496 ⟶ 5,498:
=={{header|Common Lisp}}==
Depends on Windows msvcrt.dll for _getch. Depends on quicklisp. Use arrow keys to make moves and press "Q" to quit. Tested with SBCL.
<langsyntaxhighlight lang="lisp">(ql:quickload '(cffi alexandria))
 
(defpackage :2048-lisp
Line 2,696 ⟶ 5,698:
(format t "~% Score: ~D~%" score)
(print-board board 4)
(prompt-input board score))</langsyntaxhighlight>
{{out}}
<pre>* (2048-lisp::prompt)
Line 2,724 ⟶ 5,726:
=={{header|D}}==
{{trans|C++}}
<langsyntaxhighlight lang="d">import std.stdio, std.string, std.random;
import core.stdc.stdlib: exit;
 
struct G2048 {
public void gameLoop() /*@safe @nogc*/ {
addTile;
while (true) {
Line 2,742 ⟶ 5,744:
 
private:
static struct Tile {
uint val = 0;
bool blocked = false;
Line 2,754 ⟶ 5,756:
uint score = 0;
 
void drawBoard() const /*@safe @nogc*/ {
writeln("SCORE: ", score, "\n");
foreach (immutable y; 0 .. side) {
write("+------+------+------+------+\n| ");
foreach (immutable x; 0 .. side) {
if (board[x][y].val)
writef("%4d", board[x][y].val);
Line 2,767 ⟶ 5,769:
writeln;
}
writeln("+------+------+------+------+\n".writeln);
}
 
void waitKey() /*@safe*/ {
moved = false;
write("(W)Up (S)Down (A)Left (D)Right (Q)Quit: ".write);
immutableauto c = readln.strip.toLower;
 
switch (c) {
Line 2,784 ⟶ 5,786:
}
 
foreach (immutable y; 0 .. side)
foreach (immutable x; 0 .. side)
board[x][y].blocked = false;
}
Line 2,794 ⟶ 5,796:
}
 
void addTile() /*nothrow*/ @safe /*@nogc*/ {
foreach (immutable y; 0 .. side) {
foreach (immutable x; 0 .. side) {
if (!board[x][y].val) {
uint a, b;
Line 2,813 ⟶ 5,815:
}
 
bool canMove() const pure nothrow @safe @nogc {
foreach (immutable y; 0 .. side)
foreach (immutable x; 0 .. side)
if (!board[x][y].val)
return true;
 
foreach (immutable y; 0 .. side) {
foreach (immutable x; 0 .. side) {
if (testAdd(x + 1, y, board[x][y].val) ||
testAdd(x - 1, y, board[x][y].val) ||
Line 2,831 ⟶ 5,833:
}
 
bool testAdd(in uint x, in uint y, in uint v) const pure nothrow @safe @nogc {
if (x > 3 || y > 3)
return false;
Line 2,837 ⟶ 5,839:
}
 
void moveVertically(in uint x, in uint y, in uint d) pure nothrow @safe @nogc {
if (board[x][y + d].val && board[x][y + d].val == board[x][y].val &&
!board[x][y].blocked && !board[x][y + d].blocked) {
Line 2,860 ⟶ 5,862:
}
 
void moveHorizontally(in uint x, in uint y, in uint d) pure nothrow @safe @nogc {
if (board[x + d][y].val && board[x + d][y].val == board[x][y].val &&
!board[x][y].blocked && !board[x + d][y].blocked) {
Line 2,883 ⟶ 5,885:
}
 
void move(in moveDir d) pure nothrow @safe @nogc {
final switch (d) with(moveDir) {
case up:
foreach (immutable x; 0 .. side)
foreach (immutable y; 1 .. side)
if (board[x][y].val)
moveVertically(x, y, -1);
break;
case down:
foreach (immutable x; 0 .. side)
foreach_reverse (immutable y; 0 .. 3)
if (board[x][y].val)
moveVertically(x, y, 1);
break;
case left:
foreach (immutable y; 0 .. side)
foreach (immutable x; 1 .. side)
if (board[x][y].val)
moveHorizontally(x, y, -1);
break;
case right:
foreach (immutable y; 0 .. side)
foreach_reverse (immutable x; 0 .. 3)
if (board[x][y].val)
moveHorizontally(x, y, 1);
Line 2,915 ⟶ 5,917:
G2048 g;
g.gameLoop;
}</langsyntaxhighlight>
The output is the same as the C++ version.
 
=={{header|Delphi}}==
{{libheader| System.SysUtils}}
{{libheader| Velthuis.Console}}Thanks for Rudy Velthuis [https://github.com/rvelthuis/Consoles].
{{Trans|C++}}
<syntaxhighlight lang="delphi">
program Game2048;
 
{$APPTYPE CONSOLE}
 
uses
System.SysUtils,
System.Math,
Velthuis.Console;
 
type
TTile = class
Value: integer;
IsBlocked: Boolean;
constructor Create;
end;
 
TMoveDirection = (mdUp, mdDown, mdLeft, mdRight);
 
TG2048 = class
FisDone, FisWon, FisMoved: boolean;
Fscore: Cardinal;
FBoard: array[0..3, 0..3] of TTile;
function GetLine(aType: byte): string;
public
constructor Create;
destructor Destroy; override;
procedure InitializeBoard();
procedure FinalizeBoard();
procedure Loop;
procedure DrawBoard();
procedure WaitKey();
procedure AddTile();
function CanMove(): boolean;
function TestAdd(x, y, value: Integer): boolean;
procedure MoveHorizontally(x, y, d: integer);
procedure MoveVertically(x, y, d: integer);
procedure Move(direction: TMoveDirection);
end;
 
 
{ TTile }
 
constructor TTile.Create;
begin
Value := 0;
IsBlocked := false;
end;
 
{ TG2048 }
 
procedure TG2048.AddTile;
var
y, x, a, b: Integer;
r: Double;
begin
for y := 0 to 3 do
begin
for x := 0 to 3 do
begin
if Fboard[x, y].Value <> 0 then
continue;
repeat
a := random(4);
b := random(4);
until not (Fboard[a, b].Value <> 0);
r := Random;
if r > 0.89 then
Fboard[a, b].Value := 4
else
Fboard[a, b].Value := 2;
if CanMove() then
begin
Exit;
end;
end;
end;
FisDone := true;
end;
 
function TG2048.CanMove: boolean;
var
y, x: Integer;
begin
for y := 0 to 3 do
begin
for x := 0 to 3 do
begin
if Fboard[x, y].Value = 0 then
begin
Exit(true);
end;
end;
end;
for y := 0 to 3 do
begin
for x := 0 to 3 do
begin
if TestAdd(x + 1, y, Fboard[x, y].Value) or TestAdd(x - 1, y, Fboard[x, y].Value)
or TestAdd(x, y + 1, Fboard[x, y].Value) or TestAdd(x, y - 1, Fboard[x,
y].Value) then
begin
Exit(true);
end;
end;
end;
Exit(false);
end;
 
constructor TG2048.Create;
begin
FisDone := false;
FisWon := false;
FisMoved := true;
Fscore := 0;
InitializeBoard();
Randomize;
end;
 
destructor TG2048.Destroy;
begin
FinalizeBoard;
inherited;
end;
 
procedure TG2048.DrawBoard;
var
y, x: Integer;
color: byte;
lineFragment, line: string;
begin
ClrScr;
HighVideo;
writeln('Score: ', Fscore: 3, #10);
TextBackground(White);
TextColor(black);
for y := 0 to 3 do
begin
if y = 0 then
writeln(GetLine(0))
else
writeln(GetLine(1));
 
Write(' '#$2551' ');
for x := 0 to 3 do
begin
if Fboard[x, y].Value = 0 then
begin
Write(' ');
end
else
begin
color := Round(Log2(Fboard[x, y].Value));
TextColor(14 - color);
Write(Fboard[x, y].Value: 4);
TextColor(Black);
end;
Write(' '#$2551' ');
end;
writeln(' ');
end;
writeln(GetLine(2), #10#10);
TextBackground(Black);
TextColor(White);
end;
 
procedure TG2048.FinalizeBoard;
var
y, x: integer;
begin
for y := 0 to 3 do
for x := 0 to 3 do
FBoard[x, y].Free;
end;
 
function TG2048.GetLine(aType: byte): string;
var
fragment, line: string;
bgChar, edChar, mdChar: char;
begin
 
case aType of
0:
begin
bgChar := #$2554;
edChar := #$2557;
mdChar := #$2566;
end;
1:
begin
bgChar := #$2560;
edChar := #$2563;
mdChar := #$256C;
end;
 
2:
begin
bgChar := #$255A;
edChar := #$255D;
mdChar := #$2569;
end;
end;
fragment := string.create(#$2550, 6);
line := fragment + mdChar + fragment + mdChar + fragment + mdChar + fragment;
Result := ' '+bgChar + line + edChar + ' ';
end;
 
procedure TG2048.InitializeBoard;
var
y, x: integer;
begin
for y := 0 to 3 do
for x := 0 to 3 do
FBoard[x, y] := TTile.Create;
end;
 
procedure TG2048.Loop;
begin
AddTile();
while (true) do
begin
if (FisMoved) then
AddTile();
 
DrawBoard();
if (FisDone) then
break;
 
WaitKey();
end;
 
if FisWon then
Writeln('You''ve made it!')
else
Writeln('Game Over!');
end;
 
procedure TG2048.Move(direction: TMoveDirection);
var
x, y: Integer;
begin
case direction of
mdUp:
begin
for x := 0 to 3 do
begin
y := 1;
while y < 4 do
begin
if Fboard[x, y].Value <> 0 then
MoveVertically(x, y, -1);
Inc(y);
end;
end;
end;
mdDown:
begin
for x := 0 to 3 do
begin
y := 2;
while y >= 0 do
begin
if Fboard[x, y].Value <> 0 then
MoveVertically(x, y, 1);
Dec(y);
end;
end;
end;
mdLeft:
begin
for y := 0 to 3 do
begin
x := 1;
while x < 4 do
begin
if Fboard[x, y].Value <> 0 then
MoveHorizontally(x, y, -1);
Inc(x);
end;
end;
end;
mdRight:
begin
for y := 0 to 3 do
begin
x := 2;
while x >= 0 do
begin
if Fboard[x, y].Value <> 0 then
MoveHorizontally(x, y, 1);
Dec(x);
end;
end;
end;
end;
end;
 
procedure TG2048.MoveHorizontally(x, y, d: integer);
begin
if (FBoard[x + d, y].Value <> 0) and (FBoard[x + d, y].Value = FBoard[x, y].Value)
and (not FBoard[x + d, y].IsBlocked) and (not FBoard[x, y].IsBlocked) then
begin
FBoard[x, y].Value := 0;
FBoard[x + d, y].Value := FBoard[x + d, y].Value * 2;
Fscore := Fscore + (FBoard[x + d, y].Value);
FBoard[x + d, y].IsBlocked := true;
FisMoved := true;
end
else if ((FBoard[x + d, y].Value = 0) and (FBoard[x, y].Value <> 0)) then
begin
FBoard[x + d, y].Value := FBoard[x, y].Value;
FBoard[x, y].Value := 0;
FisMoved := true;
end;
if d > 0 then
begin
if x + d < 3 then
begin
MoveHorizontally(x + d, y, 1);
end;
end
else
begin
if x + d > 0 then
begin
MoveHorizontally(x + d, y, -1);
end;
end;
end;
 
procedure TG2048.MoveVertically(x, y, d: integer);
begin
if (Fboard[x, y + d].Value <> 0) and (Fboard[x, y + d].Value = Fboard[x, y].Value)
and (not Fboard[x, y].IsBlocked) and (not Fboard[x, y + d].IsBlocked) then
begin
Fboard[x, y].Value := 0;
Fboard[x, y + d].Value := Fboard[x, y + d].Value * 2;
Fscore := Fscore + (Fboard[x, y + d].Value);
Fboard[x, y + d].IsBlocked := true;
FisMoved := true;
end
else if ((Fboard[x, y + d].Value = 0) and (Fboard[x, y].Value <> 0)) then
begin
Fboard[x, y + d].Value := Fboard[x, y].Value;
Fboard[x, y].Value := 0;
FisMoved := true;
end;
if d > 0 then
begin
if y + d < 3 then
begin
MoveVertically(x, y + d, 1);
end;
end
else
begin
if y + d > 0 then
begin
MoveVertically(x, y + d, -1);
end;
end;
end;
 
function TG2048.TestAdd(x, y, value: Integer): boolean;
begin
if (x < 0) or (x > 3) or (y < 0) or (y > 3) then
Exit(false);
 
Exit(Fboard[x, y].value = value);
end;
 
procedure TG2048.WaitKey;
var
y, x: Integer;
begin
FisMoved := false;
writeln('(W) Up (S) Down (A) Left (D) Right (ESC)Exit');
case ReadKey of
'W', 'w':
Move(TMoveDirection.mdUp);
'A', 'a':
Move(TMoveDirection.mdLeft);
'S', 's':
Move(TMoveDirection.mdDown);
'D', 'd':
Move(TMoveDirection.mdRight);
#27:
FisDone := true;
end;
 
for y := 0 to 3 do
for x := 0 to 3 do
Fboard[x, y].IsBlocked := false;
end;
 
var
Game: TG2048;
begin
with TG2048.Create do
begin
Loop;
Free;
end;
Writeln('Press Enter to exit');
Readln;
end.</syntaxhighlight>
{{out}}
<pre>
Score: 6472
 
╔══════╦══════╦══════╦══════╗
║ 2 ║ 8 ║ 2 ║ 4 ║
╠══════╬══════╬══════╬══════╣
║ 16 ║ 64 ║ 8 ║ 64 ║
╠══════╬══════╬══════╬══════╣
║ 8 ║ 512 ║ 256 ║ 2 ║
╠══════╬══════╬══════╬══════╣
║ 2 ║ 4 ║ 16 ║ 4 ║
╚══════╩══════╩══════╩══════╝
 
 
Game Over!
Press Enter to exit
</pre>
=={{header|Elixir}}==
{{works with|Elixir|1.3}}
<langsyntaxhighlight lang="elixir">defmodule Game2048 do
@size 4
@range 0..@size-1
Line 3,034 ⟶ 6,464:
end
 
Game2048.play 512</langsyntaxhighlight>
 
{{out}}
Line 3,066 ⟶ 6,496:
{{works with|Elm 0.18.0}}
Try online [https://ellie-app.com/3ZMMpYsbfcMa1/3]
<langsyntaxhighlight Elmlang="elm">module Main exposing (..)
 
import Html exposing (Html, div, p, text, button, span, h2)
Line 3,468 ⟶ 6,898:
viewGrid model.tiles
]
</syntaxhighlight>
</lang>
 
=={{header|F Sharp|F#}}==
 
The following code can be executed as is using F# Interactive from system command line ("fsi.exe 2048.fsx") but not from Visual Studio F# Interactive window due to the way it access keyboard (the System.Console.ReadKey() function).
 
<langsyntaxhighlight lang="fsharp">
// the board is represented with a list of 16 integers
let empty = List.init 16 (fun _ -> 0)
Line 3,534 ⟶ 6,964:
 
play()
</syntaxhighlight>
</lang>
 
=={{header|Factor}}==
Line 3,549 ⟶ 6,979:
 
 
<syntaxhighlight lang="factor">
<lang>
USE: accessors
FROM: arrays => <array> array ;
Line 3,870 ⟶ 7,300:
 
MAIN: start-2048
</syntaxhighlight>
</lang>
 
=={{header|Forth}}==
Line 3,878 ⟶ 7,308:
Just like my implementation of [[15 Puzzle Game#Forth|15 Puzzle Game]], this uses Vim's h/j/k/l for movement.
 
<langsyntaxhighlight lang="forth">\ in Forth, you do many things on your own. This word is used to define 2D arrays
: 2D-ARRAY ( height width )
CREATE DUP ,
Line 4,112 ⟶ 7,542:
 
INIT
MAIN-LOOP</langsyntaxhighlight>
 
{{out}}
Line 4,139 ⟶ 7,569:
 
===Source===
The initial attempt at showing the board relied rather heavily on FORMAT tricks, in particular the use of the <''n''> facility whereby the value of an integer expression can be inserted into a format statement's coding on-the-fly, as in the following. <langsyntaxhighlight Fortranlang="fortran">
WRITE (MSG,1) !Roll forth a top/bottom boundary. No corner characters (etc.), damnit.
1 FORMAT ("|",<NC>(<W>("-"),"|")) !Heavy reliance on runtime values in NC and W. But see FORMAT 22.
Line 4,145 ⟶ 7,575:
WRITE (MSG,22) ((" ",L1 = 1,W),"|",C = 1,NC) !Compare to FORMAT 2.
22 FORMAT ("|",666A1) !A constant FORMAT, a tricky WRITE.
4 FORMAT ("|",<NC - 1>(<W>("-"),"+"),<W>("-"),"|") !With internal + rather than |.</langsyntaxhighlight>
This sort of thing is not necessarily accepted by all compilers, so instead the next stage was to convert to using complicated WRITE statements. If one regarded the various sizes (the values of NR, NC, W in the source) as truly fixed, literal constants could be used throughout. This would however mean that they would appear without explanation, and if one eventually attempted to recode with different values, mistakes would be likely. Thus below, FORMAT 3 has <code> (<NC>(A1,I<W>),A1)</code> and if the <> scheme were unavailable, you'd have to use <code>(4(A1,I6),A1)</code> instead, not too troublesome a change. Or, the text of the format sequence could be written to a CHARACTER variable, as demonstrated in [[Multiplication_tables#Traditional_approach]]. Yet another approach might be <code>(666(A1,I6))</code> which relies on the addendum <code>A1</code> happening to be the same as the start of the <code>(A1,I6)</code> pair, but there is still the appearance of the literal constant six instead of <W>, and if there were to be any change to be made, it would have to be remembered...
<langsyntaxhighlight Fortranlang="fortran"> SUBROUTINE SHOW(NR,NC,BOARD) !Mess about.
INTEGER NR,NC !Number of rows and columns.
INTEGER BOARD(NR,NC) !The board. Actual storage is transposed!
Line 4,337 ⟶ 7,767:
601 FORMAT ("None! Oh dear.") !Nothing more can be done.
END !That was fun.
</syntaxhighlight>
</lang>
 
===Output===
Line 4,390 ⟶ 7,820:
Move 2, score 6. Moves RULD ... Your move:
</pre>
 
=={{header|FreeBASIC}}==
Based On MichD's original code (https://github.com/michd/2048-qbasic)
<syntaxhighlight lang="freebasic">#define EXTCHAR Chr(255)
 
'--- Declaration of global variables ---
Dim Shared As Integer gGridSize = 4 'grid size (4 -> 4x4)
Dim Shared As Integer gGrid(gGridSize, gGridSize)
Dim Shared As Integer gScore
Dim Shared As Integer curX, curY
Dim Shared As Integer hasMoved, wasMerge
' Don't touch these numbers, seriously
Dim Shared As Integer gOriginX, gOriginY
gOriginX = 75 'pixel X of top left of grid
gOriginY = 12 'pixel Y of top right of grida
Dim Shared As Integer gTextOriginX, gTextOriginY, gSquareSide
gTextOriginX = 11
gTextOriginY = 3
gSquareSide = 38 'width/height of block in pixels
 
'set up all the things!
Dim Shared As Integer gDebug = 0
 
'--- SUBroutines and FUNCtions ---
Sub addblock
Dim As Integer emptyCells(gGridSize * gGridSize, 2)
Dim As Integer emptyCellCount = 0
Dim As Integer x, y, index, num
For x = 0 To gGridSize - 1
For y = 0 To gGridSize - 1
If gGrid(x, y) = 0 Then
emptyCells(emptyCellCount, 0) = x
emptyCells(emptyCellCount, 1) = y
emptyCellCount += 1
End If
Next y
Next x
If emptyCellCount > 0 Then
index = Int(Rnd * emptyCellCount)
num = Cint(Rnd + 1) * 2
gGrid(emptyCells(index, 0), emptyCells(index, 1)) = num
End If
End Sub
 
Function pad(num As Integer) As String
Dim As String strNum = Ltrim(Str(num))
Select Case Len(strNum)
Case 1: Return " " + strNum + " "
Case 2: Return " " + strNum + " "
Case 3: Return " " + strNum
Case 4: Return strNum
End Select
End Function
 
Sub drawNumber(num As Integer, xPos As Integer, yPos As Integer)
Dim As Integer c, x, y
Select Case num
Case 0: c = 16
Case 2: c = 2
Case 4: c = 3
Case 8: c = 4
Case 16: c = 5
Case 32: c = 6
Case 64: c = 7
Case 128: c = 8
Case 256: c = 9
Case 512: c = 10
Case 1024: c = 11
Case 2048: c = 12
Case 4096: c = 13
Case 8192: c = 13
Case Else: c = 13
End Select
x = xPos *(gSquareSide + 2) + gOriginX + 1
y = yPos *(gSquareSide + 2) + gOriginY + 1
Line(x + 1, y + 1)-(x + gSquareSide - 1, y + gSquareSide - 1), c, BF
If num > 0 Then
Locate gTextOriginY + 1 +(yPos * 5), gTextOriginX +(xPos * 5) : Print " "
Locate gTextOriginY + 2 +(yPos * 5), gTextOriginX +(xPos * 5) : Print pad(num)
Locate gTextOriginY + 3 +(yPos * 5), gTextOriginX +(xPos * 5)
End If
End Sub
 
Function getAdjacentCell(x As Integer, y As Integer, d As String) As Integer
If (d = "l" And x = 0) Or (d = "r" And x = gGridSize - 1) Or (d = "u" And y = 0) Or (d = "d" And y = gGridSize - 1) Then
getAdjacentCell = -1
Else
Select Case d
Case "l": getAdjacentCell = gGrid(x - 1, y)
Case "r": getAdjacentCell = gGrid(x + 1, y)
Case "u": getAdjacentCell = gGrid(x, y - 1)
Case "d": getAdjacentCell = gGrid(x, y + 1)
End Select
End If
End Function
 
'Draws the outside grid(doesn't render tiles)
Sub initGraphicGrid
Dim As Integer x, y, gridSide =(gSquareSide + 2) * gGridSize
Line(gOriginX, gOriginY)-(gOriginX + gridSide, gOriginY + gridSide), 14, BF 'outer square, 3 thick
Line(gOriginX, gOriginY)-(gOriginX + gridSide, gOriginY + gridSide), 1, B 'outer square, 3 thick
Line(gOriginX - 1, gOriginY - 1)-(gOriginX + gridSide + 1, gOriginY + gridSide + 1), 1, B
Line(gOriginX - 2, gOriginY - 2)-(gOriginX + gridSide + 2, gOriginY + gridSide + 2), 1, B
For x = gOriginX + gSquareSide + 2 To gOriginX +(gSquareSide + 2) * gGridSize Step gSquareSide + 2 ' horizontal lines
Line(x, gOriginY)-(x, gOriginY + gridSide), 1
Next x
For y = gOriginY + gSquareSide + 2 To gOriginY +(gSquareSide + 2) * gGridSize Step gSquareSide + 2 ' vertical lines
Line(gOriginX, y)-(gOriginX + gridSide, y), 1
Next y
End Sub
 
'Init the(data) grid with 0s
Sub initGrid
Dim As Integer x, y
For x = 0 To 3
For y = 0 To 3
gGrid(x, y) = 0
Next y
Next x
addblock
addblock
End Sub
 
Sub moveBlock(sourceX As Integer, sourceY As Integer, targetX As Integer, targetY As Integer, merge As Integer)
If sourceX < 0 Or sourceX >= gGridSize Or sourceY < 0 Or sourceY >= gGridSize And gDebug = 1 Then
Locate 0, 0 : Print "moveBlock: source coords out of bounds"
End If
If targetX < 0 Or targetX >= gGridSize Or targetY < 0 Or targetY >= gGridSize And gDebug = 1 Then
Locate 0, 0 : Print "moveBlock: source coords out of bounds"
End If
Dim As Integer sourceSquareValue = gGrid(sourceX, sourceY)
Dim As Integer targetSquareValue = gGrid(targetX, targetY)
If merge = 1 Then
If sourceSquareValue = targetSquareValue Then
gGrid(sourceX, sourceY) = 0
gGrid(targetX, targetY) = targetSquareValue * 2
gScore += targetSquareValue * 2 ' Points!
Elseif gDebug = 1 Then
Locate 0, 0 : Print "moveBlock: Attempted to merge unequal sqs"
End If
Else
If targetSquareValue = 0 Then
gGrid(sourceX, sourceY) = 0
gGrid(targetX, targetY) = sourceSquareValue
Elseif gDebug = 1 Then
Locate 0, 0 : Print "moveBlock: Attempted to move to non-empty block"
End If
End If
End Sub
 
Function pColor(r As Integer, g As Integer, b As Integer) As Integer
Return (r + g * 256 + b * 65536)
End Function
 
Sub moveToObstacle(x As Integer, y As Integer, direcc As String)
curX = x : curY = y
Do While getAdjacentCell(curX, curY, direcc) = 0
Select Case direcc
Case "l": curX -= 1
Case "r": curX += 1
Case "u": curY -= 1
Case "d": curY += 1
End Select
Loop
End Sub
 
Sub processBlock(x As Integer, y As Integer, direcc As String)
Dim As Integer merge = 0, mergeDirX, mergeDirY
If gGrid(x, y) <> 0 Then ' have block
moveToObstacle(x, y, direcc) ' figure out where it can be moved to
If getAdjacentCell(curX, curY, direcc) = gGrid(x, y) And wasMerge = 0 Then ' obstacle can be merged with
merge = 1
wasMerge = 1
Else
wasMerge = 0
End If
If curX <> x Or curY <> y Or merge = 1 Then
mergeDirX = 0
mergeDirY = 0
If merge = 1 Then
Select Case direcc
Case "l": mergeDirX = -1
Case "r": mergeDirX = 1
Case "u": mergeDirY = -1
Case "d": mergeDirY = 1
End Select
End If
moveBlock(x, y, curX + mergeDirX, curY + mergeDirY, merge) ' move to before obstacle or merge
hasMoved = 1
End If
End If
End Sub
 
Sub renderGrid
Dim As Integer x, y
For x = 0 To gGridSize - 1
For y = 0 To gGridSize - 1
drawNumber(gGrid(x, y), x, y)
Next y
Next x
End Sub
 
Sub updateScore
Locate 1, 10 : Print Using "Score: #####"; gScore
End Sub
 
Sub processMove(direcc As String) '' direcc can be 'l', 'r', 'u', or 'd'
Dim As Integer x, y
hasMoved = 0
If direcc = "l" Then
For y = 0 To gGridSize - 1
wasMerge = 0
For x = 0 To gGridSize - 1
processBlock(x,y,direcc)
Next x
Next y
Elseif direcc = "r" Then
For y = 0 To gGridSize - 1
wasMerge = 0
For x = gGridSize - 1 To 0 Step -1
processBlock(x,y,direcc)
Next x
Next y
Elseif direcc = "u" Then
For x = 0 To gGridSize - 1
wasMerge = 0
For y = 0 To gGridSize - 1
processBlock(x,y,direcc)
Next y
Next x
Elseif direcc = "d" Then
For x = 0 To gGridSize - 1
wasMerge = 0
For y = gGridSize - 1 To 0 Step -1
processBlock(x,y,direcc)
Next y
Next x
End If
If hasMoved = 1 Then addblock
renderGrid
updateScore
End Sub
 
 
'--- Main Program ---
Screen 8
Windowtitle "2048"
Palette 1, pColor(35, 33, 31)
Palette 2, pColor(46, 46, 51)
Palette 3, pColor(59, 56, 50)
Palette 4, pColor(61, 44, 30)
Palette 5, pColor(61, 37, 25)
Palette 6, pColor(62, 31, 24)
Palette 7, pColor(62, 24, 15)
Palette 8, pColor(59, 52, 29)
Palette 9, pColor(59, 51, 24)
Palette 10, pColor(59, 50, 20)
Palette 11, pColor(59, 49, 16)
Palette 12, pColor(59, 49, 12)
Palette 13, pColor(15, 15, 13)
Palette 14, pColor(23, 22, 20)
 
Randomize Timer
Cls
Do
initGrid
initGraphicGrid
renderGrid
updateScore
gScore = 0
Locate 23, 10 : Print "Move with arrow keys."
Locate 24, 12 : Print "(R)estart, (Q)uit"
Dim As String k
Do
Do
k = Inkey
Loop Until k <> ""
Select Case k
Case EXTCHAR + Chr(72) 'up
processMove("u")
Case EXTCHAR + Chr(80) 'down
processMove("d")
Case EXTCHAR + Chr(77) 'right
processMove("r")
Case EXTCHAR + Chr(75) 'left
processMove("l")
Case "q", "Q", Chr(27) 'escape
End
Case "r", "R"
Exit Do
End Select
Loop
Loop</syntaxhighlight>
 
 
=={{header|FutureBasic}}==
<syntaxhighlight lang="futurebasic">
begin enum 123
_lf
_rt
_dn
_up
_new
_end
end enum
str63 bd
colorref color(11)
byte zs
 
void local fn initialize
subclass window 1, @"2048",(0,0,438,438)
fn WindowSetBackgroundColor( 1, fn ColorBlack )
color(0) = fn ColorDarkGray
color(1) = fn ColorGray
color(2) = fn ColorLightGray
color(3) = fn ColorBlue
color(4) = fn ColorBrown
color(5) = fn ColorCyan
color(6) = fn ColorGreen
color(7) = fn ColorMagenta
color(8) = fn ColorOrange
color(9) = fn ColorPurple
color(10) = fn ColorYellow
color(11) = fn ColorRed
end fn
 
void local fn drawBoard
int x, y,r = 1, add
cls
for y = 320 to 20 step -100
for x = 20 to 320 step 100
rect fill (x,y,98,98),color( bd[r] )
select bd[r]
case < 4 : add = 40
case < 7 : add = 30
case < 10 : add = 20
case else : add = 6
end select
if bd[r] then print %(x+add, y+25)2^bd[r]
r++
next
next
end fn
 
local fn finish( won as bool )
CFStringRef s = @"GAME OVER"
CGRect r = fn windowContentRect( 1 )
r.origin.y += r.size.height - 20
r.size.height = 100
window 2,,r,NSwindowStyleMaskBorderless
if won
fn windowSetBackgroundColor( 2, color(11) )
s = @"CONGRATULATIONS—YOU DID IT!!"
text,24,fn ColorBlack,,NSTextAlignmentCenter
else
fn windowSetBackgroundColor( 2, fn ColorBlack )
text,24,fn ColorWhite,,NSTextAlignmentCenter
end if
print s
button _new,,,@"New Game", (229,20,100,32)
button _end,,,@"Quit", (109,20,100,32)
end fn
 
void local fn newGame
int r
text @"Arial bold", 36, fn ColorBlack, fn ColorClear
bd = chr$(0)
for r = 1 to 4
bd += bd
next
bd[rnd(16)] ++
do
r = rnd(16)
until bd[r] == 0
bd[r]++
zs = 14
fn drawBoard
end fn
 
local fn play( st as short, rd as short, cd as short )
short a, b, c, t, moved = 0
for a = st to st + rd * 3 step rd
// SHIFT
t = a
for b = a to a + cd * 3 step cd
if bd[b]
if t <> b then swap bd[t], bd[b] : moved ++
t += cd
end if
next
// MERGE
for b = a to a + cd * 2 step cd
if bd[b] > 0 && bd[b] == bd[b+cd]
bd[b]++ : c = b + cd
// FILL IN
while c <> a+cd*3
bd[c] = bd[c+cd] : c += cd
wend
bd[c] = 0
// CHECK FOR WIN
if bd[b] == 11 then fn drawBoard : fn finish( yes ) : exit fn
zs ++ : moved ++
end if
next
next
fn drawBoard
if moved == 0 then exit fn
// GROW
b = 0 : c = rnd(zs)
while c
b ++
if bd[b] == 0 then c--
wend
if rnd(10) - 1 then bd[b]++ else bd[b] = 2
zs--
timerbegin 0.25
fn drawBoard
timerend
if zs then exit fn
// IS GAME OVER?
for a = 1 to 12
if bd[a] == bd[a+4] then exit fn
next
for a = 1 to 13 step 4
if bd[a] == bd[a+1] || bd[a+1] == bd[a+2] || bd[a+2] == bd[a+3]¬
then exit fn
next
fn finish( no )
end fn
 
local fn doDialog(ev as long,tag as long, wnd as long)
select ev
case _windowKeyDown : if window() == 2 then exit fn
select fn EventKeyCode
case _up : fn play(13, 1, -4)
case _dn : fn play( 1, 1, 4)
case _lf : fn play( 1, 4, 1)
case _rt : fn play( 4, 4, -1)
case else : exit fn
end select
DialogEventSetBool(yes)
case _btnClick : window close 2
if tag == _end then end
fn newGame
case _windowWillClose : if wnd == 1 then end
end select
end fn
 
fn initialize
fn newGame
on dialog fn doDialog
 
handleevents
</syntaxhighlight>
[[File:FutureBasic 2048.png]]
 
=={{header|Go}}==
 
<langsyntaxhighlight Golang="go">package main
 
import (
Line 4,662 ⟶ 8,573:
}
}
</syntaxhighlight>
</lang>
 
=={{header|Haskell}}==
<langsyntaxhighlight lang="haskell">import System.IO
import Data.List
import Data.Maybe
Line 4,797 ⟶ 8,708:
setCursorPosition 1 1
putStrLn $ intercalate "\n\n\n\ESC[C" $ concatMap showTile `map` pos
</syntaxhighlight>
</lang>
 
=={{header|J}}==
'''Solution'''
<langsyntaxhighlight lang="j">NB. 2048.ijs script
NB. =========================================================
NB. 2048 game engine
Line 4,906 ⟶ 8,817:
- start a new game:
grd=: g2048Con ''
)</langsyntaxhighlight>
'''Usage'''
<langsyntaxhighlight lang="j"> grd=: g2048Con ''
 
Score is 0
Line 4,927 ⟶ 8,838:
0 0 4 4
0 0 0 2
...</langsyntaxhighlight>
 
=={{header|Java}}==
[[File:game_2048_java2.png|300px|thumb|right]]
{{works with|Java|8}}
<langsyntaxhighlight lang="java">import java.awt.*;
import java.awt.event.*;
import java.util.Random;
Line 5,229 ⟶ 9,140:
return -1;
}
}</langsyntaxhighlight>
 
=={{header|JavaScript}}==
Uses the P5.js library.
<syntaxhighlight lang="javascript">
<lang JavaScript>
/* Tile object: */
 
Line 5,413 ⟶ 9,324:
game.keyHandler(keyCode);
}
</syntaxhighlight>
</lang>
 
=={{header|Julia}}==
Uses the Gtk toolkit. Includes scoring, a choice of board size and toolbar buttons for Undo and New Game.
<syntaxhighlight lang="julia">using Gtk.ShortNames
<lang julia>
using Gtk.ShortNames
 
@enum Direction2048 Right Left Up Down
Line 5,498 ⟶ 9,408:
toolbar = Toolbar()
newgame = ToolButton("New Game")
setpropertyset_gtk_property!(newgame, :label, "New Game")
setpropertyset_gtk_property!(newgame, :is_important, true)
undomove = ToolButton("Undo Move")
setpropertyset_gtk_property!(undomove, :label, "Undo Move")
setpropertyset_gtk_property!(undomove, :is_important, true)
map(w->push!(toolbar,w),[newgame,undomove])
grid = Grid()
map(w -> push!(box, w),[toolbar, grid])
buttons = Array{Gtk.GtkButtonLeaf,2}(undef, bsize, bsize)
for i in 1:bsize, j in 1:bsize
grid[i,j] = buttons[i,j] = Button()
setpropertyset_gtk_property!(buttons[i,j], :expand, true)
end
board = zeros(Int, (bsize,bsize))
Line 5,520 ⟶ 9,430:
function update!()
for i in 1:bsize, j in 1:bsize
label = (board[i,j] > 0) ? board[i,j] : " "
setpropertyset_gtk_property!(buttons[i,j], :label, label)
end
setpropertyset_gtk_property!(win, :title, "$won 2048 Game (Score: $score)")
end
function newrandomtile!()
Line 5,544 ⟶ 9,454:
for i in 1:bsize, j in 1:bsize
board[i,j] = 0
setpropertyset_gtk_property!(buttons[i,j], :label, " ")
end
newrandomtile!()
Line 5,581 ⟶ 9,491:
signal_connect(undo!,undomove, :clicked)
signal_connect(endit, win, :destroy)
signal_connect(keypress, win, "key-press-event")
Gtk.showall(win)
wait(condition)
end
Line 5,589 ⟶ 9,499:
const boardsize = 4
app2048(boardsize)
</syntaxhighlight>
</lang>
 
=={{header|Koka}}==
Based on F#
<syntaxhighlight lang="koka">
import std/num/random
import std/os/readline
 
val empty = list(0, 15).map(fn(_) 0)
fun win(l)
l.any(fn(x) x == 2048)
 
fun stack(l)
match l
Cons(0, tl) -> tl.stack ++ [0]
Cons(hd, tl) -> Cons(hd, tl.stack)
Nil -> Nil
 
fun join(l: list<int>)
match l
Cons(a, Cons(b, c)) | a == b -> Cons((a + b), c.join) ++ [0]
Cons(a, b) -> Cons(a, b.join)
Nil -> Nil
 
fun hit(l)
l.stack.join
 
fun hitBack(l)
l.reverse.hit.reverse
 
fun splitBy(l: list<a>, i: int): div list<list<a>>
val (a, b) = l.split(i)
match b
Cons -> Cons(a, b.splitBy(i))
Nil -> Cons(a, Nil)
 
fun transpose(l: list<list<a>>): <exn> list<list<a>>
match l
Cons(Cons(a, b), c) -> Cons(Cons(a, c.map(fn(x) x.head.unjust)), transpose(Cons(b, c.map(fn(x) x.tail)).unsafe-decreasing))
Cons(Nil, b) -> transpose(b)
Nil -> Nil
 
fun rows(l)
l.splitBy(4)
 
fun left(l)
l.rows.map(hit).concat
 
fun right(l)
l.rows.map(hitBack).concat
 
fun up(l)
l.rows.transpose.map(hit).transpose.concat
 
fun down(l)
l.rows.transpose.map(hitBack).transpose.concat
 
fun (==)(l1: list<int>, l2: list<int>): bool
match l1
Cons(a, b) -> match l2
Cons(c, d) -> a == c && b == d
Nil -> False
Nil -> match l2
Cons -> False
Nil -> True
 
fun lose(l)
l.left == l && l.right == l && l.up == l && l.down == l
 
fun numZeros(l: list<int>): int
l.filter(fn(x) x == 0).length
 
fun insert(l: list<int>, what: int, toWhere: int)
match l
Cons(0, tail) | tail.numZeros == toWhere -> Cons(what, tail)
Cons(head, tail) -> Cons(head, tail.insert(what, toWhere))
Nil -> Nil
 
fun spawnOn(l)
val newTileValue = if random-int() % 10 == 0 then 4 else 2
val newPosition = random-int() % (l.numZeros - 1)
l.insert(newTileValue, newPosition)
 
fun show-board(l: list<int>): div string
"\n" ++ l.rows.map(fn(r) r.map(fn(x) x.show.pad-left(4)).join("")).intersperse("\n").join("") ++ "\n"
 
fun quit(l)
[]
 
fun quitted(l)
l.is-nil
 
fun dispatch(c)
match c
'i' -> up
'j' -> left
'k' -> down
'l' -> right
'q' -> quit
_ ->
println("Unknown command: keys are ijkl to move, q to quit")
id
 
fun key()
readline().head-char.default('_')
 
fun turn(l)
l.show-board.println
val next = dispatch(key())(l)
if !(next == l) && next.quitted.not then
spawnOn(next)
else
next
 
fun play(state)
if state.win || state.lose || state.quitted then
if state.quitted then
"You quit!".println
else if state.win then
"You won!".println
else
"You lost!".println
else
"play".println
play(turn(state))
 
fun main()
print("ijkl to move, q to quit\n")
val initial = empty.spawnOn
println("Starting game...")
play(initial)
 
</syntaxhighlight>
 
=={{header|Kotlin}}==
Stateless with focus on clarity rather than conciseness.
 
<langsyntaxhighlight lang="scala">import java.io.BufferedReader
import java.io.InputStreamReader
 
Line 5,763 ⟶ 9,805:
}
println("+----+----+----+----+")
}</langsyntaxhighlight>
 
Sample output:
Line 5,784 ⟶ 9,826:
Takes input on stdin using the words "left", "right", "up", "down".
 
<syntaxhighlight lang="latitude">
<lang Latitude>
use 'format import '[format].
use 'random.
Line 6,011 ⟶ 10,053:
$stdout putln: "Better luck next time!".
}.
</syntaxhighlight>
</lang>
 
Sample output:
Line 6,024 ⟶ 10,066:
+----+----+----+----+
Your move (left, right, up, down)></pre>
 
=={{header|Lua}}==
Sadly, ANSI C doesn't have low-level keyboard input, so neither does vanilla Lua, so the input is a bit cumbersome (wasd PLUS enter).
<syntaxhighlight lang="lua">-- 2048 for Lua 5.1-5.4, 12/3/2020 db
local unpack = unpack or table.unpack -- for 5.3 +/- compatibility
game = {
cell = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
best = 0,
draw = function(self)
local t = self.cell
print("+----+----+----+----+")
for r=0,12,4 do
print(string.format("|%4d|%4d|%4d|%4d|\n+----+----+----+----+",t[r+1],t[r+2],t[r+3],t[r+4]))
end
end,
incr = function(self)
local t,open = self.cell,{}
for i=1,16 do if t[i]==0 then open[#open+1]=i end end
t[open[math.random(#open)]] = math.random()<0.1 and 4 or 2
end,
pack = function(self,ofr,oto,ost,ifr,ito,ist)
local t = self.cell
for outer=ofr,oto,ost do
local skip = 0
for inner=ifr,ito,ist do
local i = outer+inner
if t[i]==0 then skip=skip+1 else if skip>0 then t[i-skip*ist],t[i],self.diff = t[i],0,true end end
end
end
end,
comb = function(self,ofr,oto,ost,ifr,ito,ist)
local t = self.cell
for outer=ofr,oto,ost do
for inner=ifr,ito-ist,ist do
local i,j = outer+inner,outer+inner+ist
if t[i]>0 and t[i]==t[j] then t[i],t[j],self.diff,self.best = t[i]*2,0,true,math.max(self.best,t[i]*2) end
end
end
end,
move = function(self,dir)
local loopdata = {{0,12,4,1,4,1},{0,12,4,4,1,-1},{1,4,1,0,12,4},{1,4,1,12,0,-4}}
local ofr,oto,ost,ifr,ito,ist = unpack(loopdata[dir])
self:pack(ofr,oto,ost,ifr,ito,ist)
self:comb(ofr,oto,ost,ifr,ito,ist)
self:pack(ofr,oto,ost,ifr,ito,ist)
end,
full = function(self)
local t = self.cell
for r=0,12,4 do
for c=1,4 do
local i,v = r+c,t[r+c]
if (v==0) or (c>1 and t[i-1]==v) or (c<4 and t[i+1]==v) or (r>0 and t[i-4]==v) or (r<12 and t[i+4]==v) then
return false
end
end
end
return true
end,
play = function(self)
math.randomseed(os.time())
self:incr()
self:incr()
while true do
self:draw()
if self.best==2048 then print("WIN!") break end
if self:full() then print("LOSE!") break end
io.write("Your move (wasd + enter, or q + enter to quit): ")
local char = io.read()
self.diff = false
if (char=="a") then self:move(1)
elseif (char=="d") then self:move(2)
elseif (char=="w") then self:move(3)
elseif (char=="s") then self:move(4)
elseif (char=="q") then break end
if self.diff then self:incr() end
end
end
}
game:play()</syntaxhighlight>
{{out}}
<pre>+----+----+----+----+
| 2| 0| 0| 0|
+----+----+----+----+
| 4| 0| 0| 0|
+----+----+----+----+
| 2| 2| 16| 4|
+----+----+----+----+
| 4| 32| 64| 128|
+----+----+----+----+
Your move (wasd + enter, or q + enter to quit):</pre>
 
=={{header|M2000 Interpreter}}==
<syntaxhighlight lang="m2000 interpreter">
<lang M2000 Interpreter>
Module Game2048 {
\\ 10% 4 and 90% 2
Line 6,150 ⟶ 10,282:
}
Game2048
</syntaxhighlight>
</lang>
 
Each move copied to clipboard
Line 6,182 ⟶ 10,314:
 
Next is the main body of code:
<syntaxhighlight lang="maple">
<lang Maple>
macro(SP=DocumentTools:-SetProperty, GP=DocumentTools:-GetProperty);
G := module()
Line 6,402 ⟶ 10,534:
end module;
G:-reset();SP("Score/Lose",caption,"Click an Arrow to begin.");
</syntaxhighlight>
</lang>
 
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">SetOptions[InputNotebook[],NotebookEventActions->{
"LeftArrowKeyDown":>(stat=Coalesce[stat];AddNew[]),
"RightArrowKeyDown":>(stat=Reverse/@Coalesce[Reverse/@stat];AddNew[]),
"UpArrowKeyDown":>(stat=Coalesce[stat\[Transpose]]\[Transpose];AddNew[]),
"DownArrowKeyDown":>(stat=(Reverse/@(Coalesce[Reverse/@(stat\[Transpose])]))\[Transpose];AddNew[])
}
];
 
n=4;
bgcolor=GrayLevel[0.84];
colorfunc=Blend[{{0,Gray},{1/2,Red},{1,Blend[{Yellow,Orange}]}},#]&;
 
ClearAll[AddNew,PrintStat,Coalesce,SubCoalesce,AddRandomNumber]
AddNew[]:=(stat=AddRandomNumber[stat])
PrintStat[stat_]:=Module[{gr1,gr2,gr3,dr=0.2,cols,nstat=stat,positions},
gr1={bgcolor,Rectangle[-dr{1,1},n+dr{1,1},RoundingRadius->dr]};
cols=Map[If[#==0,0,Log2[#]]&,nstat,{2}];
cols=Map[If[#==0,Lighter@bgcolor,colorfunc[#/Max[cols]]]&,cols,{2}];
positions=Table[{i,n-j+1},{j,n},{i,n}];
gr2=MapThread[{#2,Rectangle[#3-{1,1}(1-dr/3),#3-{1,1}dr/3,RoundingRadius->dr/2]}&,{stat,cols,positions},2];
gr3=MapThread[If[#1>0,Style[Text[#1,#2-0.5{1,1}],20,White],{}]&,{stat,positions},2];
Graphics[{gr1,gr2,gr3},PlotRange->{{-0.5,n+0.5},{-0.5,n+0.5}},ImageSize->500]
]
Coalesce[stat_]:=SubCoalesce/@stat
SubCoalesce[statlist_]:=Module[{st=statlist,n=Length[statlist],pairs},
st=Split[DeleteCases[st,0]];
st=Partition[#,2,2,1,{}]&/@st;
st=Map[If[Length[#]==2,Total[#],#]&,st,{2}];
Join[Flatten[st],ConstantArray[0,n-Length[Flatten[st]]]]
]
AddRandomNumber[stat_,n_:2]:=With[{pos=Position[stat,0,{2}]},If[Length[pos]>0,ReplacePart[stat,RandomChoice[pos]->n],stat]]
 
stat=Nest[AddRandomNumber[#,RandomChoice[{2,4}]]&,ConstantArray[0,{n,n}],4];
Dynamic[PrintStat@stat]</syntaxhighlight>
 
 
=={{header|MATLAB}}==
 
<langsyntaxhighlight MATLABlang="matlab">function field = puzzle2048(field)
 
if nargin < 1 || isempty(field)
Line 6,537 ⟶ 10,707:
vector(vector==0) = [];
 
end</langsyntaxhighlight>
 
You can start with an empty 4 x 4 board and save the last state of the playing field with:
<langsyntaxhighlight MATLABlang="matlab">field = puzzle2048();</langsyntaxhighlight>
 
Or you start from a saved playing field:
<langsyntaxhighlight MATLABlang="matlab">field = puzzle2048(savedField);</langsyntaxhighlight>
 
=={{header|Nim}}==
Line 6,549 ⟶ 10,719:
{{works with|Nim Compiler|0.19.4}}
 
<langsyntaxhighlight lang="nim">import random, strutils, terminal
 
const
Line 6,733 ⟶ 10,903:
for i in 1..BoardLength + 7:
eraseLine()
cursorUp()</langsyntaxhighlight>
 
=={{header|OCaml}}==
 
<langsyntaxhighlight lang="ocaml">
let list_make x v =
let rec aux acc i =
Line 6,886 ⟶ 11,056:
loop grid
in
loop grid</langsyntaxhighlight>
 
{{out}}
Line 6,925 ⟶ 11,095:
</pre>
 
=={{header|PhixPascal}}==
<syntaxhighlight lang="pascal">
{{libheader|Phix/pGUI}}
program game2048;
Faithful desktop gui reproduction of the above link (https://gabrielecirulli.github.io/2048/)
uses Crt;
Now I just got figure out how to win...
const
<lang Phix>--
SIZE_MAP = 4;
-- demo\rosetta\2048.exw
SIZETOPBOT = SIZE_MAP*6+6; (* Calculate the length of the top and bottom to create a box around the game *)
--
NOTHING = 0;
include pGUI.e
UP = 93;
RIGHT = 92;
LEFT = 91;
DOWN = 90;
type
type_vector = array [1..SIZE_MAP] of integer;
type_game = record
lin,col:integer;
map: array [1..SIZE_MAP,1..SIZE_MAP] of integer;
score:integer;
end;
type_coord = record
lin,col:integer;
end;
 
var
Ihandle canvas, dialog
game:type_game;
cdCanvas cddbuffer, cdcanvas
end_game,movement:boolean;
 
procedure Create_Number(var game:type_game);
constant tile_colours = {#CCC0B4, -- blank
(* Create the number(2 or 4) in a random position on the map *)
#EEE4DA, -- 2
(* The number 4 had a 10% of chance to be created *)
#EDE0C8, -- 4
var
#F2B179, -- 8
number:integer;
#F59563, -- 16
RanP:type_coord;
#F67C5F, -- 32
begin
#F65E3B, -- 64
randomize;
#EDCF72, -- 128
if random(9) = 1 then
#EDCC61, -- 256
number:=4
#EDC850, -- 512
else
#EDC53F, -- 1024
number:=2;
#EDC22E} -- 2048
RanP.lin:=random(game.lin)+1;
RanP.col:=random(game.col)+1;
while game.map[RanP.lin,RanP.col] <> NOTHING do
begin
RanP.lin:=random(game.lin)+1;
RanP.col:=random(game.col)+1;
end;
game.map[RanP.lin,Ranp.Col]:=number;
end;
 
procedure initializing_game(var game:type_game);
-- the 4x4 board.
var i,j:integer;
-- note that values are [1..12] for [blank,2,4,8,..2048].
begin
-- (merging two eights is not 8+8->16 but 4+1->5, internally)
game.lin:=SIZE_MAP;
sequence board
game.col:=SIZE_MAP;
game.score:=0;
for i:=1 to game.lin do
for j:=1 to game.col do
game.map[i,j]:=NOTHING;
 
Create_Number(game);
integer newgame = 1
Create_Number(game);
end;
 
function CountDigit(number:integer):integer;
procedure add_rand(integer count)
begin
-- (nb infinite loop if board is full)
if number <> 0 then
integer x, y
begin
while count do
CountDigit:=0;
x = rand(4)
while number <> 0 y = rand(4)do
begin
if board[y][x]=1 then -- blank
CountDigit:=CountDigit+1;
board[y][x] = 2+(rand(10)=10)
number:=number div 10;
count -= 1
end if;
end
end while
else
end procedure
CountDigit:=1;
end;
 
procedure print_number(number:integer);
integer valid = 0
(* Print the number aligned with other numbers in the matrix *)
integer prev, nxt, bxy
var k,hwdigit:integer;
begin
hwdigit:=CountDigit(number);
write(' ');
write(number);
(* The 4 is used to aling the numbers because the greatest number *)
(* possible is 2048, which have 4 digits *)
for k:=1 to 4-hwdigit do
write(' ');
write(' ');
end;
 
procedure move_xprint_line(lengthL:integer; x, integer y, integer dch:string);
var i:integer;
bxy = board[x][y]
begin
if bxy!=1 then
write('+');
if bxy=prev then
for i:=1 to (lengthL-2) do
board[x][y] = 1
begin
bxy += 1
if i mod 7 = 0 board[x][nxt] = bxythen
write('+')
nxt += d
else
prev = 13
write(ch);
valid = 1
elseend;
writeln;
if prev=1
end;
or y!=nxt then
if prev!=1
and prev!=13 then
nxt += d
end if
if y!=nxt then
board[x][y] = 1
board[x][nxt] = bxy
valid = 1
end if
end if
prev = bxy
end if
end if
end procedure
 
procedure move_yprint_map(integervar x, integer y, integer dgame:type_game);
var i,j:integer;
bxy = board[x][y]
begin
if bxy!=1 then
print_line(SIZETOPBOT,'-');
if bxy=prev then
for i:=1 to game.lin do
board[x][y] = 1
begin
bxy += 1
write('|');
board[nxt][y] = bxy
for j:=1 to game.col nxt += ddo
if game.map[i,j] >= 0 then
prev = 13
begin
valid = 1
print_number(game.map[i,j]);
else
write('|');
if prev=1
end;
or x!=nxt then
writeln;
if prev!=1
print_line(SIZETOPBOT,'-');
and prev!=13 then
end;
nxt += d
end;
end if
if x!=nxt then
board[x][y] = 1
board[nxt][y] = bxy
valid = 1
end if
end if
prev = bxy
end if
end if
end procedure
 
function CanMove(var v_lin:type_vector; i:integer):integer;
function move(integer key)
(* Returns 1 if the next position is free *)
-- a non-zero result means it changed something.
(* Returns 2 if the next position has an equal number *)
valid = 0
(* Returns 0 if the next position is not free *)
if key=K_LEFT then
begin
for x=1 to 4 do
if v_lin[i-1] = NOTHING then
prev = 13
nxt CanMove:= 1
else if v_lin[i] = for y=v_lin[i-1] to 4 dothen
move_x(x,y,+1)CanMove:=2
end forelse
end forCanMove:=0;
end;
elsif key=K_UP then
for y=1 to 4 do
prev = 13
nxt = 4
for x=4 to 1 by -1 do
move_y(x,y,-1)
end for
end for
elsif key=K_RIGHT then
for x=1 to 4 do
prev = 13
nxt = 4
for y=4 to 1 by -1 do
move_x(x,y,-1)
end for
end for
elsif key=K_DOWN then
for y=1 to 4 do
prev = 13
nxt = 1
for x=1 to 4 do
move_y(x,y,+1)
end for
end for
end if
return valid
end function
 
function MoveAndSum(var game:type_game; var v_lin:type_vector; size:integer):boolean;
function game_won()
(* Move and Sum the elements of the vector *)
for i=1 to length(board) do
(* The direction of the move is to the left *)
if find(12,board[i]) then return 1 end if
(* Returns TRUE if a number was moved *)
end for
(* Returns FALSE if a number was not moved *)
return 0
var
end function
i,e,ResultM:integer;
v:type_vector;
begin
MoveAndSum:=FALSE;
(* Initializing the vector *)
(* This Vector is to know what number sum and what not sum *)
for i:=1 to size do
v[i]:=0;
 
for i:=2 to size do
constant valid_keys = {K_LEFT,K_DOWN,K_RIGHT,K_UP}
begin
if v_lin[i] <> 0 then
begin
(* Move the number in v_lin[i] to the left as much as possible *)
e:=i;
ResultM:=CanMove(v_lin,e);
while (ResultM <> 0)and(e>1) do
begin
case ResultM of
1:begin
v_lin[e-1]:=v_lin[e];
v_lin[e]:=NOTHING;
end;
2:begin
if v[e] = 0 then
begin
v_lin[e-1]:=v_lin[e-1]*2;
game.score:=game.score+v_lin[e-1];
v_lin[e]:=NOTHING;
(* This number will not be sum again *)
v[e-1]:=1;
end;
end;
end;
e:=e-1;
ResultM:=CanMove(v_lin,e);
end;
if e <> i then
MoveAndSum:=TRUE;
v[e-1]:=1;
end;
end;
end;
 
function no_valid_moves()
sequence saved_board = board
for i=1 to length(valid_keys) do
if move(valid_keys[i]) then
board = saved_board
return 0 -- OK
end if
end for
return 1 -- game over...
end function
 
function move_left(var game:type_game):boolean;
function redraw_cb(Ihandle /*ih*/, integer /*posx*/, integer /*posy*/)
var
integer tx, ty, bxy,
i,j:integer;
ox,oy, -- top right coords
v:type_vector;
os,ts, -- overall and tile size
begin
ts2 -- half tile, for number positioning
move_left:=FALSE;
integer {dw,dh} = IupGetIntInt(canvas, "DRAWSIZE")
iffor dw>i:=dh1 thento game.lin do
begin
ox = floor((dw-dh)/2)
for j:=1 to game.col oy = 0do
v[j]:=game.map[i,j];
os = dh
else
ox = 0
oy = floor((dh-dw)/2)
os = dw
end if
ts = floor((os-10)/4-7)
ts2 = floor(ts/2+5)-10
 
if newgameMoveAndSum(game,v,game.lin) then
move_left:=TRUE;
board = repeat(repeat(1,4),4)
add_rand(2)
newgame = 0
end if
 
for j:=1 to game.col do
cdCanvasActivate(cddbuffer)
game.map[i,j]:=v[j];
cdCanvasSetBackground(cddbuffer, #FAF8EF)
end;
cdCanvasClear(cddbuffer)
end;
cdCanvasSetForeground(cddbuffer, #BBADA0)
cdCanvasRoundedBox(cddbuffer, ox+5, ox+os-5, oy+5, oy+os-5, 10, 10)
 
tx = ox+15
for y=1 to 4 do
ty = oy+15
for x=1 to 4 do
bxy = board[x][y]
cdCanvasSetForeground(cddbuffer, tile_colours[bxy])
cdCanvasRoundedBox(cddbuffer, tx, tx+ts-10, ty, ty+ts-10, 5, 5)
if bxy>1 then
cdCanvasSetForeground(cddbuffer, iff(bxy<=3?#776E65:#F9F6F2))
cdCanvasFont(cddbuffer, "Calibri", CD_BOLD, iff(bxy>10?32:40))
cdCanvasText(cddbuffer, tx+ts2, ty+ts2-25-iff(bxy<11?7:0), sprint(power(2,bxy-1)))
end if
ty += ts+5
end for
tx += ts+5
end for
cdCanvasFlush(cddbuffer)
return IUP_DEFAULT
end function
 
function map_cbmove_right(Ihandlevar ihgame:type_game):boolean;
var
cdcanvas = cdCreateCanvas(CD_IUP, ih)
i,j,k:integer;
cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas)
v:type_vector;
{} = cdCanvasTextAlignment(cddbuffer, CD_SOUTH)
begin
return IUP_DEFAULT
move_right:=FALSE;
end function
for i:=1 to game.lin do
begin
(* The side which will be move had to be at the beginning of the vector *)
(* For example, I want to move this line to the right: 0 2 0 3 6 *)
(* The procedure "MoveAndSum" has to receive this vector: 6 3 0 2 0 *)
k:=1;
for j:=game.col downto 1 do
begin
v[k]:=game.map[i,j];
k:=k+1;
end;
if MoveAndSum(game,v,game.lin) then
move_right:=TRUE;
(* Copy to the right place in the matrix *)
k:=1;
for j:=game.col downto 1 do
begin
game.map[i,k]:=v[j];
k:=k+1;
end;
end;
end;
 
function key_cb(Ihandle /*ih*/, atom c)
if c=K_ESC then return IUP_CLOSE end if
if find(c,valid_keys) then
if move(c) then
IupUpdate(canvas)
string mbmsg = ""
if game_won() then
mbmsg = "!!!YOU WON!!!\n\nAnother Go?"
else
add_rand(1)
-- repaintWindow(main)
IupUpdate(canvas)
if no_valid_moves() then
mbmsg = "You Lost.\n\nAnother Go?"
end if
end if
if length(mbmsg) then
if IupAlarm("Game Over",mbmsg,"Yes","No")=1 then
newgame=1
else
return IUP_CLOSE
end if
end if
end if
IupUpdate(canvas)
end if
return IUP_CONTINUE
end function
 
function move_down(var game:type_game):boolean;
procedure main()
var
i,j,k:integer;
v:type_vector;
begin
move_down:=FALSE;
for j:=1 to game.col do
begin
k:=1;
for i:=game.lin downto 1 do
begin
v[k]:=game.map[i,j];
k:=k+1;
end;
if MoveAndSum(game,v,game.lin) then
move_down:=TRUE;
k:=1;
for i:=game.lin downto 1 do
begin
game.map[k,j]:=v[i];
k:=k+1;
end;
end;
end;
 
function move_up(var game:type_game):boolean;
IupOpen()
var
i,j:integer;
v:type_vector;
begin
move_up:=FALSE;
for j:=1 to game.col do
begin
for i:=1 to game.lin do
v[i]:=game.map[i,j];
if MoveAndSum(game,v,game.lin) then
move_up:=TRUE;
for i:=1 to game.lin do
game.map[i,j]:=v[i];
end;
end;
 
function CheckWinLose(var game:type_game):integer;
canvas = IupCanvas("RASTERSIZE=520x540")
(* Returns 2 if the player win the game *)
IupSetCallback(canvas, "MAP_CB", Icallback("map_cb"))
(* Returns 1 if the player lose the game *)
IupSetCallback(canvas, "ACTION", Icallback("redraw_cb"))
(* Returns 0 if has a valid move*)
var i,j:integer;
begin
with game do
begin
CheckWinLose:=1;
i:=1;
while (i<=game.lin)and(CheckWinLose<>2) do
begin
j:=1;
while (j<=game.col)and(CheckWinLose<>2) do
begin
if map[i,j] = 2048 then
CheckWinLose:=2
else
if map[i,j] = NOTHING then
CheckWinLose:=0
else
if (map[i,j] = map[i,j+1])and(j<>col) then
CheckWinLose:=0
else
if (map[i,j] = map[i,j-1])and(j<>1) then
CheckWinLose:=0
else
if (map[i,j] = map[i+1,j])and(i<>lin) then
CheckWinLose:=0
else
if (map[i,j] = map[i-1,j])and(i<>1) then
CheckWinLose:=0;
j:=j+1;
end;
i:=i+1;
end;
end;
end;
 
begin
dialog = IupDialog(canvas,"MINSIZE=440x450")
movement:=false;
IupSetAttribute(dialog,"TITLE","2048");
end_game:=false;
IupSetCallback(dialog, "K_ANY", Icallback("key_cb"));
initializing_game(game);
repeat
ClrScr;
if movement then
Create_Number(game);
movement:=false;
 
writeln('SCORE: ',game.score);
IupShow(dialog)
print_map(game);
IupSetAttribute(canvas, "RASTERSIZE", NULL)
writeln(' Use the arrow keys to move ');
writeln(' Press ESC to quit the game ');
 
case CheckWinLose(game) of
IupMainLoop()
IupClose()1:begin
print_line(SIZETOPBOT,'-');
end procedure
writeln('| Game Over! |');
main()</lang>
print_line(SIZETOPBOT,'-');
end_game:=TRUE;
end;
2:begin
print_line(SIZETOPBOT,'-');
writeln('| You Win! |');
print_line(SIZETOPBOT,'-');
end_game:=TRUE;
end;
end;
 
repeat
until KeyPressed;
case ReadKey of
#0:begin
case ReadKey of
#72:movement:=move_up(game);
#77:movement:=move_right(game);
#75:movement:=move_left(game);
#80:movement:=move_down(game);
end;
end;
#27:end_game:=true;
end;
until end_game;
end.
</syntaxhighlight>
 
=={{header|Perl}}==
<syntaxhighlight lang="perl">#!/usr/bin/perl
 
use strict; # https://rosettacode.org/wiki/2048
use warnings;
use Tk;
 
my $N = shift // 4;
$N < 2 and $N = 2;
my @squares = 1 .. $N*$N;
my %n2ch = (' ' => ' ');
@n2ch{ map 2**$_, 1..26} = 'a'..'z';
my %ch2n = reverse %n2ch;
my $winner = '';
my @arow = 0 .. $N - 1;
my @acol = map $_ * $N, @arow;
 
my $mw = MainWindow->new;
$mw->geometry( '+300+0' );
$mw->title( 2048 );
$mw->focus;
$mw->bind('<KeyPress-Left>' => sub { arrow($N, @arow) } );
$mw->bind('<KeyPress-Right>' => sub { arrow($N, reverse @arow) } );
$mw->bind('<KeyPress-Up>' => sub { arrow(1, @acol) } );
$mw->bind('<KeyPress-Down>' => sub { arrow(1, reverse @acol) } );
my $grid = $mw->Frame()->pack;
for my $i ( 0 .. $#squares )
{
$grid->Label(-textvariable => \$squares[$i],
-width => 5, -height => 2, -font => 'courierbold 30',
-relief => 'ridge', -borderwidth => 5,
)->grid(-row => int $i / $N, -column => $i % $N );
}
my $buttons = $mw->Frame()->pack(-fill => 'x', -expand => 1);
$buttons->Button(-text => 'Exit', -command => sub {$mw->destroy},
-font => 'courierbold 14',
)->pack(-side => 'right');
$buttons->Button(-text => 'New Game', -command => \&newgame,
-font => 'courierbold 14',
)->pack(-side => 'left');
$buttons->Label(-textvariable => \$winner,
-font => 'courierbold 18', -fg => 'red2',
)->pack;
 
newgame();
MainLoop;
-M $0 < 0 and exec $0;
 
sub losecheck
{
local $_ = join '', @n2ch{ @squares };
/ / || ($_ ^ substr $_, $N) =~ tr/\0// and return;
/(.)\1/ and return for /.{$N}/g;
$winner = 'You Lost';
}
 
sub arrow
{
$winner and return; # you won, no more play
my ($inc, @ix) = @_;
my $oldboard = "@squares";
for ( 1 .. $N )
{
local $_ = join '', @n2ch{ @squares[@ix] }; # extract 4 squares
tr/ //d; # force left
s/(\w)\1/ chr 1 + ord $1 /ge; # group by twos
@squares[@ix] = @ch2n{ split //, $_ . ' ' x $N }; # replace
$_ += $inc for @ix; # next row or col
}
$oldboard eq "@squares" and return;
add2();
losecheck();
grep $_ eq 2048, @squares and $winner = 'WINNER !!';
}
 
sub add2
{
my @blanks = grep $squares[$_] eq ' ', 0 .. $#squares;
@blanks and $squares[ $blanks[rand @blanks] ] =
$_[0] // (rand() < 0.1 ? 4 : 2);
}
 
sub newgame
{
$_ = ' ' for @squares;
add2(2) for 1, 2;
$winner = '';
}</syntaxhighlight>
 
=={{header|Phix}}==
{{libheader|Phix/pGUI}}
{{libheader|Phix/online}}
Faithful desktop gui reproduction of the above link (https://gabrielecirulli.github.io/2048/)
Now I just got figure out how to win...
You can run this online [http://phix.x10.mx/p2js/2048.htm here].
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">-- demo\rosetta\2048.exw</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">dialog</span>
<span style="color: #004080;">cdCanvas</span> <span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">tile_colours</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">#CCC0B4</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- blank</span>
<span style="color: #000000;">#EEE4DA</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 2</span>
<span style="color: #000000;">#EDE0C8</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 4</span>
<span style="color: #000000;">#F2B179</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 8</span>
<span style="color: #000000;">#F59563</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 16</span>
<span style="color: #000000;">#F67C5F</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 32</span>
<span style="color: #000000;">#F65E3B</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 64</span>
<span style="color: #000000;">#EDCF72</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 128</span>
<span style="color: #000000;">#EDCC61</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 256</span>
<span style="color: #000000;">#EDC850</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 512</span>
<span style="color: #000000;">#EDC53F</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 1024</span>
<span style="color: #000000;">#EDC22E</span><span style="color: #0000FF;">}</span> <span style="color: #000080;font-style:italic;">-- 2048
-- the 4x4 board.
-- note that values are [1..12] for [blank,2,4,8,..2048].
-- (merging two eights is not 8+8-&gt;16 but 4+1-&gt;5, internally)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">board</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">newgame</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">valid</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">prev</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">nxt</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">add_rand</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">count</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- (nb infinite loop if board is full)</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">count</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">x</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">4</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">y</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">4</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">y</span><span style="color: #0000FF;">][</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- blank</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">y</span><span style="color: #0000FF;">][</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">+(</span><span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">10</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">10</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">count</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">move_x</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">d</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">bxy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">][</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">bxy</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- (not blank)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">bxy</span><span style="color: #0000FF;">=</span><span style="color: #000000;">prev</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">][</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">bxy</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">][</span><span style="color: #000000;">nxt</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bxy</span>
<span style="color: #000000;">nxt</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">d</span>
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">13</span>
<span style="color: #000000;">valid</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">else</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">prev</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- (blank)</span>
<span style="color: #008080;">or</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">nxt</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">prev</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span>
<span style="color: #008080;">and</span> <span style="color: #000000;">prev</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">13</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">nxt</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">d</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">nxt</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">][</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">][</span><span style="color: #000000;">nxt</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bxy</span>
<span style="color: #000000;">valid</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bxy</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">move_y</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">d</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">bxy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">][</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">bxy</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- (not blank)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">bxy</span><span style="color: #0000FF;">=</span><span style="color: #000000;">prev</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">][</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">bxy</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">nxt</span><span style="color: #0000FF;">][</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bxy</span>
<span style="color: #000000;">nxt</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">d</span>
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">13</span>
<span style="color: #000000;">valid</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">else</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">prev</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- (blank)</span>
<span style="color: #008080;">or</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">nxt</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">prev</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span>
<span style="color: #008080;">and</span> <span style="color: #000000;">prev</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">13</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">nxt</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">d</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">nxt</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">][</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">nxt</span><span style="color: #0000FF;">][</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bxy</span>
<span style="color: #000000;">valid</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bxy</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">move</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- a non-zero result means it changed something.</span>
<span style="color: #000000;">valid</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_LEFT</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">13</span>
<span style="color: #000000;">nxt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">move_x</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_UP</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">13</span>
<span style="color: #000000;">nxt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">4</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">4</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">move_y</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_RIGHT</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">13</span>
<span style="color: #000000;">nxt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">4</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">4</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">move_x</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_DOWN</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">13</span>
<span style="color: #000000;">nxt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">move_y</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">valid</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">game_won</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">12</span><span style="color: #0000FF;">,</span><span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">1</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">valid_keys</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #004600;">K_LEFT</span><span style="color: #0000FF;">,</span><span style="color: #004600;">K_DOWN</span><span style="color: #0000FF;">,</span><span style="color: #004600;">K_RIGHT</span><span style="color: #0000FF;">,</span><span style="color: #004600;">K_UP</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">no_valid_moves</span><span style="color: #0000FF;">()</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">saved_board</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">valid_keys</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">move</span><span style="color: #0000FF;">(</span><span style="color: #000000;">valid_keys</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">board</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">saved_board</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #000080;font-style:italic;">-- OK</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- game over...</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">redraw_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ox</span><span style="color: #0000FF;">,</span><span style="color: #000000;">oy</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- top right coords</span>
<span style="color: #000000;">os</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ts</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- overall and tile size</span>
<span style="color: #000000;">ts2</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- half tile, for number positioning</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">dw</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dh</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetIntInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DRAWSIZE"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">dw</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">dh</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">ox</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #000000;">dw</span><span style="color: #0000FF;">-</span><span style="color: #000000;">dh</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">oy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #000000;">os</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dh</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">ox</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #000000;">oy</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #000000;">dh</span><span style="color: #0000FF;">-</span><span style="color: #000000;">dw</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">os</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dw</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">ts</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #000000;">os</span><span style="color: #0000FF;">-</span><span style="color: #000000;">10</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">4</span><span style="color: #0000FF;">-</span><span style="color: #000000;">7</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">ts2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ts</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">+</span><span style="color: #000000;">5</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">10</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">newgame</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">board</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">),</span><span style="color: #000000;">4</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">add_rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">newgame</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">cdCanvasActivate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasSetBackground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">#FAF8EF</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasClear</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasSetForeground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">#BBADA0</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasRoundedBox</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ox</span><span style="color: #0000FF;">+</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ox</span><span style="color: #0000FF;">+</span><span style="color: #000000;">os</span><span style="color: #0000FF;">-</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">oy</span><span style="color: #0000FF;">+</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">oy</span><span style="color: #0000FF;">+</span><span style="color: #000000;">os</span><span style="color: #0000FF;">-</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">tx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ox</span><span style="color: #0000FF;">+</span><span style="color: #000000;">15</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ty</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">oy</span><span style="color: #0000FF;">+</span><span style="color: #000000;">15</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">bxy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">][</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span>
<span style="color: #7060A8;">cdCanvasSetForeground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tile_colours</span><span style="color: #0000FF;">[</span><span style="color: #000000;">bxy</span><span style="color: #0000FF;">])</span>
<span style="color: #7060A8;">cdCanvasRoundedBox</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tx</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">ts</span><span style="color: #0000FF;">-</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ty</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ty</span><span style="color: #0000FF;">+</span><span style="color: #000000;">ts</span><span style="color: #0000FF;">-</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">bxy</span><span style="color: #0000FF;">></span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">cdCanvasSetForeground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bxy</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">3</span><span style="color: #0000FF;">?</span><span style="color: #000000;">#776E65</span><span style="color: #0000FF;">:</span><span style="color: #000000;">#F9F6F2</span><span style="color: #0000FF;">))</span>
<span style="color: #7060A8;">cdCanvasFont</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"Calibri"</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_BOLD</span><span style="color: #0000FF;">,</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bxy</span><span style="color: #0000FF;">></span><span style="color: #000000;">10</span><span style="color: #0000FF;">?</span><span style="color: #000000;">32</span><span style="color: #0000FF;">:</span><span style="color: #000000;">40</span><span style="color: #0000FF;">))</span>
<span style="color: #7060A8;">cdCanvasText</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">ts2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ty</span><span style="color: #0000FF;">+</span><span style="color: #000000;">ts2</span><span style="color: #0000FF;">-</span><span style="color: #000000;">25</span><span style="color: #0000FF;">-</span><span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bxy</span><span style="color: #0000FF;"><</span><span style="color: #000000;">11</span><span style="color: #0000FF;">?</span><span style="color: #000000;">7</span><span style="color: #0000FF;">:</span><span style="color: #000000;">0</span><span style="color: #0000FF;">),</span> <span style="color: #7060A8;">sprint</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bxy</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">ty</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">ts</span><span style="color: #0000FF;">+</span><span style="color: #000000;">5</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">tx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">ts</span><span style="color: #0000FF;">+</span><span style="color: #000000;">5</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">cdCanvasFlush</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">map_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">cdcanvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_IUP</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">cddbuffer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_DBUFFER</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasSetTextAlignment</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_SOUTH</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">key_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_ESC</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CLOSE</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">,</span><span style="color: #000000;">valid_keys</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">move</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">IupUpdate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">mbmsg</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">game_won</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">mbmsg</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"!!!YOU WON!!!\n\nAnother Go?"</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">add_rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupUpdate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">no_valid_moves</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">mbmsg</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"You Lost.\n\nAnother Go?"</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">mbmsg</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">IupMessage</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Game Over"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mbmsg</span><span style="color: #0000FF;">);</span>
<span style="color: #000000;">newgame</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span>
<span style="color: #008080;">else</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">IupAlarm</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Game Over"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mbmsg</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Yes"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"No"</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">newgame</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span>
<span style="color: #008080;">else</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CLOSE</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">IupUpdate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CONTINUE</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">canvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupCanvas</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"RASTERSIZE=520x540"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"MAP_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"map_cb"</span><span style="color: #0000FF;">))</span>
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"ACTION"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"redraw_cb"</span><span style="color: #0000FF;">))</span>
<span style="color: #000000;">dialog</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"MINSIZE=440x450"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dialog</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"TITLE"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"2048"</span><span style="color: #0000FF;">);</span>
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dialog</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"K_ANY"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"key_cb"</span><span style="color: #0000FF;">));</span>
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dialog</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"RASTERSIZE"</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">NULL</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
 
=={{header|PHP}}==
Works from PHP5 and upwards in CLI mode.
<syntaxhighlight lang="php">
<lang PHP>
<?php
 
Line 7,424 ⟶ 12,055:
 
}
</syntaxhighlight>
</lang>
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(load "@lib/simul.l")
 
(symbols 'simul 'pico)
 
(seed (in "/dev/urandom" (rd 8)))
Line 7,559 ⟶ 12,192:
(T (fish '((This) (= 512 (: N))) *G)
(println 'Maximum) ) )
(bye)</langsyntaxhighlight>
 
=={{header|Pony}}==
{{works with|ponyc|0.10.0}}
<langsyntaxhighlight lang="pony">
use "term"
use "random"
Line 7,830 ⟶ 12,463:
 
input(consume notify)
</syntaxhighlight>
</lang>
 
=={{header|Prolog}}==
Works with swi-prolog, any version.
<langsyntaxhighlight Prologlang="prolog">/* -------------------------------------------------------------
Entry point, just create a blank grid and enter a 'game loop'
-------------------------------------------------------------*/
Line 7,992 ⟶ 12,625:
dbl(' ', ' ').
dbl(2,4). dbl(4,8). dbl(8,16). dbl(16,32). dbl(32,64). dbl(64,128). dbl(128,256). dbl(256,512). dbl(512,1028). dbl(1028,2048).
</syntaxhighlight>
</lang>
{{out}}
<pre>?- play_2048.
Line 8,011 ⟶ 12,644:
 
=={{header|Python}}==
===Python: Original, with output===
<lang python>
<syntaxhighlight lang="python">#!/usr/bin/env python3
 
import curses
Line 8,213 ⟶ 12,846:
 
curses.wrapper(main)
</syntaxhighlight>
</lang>
 
===Python: using tkinter===
<syntaxhighlight lang="python">#!/usr/bin/env python3
 
''' Python 3.6.5 code using Tkinter graphical user interface.
Option to set goal to powers of 2 from 128 to 2048. '''
from tkinter import *
from tkinter import messagebox
from tkinter import ttk
import random
 
# ************************************************
 
class Board:
 
def __init__(self):
self.bd = ['']* 16
self.goal = 2048
self.choices = '2222222224'
# place 2 random squares on empty board:
def place_two(self):
idx = range(15)
a, b = random.sample(idx, 2)
self.bd[a] = random.choice(self.choices)
self.bd[b] = random.choice(self.choices)
 
# return text on square at index=idx of board:
def get_text(self, idx):
return self.bd[idx]
 
# move squares on board based on arrow key entered:
def move_squares(self, key):
if key in ('LR'):
# generate 4x4 2D array for row processing:
rows = [[self.bd[0], self.bd[1], self.bd[2], self.bd[3]],
[self.bd[4], self.bd[5], self.bd[6], self.bd[7]],
[self.bd[8], self.bd[9], self.bd[10], self.bd[11]],
[self.bd[12], self.bd[13], self.bd[14], self.bd[15]]]
else:
# generate transposed 4x4 2D array instead:
rows = [[self.bd[0], self.bd[4], self.bd[8], self.bd[12]],
[self.bd[1], self.bd[5], self.bd[9], self.bd[13]],
[self.bd[2], self.bd[6], self.bd[10], self.bd[14]],
[self.bd[3], self.bd[7], self.bd[11], self.bd[15]]]
 
# build a new 4x4 array of "moved" rows:
nrows = []
for row in rows:
if key in 'RD':
# reverse these rows and slide to left:
row = row[::-1]
nrow = self.slide_squares(row)
if key in 'RD':
# restore reversed rows:
nrow = nrow[::-1]
nrows.append(nrow)
if key in ('UD'):
# transpose arrays that were transposed:
nrows = list(map(list, zip(*nrows)))
 
# flatten 4x4 2D array:
newbd = []
for row in nrows:
for r in row:
newbd.append(r)
 
# place a '2' or '4' in random open square of newbd:
if newbd != self.bd and '' in newbd:
loi = []
for i in range(16):
if newbd[i] == '':
loi.append(i)
i = random.choice(loi)
newbd[i] = random.choice(self.choices)
self.bd = newbd
return
 
# slide squares in row to the left:
def slide_squares(self, row):
new = [''] * 4
icmb = -1
inew = 0
for x in row:
if x:
if (inew > 0 and
x == new[inew-1] and
icmb != inew-1):
new[inew-1] = str(2*int(x))
icmb = inew-1
else:
new[inew] = x
inew += 1
return new
 
# check if game won, lost, or continuing:
def is_end(self):
if self.goal in self.bd:
return 'W'
if '' in self.bd:
return 'C'
for i in [0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14]:
if self.bd[i] == self.bd[i+1]:
return 'C'
for i in range(12):
if self.bd[i] == self.bd[i+4]:
return 'C'
return 'L'
# ************************************************
 
class Game:
def __init__(self, gw):
self.window = gw
 
self.rosybrown1 = '#ffc1c1'
self.lemonchiffon = '#fffacd'
self.skyblue1 = '#87ceff'
self.springgreen = '#00ff7f'
self.tomato1 = '#ff6347'
self.hotpink = '#ff69b4'
self.brilliantlavender = '#edcaf6'
self.cobaltgreen = '#3d9140'
self.dodgerblue = '#1e90ff'
self.darkgoldenrod1 = '#ffb90f'
self.yellow = '#ffff00'
self.imperialred = '#ed2939'
self.navyblue = '#000080'
self.lightgreen = '#90ee90'
self.lightsteelblue = '#b0c4de'
self.white = '#ffffff'
self.palegreen4 = '#548b54'
self.darkgreen = '#013220'
self.black = '#000000'
 
self.doc = {'':self.rosybrown1,
'2':self.lemonchiffon,
'4':self.skyblue1,
'8':self.springgreen,
'16':self.tomato1,
'32':self.hotpink,
'64':self.brilliantlavender,
'128':self.cobaltgreen,
'256':self.dodgerblue,
'512':self.darkgoldenrod1,
'1024':self.yellow,
'2048':self.imperialred}
 
# game data:
self.bd = None
self.playable = False
 
# top frame:
self.top_fr = Frame(gw,
width=600,
height=100,
bg=self.lightgreen)
self.top_fr.pack(fill=X)
 
self.hdg = Label(self.top_fr,
text=' 2048 ',
font='arial 22 bold',
fg=self.navyblue,
bg=self.white)
self.hdg.place(relx=0.5, rely=0.4,
anchor=CENTER)
 
self.dir = Label(self.top_fr,
text="(Select a 'Goal' & Click 'New Game')",
font='arial 12 ',
fg=self.navyblue,
bg=self.lightgreen)
self.dir.place(relx=0.5, rely=0.8,
anchor=CENTER)
 
self.play_btn = Button(self.top_fr,
text='New \nGame',
bd=5,
bg=self.palegreen4,
fg=self.white,
font='times 12 bold',
command=self.new_game)
self.play_btn.place(relx=0.92, rely=0.5,
anchor=E)
 
self.lbl_cb = Label(self.top_fr,
text=' Goal',
font='arial 12 bold ',
fg=self.darkgreen,
bg=self.lightgreen)
self.lbl_cb.place(relx=0.08, rely=0.35,
anchor=W)
 
goals = ['2048', '1024', '512', '256', '128']
self.cur_goal = StringVar()
self.goal_cb = ttk.Combobox(self.top_fr,
foreground=self.darkgreen,
values=goals,
font='times 12 bold',
justify='left',
state='readonly',
textvariable=self.cur_goal,
width=7,
height=30)
self.goal_cb.place(relx=0.08, rely=0.6,
anchor=W)
self.goal_cb.current(0)
 
# bottom frame:
self.btm_fr = Frame(gw,
width=600,
height=500,
bg=self.lightsteelblue)
self.btm_fr.pack(fill=X)
 
# board frame:
self.bd_fr = Frame(self.btm_fr,
width=400+2,
height=400+2,
relief='solid',
bd=1,
bg=self.lemonchiffon)
self.bd_fr.place(relx=0.5, rely=0.5,
anchor=CENTER)
 
self.bd = Board()
self.play_game()
 
# ************************************************
 
# action to take if 'new game' button is clicked
# or if 'play again' is chosen after win or loss:
def new_game(self):
self.playable = True
self.bd = Board()
self.bd.place_two()
self.bd.goal = self.goal_cb.get()
self.goal_cb.config(state='disabled')
self.dir.config(text='(Use arrow keys to play game)')
self.play_game()
 
# show current contents of board:
def play_game(self):
objh = 100 # widget height
objw = 100 # widget width
objx = 0 # x-position of widget in frame
objy = 0 # y-position of widget in frame
 
i = 0
for r in range(4):
for c in range(4):
txt = self.bd.get_text(i)
bg_color = self.doc[txt]
game_sq = Label(self.bd_fr,
text=txt,
relief='solid',
bd=1,
fg=self.black,
bg=bg_color,
font='times 16 bold')
game_sq.place(x=objx, y=objy,
height=objh, width=objw)
i += 1
objx = objx + objw
objx = 0
objy = objy + objh
 
# control play when an arrow key is pressed:
def key(self, event):
if event.keysym in ('Left', 'Right', 'Up', 'Down'):
if self.playable:
self.bd.move_squares(event.keysym[0])
self.play_game()
x = self.bd.is_end()
if x == 'C':
return
elif x == 'W':
msg = 'You won!!! Play again?'
elif x == 'L':
msg = 'You lost!!! Play again?'
ans = messagebox.askquestion(msg)
if ans == 'no':
self.window.destroy()
else:
self.new_game()
 
# ************************************************
 
root = Tk()
root.title('2048')
root.geometry('600x600+100+50')
root.resizable(False, False)
g = Game(root)
root.bind_all('<Key>', g.key)
root.mainloop()
</syntaxhighlight>
 
=={{header|QB64}}==
<syntaxhighlight lang="qb64">
<lang QB64>
_DEFINE A-Z AS _INTEGER64
DIM SHARED Grid(0 TO 5, 0 TO 5) AS INTEGER
Line 8,504 ⟶ 13,434:
COLOR dc&, bg&
END SUB
</syntaxhighlight>
</lang>
 
=={{header|R}}==
orginal R package : https://github.com/ThinkRstat/r2048
<syntaxhighlight lang="r">
<lang R>
GD <- function(vec) {
c(vec[vec != 0], vec[vec == 0])
Line 8,672 ⟶ 13,602:
}
 
</syntaxhighlight>
</lang>
 
=={{header|Racket}}==
Line 8,678 ⟶ 13,608:
Play the RacketScript fork online here: http://rapture.twistedplane.com:8080/#example/2048-game
 
<syntaxhighlight lang="racket">
<lang Racket>
;; LICENSE: See License file LICENSE (MIT license)
;;
Line 9,483 ⟶ 14,413:
 
(start)
</syntaxhighlight>
</lang>
 
=={{header|Raku}}==
Line 9,489 ⟶ 14,419:
Uses termios to set the terminal options, so only compatible with POSIX terminals. This version does not include a specific "win" or "lose" condition. (though it would be trivial to add them.) You can continue to play this even after getting a 2048 tile; and if there is no valid move you can make, you can't do anything but quit.
{{works with|Rakudo|2018.05}}
<syntaxhighlight lang="raku" perl6line>use Term::termios;
 
constant $saved = Term::termios.new(fd => 1).getattr;
Line 9,603 ⟶ 14,533:
move %dir{$key} if so %dir{$key};
last if $key eq 'q'; # (q)uit
}</langsyntaxhighlight>
Sample output:
<pre>
Line 9,628 ⟶ 14,558:
{{works with|Red|0.6.4}}
 
<langsyntaxhighlight Redlang="red">Red [Needs: 'View]
 
random/seed now
Line 9,716 ⟶ 14,646:
display
view lay
</syntaxhighlight>
</lang>
 
{{out}}
[https://thavyraw.orggithubusercontent.com/Palaing/redlib/master/games/images/2048game.png graphical display of game interface]
 
=={{header|REXX}}==
Line 9,728 ⟶ 14,658:
::* &nbsp; allows abbreviations for the directions &nbsp; (Up, Down, Left, Right).
::* &nbsp; allows the player to quit the game at any time.
::* &nbsp; clears the screen if a legal move is in upper case.
::* &nbsp; does error checking/validation for entered directions &nbsp; (in response to the prompt).
::* &nbsp; keeps track of the number of legal moves made and the score.
Line 9,734 ⟶ 14,665:
::* &nbsp; displays a message if a winning move was entered.
::* &nbsp; displays the game board as a grid &nbsp; (with boxes).
<langsyntaxhighlight lang="rexx">/*REXX program lets a user play the 2048 game on an NxN grid (default is 4x4 grid).*/
parse arg N win seed . /*obtain optional arguments from the CL*/
if N=='' | N=="," then N= 4 /*Not specified? Then use the default.*/
Line 9,756 ⟶ 14,687:
if x\=='' then call err "too many arguments entered: " xx
if abbrev('QUIT',a,1) then do; say; say eye "quitting the game".; exit 1; end
good=abbrev('UP',a,1) | abbrev('"DOWN'",a,1) | abbrev('RIGHT',a,1) | abbrev('"LEFT'",a,1)
if \good then call err "invalid direction: " way
if \ok then iterate; moves= moves + 1; call mov
Line 9,763 ⟶ 14,694:
say translate(eye "Congrats!! You've won the" win 'game!' eye,"═",'─') "score:" score
exit 0 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
showGrid: do r=0 for N+2; _= '║'; __= '╠'
do c=1 for N; _=_ || row()'║'; __=__ || copies("═", L)'╬'
end /*c*/
if r==0 then _= '╔'translate( substr(_, 2, length(_) - 2), "╦", '║')"╗"
if r >N then _= '╚'translate( substr(_, 2, length(_) - 2), "╩", '║')"╝"
say pad _
if r<N & r>0 then say pad substr(__, 1, length(__) -1)"╣"
end /*r*/; return
/*──────────────────────────────────────────────────────────────────────────────────────*/
@: procedure expose @.; parse arg row,col; return @.row.col
Line 9,783 ⟶ 14,705:
two: do until @.p.q==b; p= random(1,N); q= random(1,N); end; @.p.q= ten(); return
/*──────────────────────────────────────────────────────────────────────────────────────*/
movshowGrid: move= do r=0; for N+2; if d= _= 'R'; then call moveLR N, 1, -1 /*move (slide) numbers right. */ __= "╠"
ifdo dc=='L'1 thenfor callN; moveLR 1, N, +1 _= _ /* || " row()'║'; " __= __ || copies("═", left. */L)'╬'
if d=='U' then call moveUD 1, N, +1 end /* " " " up. c*/
if dr=='D'0 then call_= moveUD'╔'translate( Nsubstr(_, 12, length(_) -1 /*2), " ", '║')"╗" down. */
if r >N then _= '╚'translate( substr(_, 2, length(_) - 2), "╩", '║')"╝"
say pad _
if r<N & r>0 then say pad substr(__, 1, length(__) - 1)"╣"
end /*r*/; return
/*──────────────────────────────────────────────────────────────────────────────────────*/
mov: move= 0; if d=='R' then call moveLR N, 1, -1 /*move (slide) numbers ► */
if d=='L' then call moveLR 1, N, +1 /* " " " ◄ */
if d=='U' then call moveUD 1, N, +1 /* " " " ↑ */
if d=='D' then call moveUD N, 1, -1 /* " " " ↓ */
if \move then call err 'moving ' way " doesn't change anything."; return
/*──────────────────────────────────────────────────────────────────────────────────────*/
moveLR: parse arg start, sTo, # /*slide ◄ or ► */
do r=1 for N; old= o_r(); if ! then iterate /*is this row blank? */
do N-1; call packLR /*pack left or right.*/
end /*N-1*/ /* [↓] get new tiles.*/
new= o_r(); move= move | (old\==new) /*indicate tiles moved*/
do c=start for N-1 by # while @.r.c\==b /*slide left or right.*/
if @.r.c\==@(r,c+#) then iterate /*not a duplicate ? */
@.r.c= @.r.c * 2; score= score + @.r.c /*double; bump score */
c= c + # ; @.r.c= b; move= 1 move= 1 /*bump C; blank dup 2.*/
end /*c*/ /* [↑] indicate move.*/
call packLR /*pack left or right.*/
end /*r*/; return
/*──────────────────────────────────────────────────────────────────────────────────────*/
moveUD: parse arg start, Sto, # /*slide ↑ or ↓ */
do c=1 for N; old= o_c(); if ! then iterate /*is this col blank? */
do N-1; call packUD /*pack up or down. */
end /*N-1*/ /* [↓] get new tiles.*/
new= o_c(); move= move | (old\==new) /*indicate tiles moved*/
do r=start for N-1 by # while @.r.c\==b /*slide up or down. */
if @.r.c\==@(r+#,c) then iterate /*not a duplicate ? */
@.r.c= @.r.c * 2; score= score + @.r.c /*double; bump score */
r= r + # ; @.r.c= b; move= 1 move= 1 /*bump R; blank dup 2.*/
end /*r*/ /* [↑] indicate move.*/
call packUD /*pack up or down. */
end /*c*/; return
/*──────────────────────────────────────────────────────────────────────────────────────*/
packLR: do c=start for N-1 by #; if @.r.c\==b then iterate /*slideNot lefta orblank? right Skip. */
do if @.r.c\s==bc thento iteratesTo by #; @.r.s= @(r, s + #) /*slide /*Not aor blank? Skip. */
end /*s*/; do s=c to sTo by #; @.r.ssTo= @(r,b s+#) /*slidehandle leftthe orlast rightone.*/
end end /*sc*/; @.r.sTo= b /*handle the last one.*/return
end /*c*/; return
/*──────────────────────────────────────────────────────────────────────────────────────*/
packUD: do r=start for N-1 by #; if @.r.c\==b then iterate /*slideNot upa orblank? down Skip. */
do if @.r.c\s==br thento iteratesTo by #; @.s.c= @(s + #, c) /*slide /*Not aor blank? Skip. */
end /*s*/; do s=r to sTo by #; @.ssTo.c= @(s+#,b c) /*slide up or down. /*handle the last one.*/
end end /*sr*/; @.sTo.c= b return</*handle the last one.*/syntaxhighlight>
Programming note: &nbsp; with a little more program complexity, &nbsp; the &nbsp; '''moveLR''' &nbsp; and &nbsp; '''moveUD''' &nbsp; subroutines could've
end /*r*/; return</lang>
<br>been combined, &nbsp; as well as the &nbsp; '''packLR''' &nbsp; and &nbsp; '''packUD''' &nbsp; subroutines.
 
 
{{out|output|text=&nbsp; when using the default inputs:}}
<pre style="font-size:84%;height:98ex">
Line 9,990 ⟶ 14,923:
 
=={{header|Ring}}==
<langsyntaxhighlight lang="ring">
# Project : 2048 Game
 
Line 10,427 ⟶ 15,360:
on '2048' setStylesheet(C_BUTTON2048STYLE)
off
</syntaxhighlight>
</lang>
 
=={{header|Ruby}}==
inspired by the Raku version
<langsyntaxhighlight lang="ruby">
#!/usr/bin/ruby
 
Line 10,630 ⟶ 15,563:
end
end
</syntaxhighlight>
</lang>
 
=={{header|Rust}}==
Line 10,636 ⟶ 15,569:
A simple implementation in rust. The user has to input an endline since i did not find a way to read a key press
{{libheader|rand}}
<langsyntaxhighlight lang="rust">
use std::io::{self,BufRead};
extern crate rand;
Line 10,821 ⟶ 15,754:
}
}
</syntaxhighlight>
</lang>
 
=={{header|Scala}}==
<langsyntaxhighlight lang="scala">import java.awt.event.{KeyAdapter, KeyEvent, MouseAdapter, MouseEvent}
import java.awt.{BorderLayout, Color, Dimension, Font, Graphics2D, Graphics, RenderingHints}
import java.util.Random
Line 11,016 ⟶ 15,949:
}
 
}</langsyntaxhighlight>
 
=={{header|Seed7}}==
Line 11,028 ⟶ 15,961:
STD_CONSOLE works also always the same, independent from the operating system or terminal/console.
 
<langsyntaxhighlight lang="seed7">$ include "seed7_05.s7i";
include "console.s7i";
include "keybd.s7i";
Line 11,217 ⟶ 16,150:
until moveOkay;
until quit;
end func;</langsyntaxhighlight>
 
=={{header|Tcl}}==
===Text mode===
<langsyntaxhighlight lang="tcl">
# A minimal implementation of the game 2048 in Tcl.
# For a maintained version with expanded functionality see
Line 11,498 ⟶ 16,431:
 
main
</syntaxhighlight>
</lang>
 
===Tk===
See https://tcl.wiki/39566.
 
=={{header|Visual Basic .NET}}==
{{trans|C#}}
<syntaxhighlight lang="vbnet">Friend Class Tile
Public Sub New()
Me.Value = 0
Me.IsBlocked = False
End Sub
Public Property Value As Integer
Public Property IsBlocked As Boolean
End Class
 
Friend Enum MoveDirection
Up
Down
Left
Right
End Enum
 
Friend Class G2048
Public Sub New()
_isDone = False
_isWon = False
_isMoved = True
_score = 0
InitializeBoard()
End Sub
 
Private Sub InitializeBoard()
For y As Integer = 0 To 3
For x As Integer = 0 To 3
_board(x, y) = New Tile()
Next
Next
End Sub
 
Private _isDone As Boolean
Private _isWon As Boolean
Private _isMoved As Boolean
Private _score As Integer
Private ReadOnly _board As Tile(,) = New Tile(3, 3) {}
Private ReadOnly _rand As Random = New Random()
Const empty As String = " "
 
Public Sub [Loop]()
AddTile()
While True
If _isMoved Then AddTile()
DrawBoard()
If _isDone Then Exit While
WaitKey()
End While
Dim endMessage As String = If(_isWon, "You've made it!", "Game Over!")
Console.WriteLine(endMessage)
End Sub
 
Public Sub DrawBoard()
Console.Clear()
Console.WriteLine("Score: " & _score & vbNewLine)
For y As Integer = 0 To 3
Console.WriteLine("+------+------+------+------+")
Console.Write("| ")
For x As Integer = 0 To 3
If _board(x, y).Value = 0 Then
Console.Write(empty.PadRight(4))
Else
Console.Write(_board(x, y).Value.ToString().PadRight(4))
End If
Console.Write(" | ")
Next
Console.WriteLine()
Next
Console.WriteLine("+------+------+------+------+" & vbNewLine & vbNewLine)
End Sub
 
Private Sub WaitKey()
_isMoved = False
Console.WriteLine("(W) Up (S) Down (A) Left (D) Right")
Dim input As Char
Char.TryParse(Console.ReadKey().Key.ToString(), input)
Select Case input
Case "W"c
Move(MoveDirection.Up)
Case "A"c
Move(MoveDirection.Left)
Case "S"c
Move(MoveDirection.Down)
Case "D"c
Move(MoveDirection.Right)
End Select
For y As Integer = 0 To 3
For x As Integer = 0 To 3
_board(x, y).IsBlocked = False
Next
Next
End Sub
 
Private Sub AddTile()
For y As Integer = 0 To 3
For x As Integer = 0 To 3
If _board(x, y).Value <> 0 Then Continue For
Dim a As Integer, b As Integer
Do
a = _rand.Next(0, 4)
b = _rand.Next(0, 4)
Loop While _board(a, b).Value <> 0
Dim r As Double = _rand.NextDouble()
_board(a, b).Value = If(r > 0.89F, 4, 2)
If CanMove() Then Return
Next
Next
_isDone = True
End Sub
 
Private Function CanMove() As Boolean
For y As Integer = 0 To 3
For x As Integer = 0 To 3
If _board(x, y).Value = 0 Then Return True
Next
Next
For y As Integer = 0 To 3
For x As Integer = 0 To 3
If TestAdd(x + 1, y, _board(x, y).Value) OrElse TestAdd(x - 1, y, _board(x, y).Value) OrElse TestAdd(x, y + 1, _board(x, y).Value) OrElse TestAdd(x, y - 1, _board(x, y).Value) Then Return True
Next
Next
Return False
End Function
 
Private Function TestAdd(ByVal x As Integer, ByVal y As Integer, ByVal value As Integer) As Boolean
If x < 0 OrElse x > 3 OrElse y < 0 OrElse y > 3 Then Return False
Return _board(x, y).Value = value
End Function
 
Private Sub MoveVertically(ByVal x As Integer, ByVal y As Integer, ByVal d As Integer)
If _board(x, y + d).Value <> 0 AndAlso _board(x, y + d).Value = _board(x, y).Value AndAlso Not _board(x, y).IsBlocked AndAlso Not _board(x, y + d).IsBlocked Then
_board(x, y).Value = 0
_board(x, y + d).Value *= 2
_score += _board(x, y + d).Value
_board(x, y + d).IsBlocked = True
_isMoved = True
ElseIf _board(x, y + d).Value = 0 AndAlso _board(x, y).Value <> 0 Then
_board(x, y + d).Value = _board(x, y).Value
_board(x, y).Value = 0
_isMoved = True
End If
If d > 0 Then
If y + d < 3 Then MoveVertically(x, y + d, 1)
Else
If y + d > 0 Then MoveVertically(x, y + d, -1)
End If
End Sub
 
Private Sub MoveHorizontally(ByVal x As Integer, ByVal y As Integer, ByVal d As Integer)
If _board(x + d, y).Value <> 0 AndAlso _board(x + d, y).Value = _board(x, y).Value AndAlso Not _board(x + d, y).IsBlocked AndAlso Not _board(x, y).IsBlocked Then
_board(x, y).Value = 0
_board(x + d, y).Value *= 2
_score += _board(x + d, y).Value
_board(x + d, y).IsBlocked = True
_isMoved = True
ElseIf _board(x + d, y).Value = 0 AndAlso _board(x, y).Value <> 0 Then
_board(x + d, y).Value = _board(x, y).Value
_board(x, y).Value = 0
_isMoved = True
End If
If d > 0 Then
If x + d < 3 Then MoveHorizontally(x + d, y, 1)
Else
If x + d > 0 Then MoveHorizontally(x + d, y, -1)
End If
End Sub
 
Private Sub Move(ByVal direction As MoveDirection)
Select Case direction
Case MoveDirection.Up
For x As Integer = 0 To 3
Dim y As Integer = 1
While y < 4
If _board(x, y).Value <> 0 Then MoveVertically(x, y, -1)
y += 1
End While
Next
Case MoveDirection.Down
For x As Integer = 0 To 3
Dim y As Integer = 2
While y >= 0
If _board(x, y).Value <> 0 Then MoveVertically(x, y, 1)
y -= 1
End While
Next
Case MoveDirection.Left
For y As Integer = 0 To 3
Dim x As Integer = 1
While x < 4
If _board(x, y).Value <> 0 Then MoveHorizontally(x, y, -1)
x += 1
End While
Next
Case MoveDirection.Right
For y As Integer = 0 To 3
Dim x As Integer = 2
While x >= 0
If _board(x, y).Value <> 0 Then MoveHorizontally(x, y, 1)
x -= 1
End While
Next
End Select
End Sub
End Class
 
Module Module1
Sub Main()
RunGame()
End Sub
 
Private Sub RunGame()
Dim game As G2048 = New G2048()
game.Loop()
CheckRestart()
End Sub
 
Private Sub CheckRestart()
Console.WriteLine("(N) New game (P) Exit")
While True
Dim input As Char
Char.TryParse(Console.ReadKey().Key.ToString(), input)
Select Case input
Case "N"c
RunGame()
Case "P"c
Return
Case Else
ClearLastLine()
End Select
End While
End Sub
 
Private Sub ClearLastLine()
Console.SetCursorPosition(0, Console.CursorTop)
Console.Write(New String(" ", Console.BufferWidth))
Console.SetCursorPosition(0, Console.CursorTop - 1)
End Sub
End Module
</syntaxhighlight>
{{out}}
<pre>
Score: 572
 
+------+------+------+------+
| | 2 | 16 | 4 |
+------+------+------+------+
| | 2 | 4 | 64 |
+------+------+------+------+
| 4 | 16 | 32 | 4 |
+------+------+------+------+
| 2 | 4 | 2 | 16 |
+------+------+------+------+
 
 
(W) Up (S) Down (A) Left (D) Right
</pre>
 
=={{header|Wren}}==
{{trans|C#}}
{{libheader|Wren-dynamic}}
{{libheader|Wren-ioutil}}
{{libheader|Wren-fmt}}
{{libheader|Wren-str}}
<syntaxhighlight lang="wren">import "./dynamic" for Enum, Struct
import "random" for Random
import "./ioutil" for Input
import "./fmt" for Fmt
import "./str" for Str
 
var MoveDirection = Enum.create("MoveDirection", ["up", "down", "left", "right"])
 
var Tile = Struct.create("Tile", ["value", "isBlocked"])
 
class G2048 {
construct new() {
_isDone = false
_isWon = false
_isMoved = true
_score = 0
_board = List.filled(4, null)
for (i in 0..3) {
_board[i] = List.filled(4, null)
for (j in 0..3) _board[i][j] = Tile.new(0, false)
}
_rand = Random.new()
initializeBoard()
}
 
initializeBoard() {
for (y in 0..3) {
for (x in 0..3) _board[x][y] = Tile.new(0, false)
}
}
 
loop() {
addTile()
while (true) {
if (_isMoved) addTile()
drawBoard()
if (_isDone) break
waitKey()
}
var endMessage = _isWon ? "You've made it!" : "Game Over!"
System.print(endMessage)
}
 
drawBoard() {
System.print("\e[2J") // clear terminal
System.print("Score: %(_score)\n")
for (y in 0..3) {
System.print("+------+------+------+------+")
System.write("| ")
for (x in 0..3) {
if (_board[x][y].value == 0) {
System.write(" ")
} else {
Fmt.write("$-4s", _board[x][y].value)
}
System.write(" | ")
}
System.print()
}
System.print("+------+------+------+------+\n\n")
}
 
waitKey() {
_isMoved = false
var input = Str.upper(Input.option("(W) Up (S) Down (A) Left (D) Right: ", "WSADwsad"))
if (input == "W") {
move(MoveDirection.up)
} else if (input == "A") {
move(MoveDirection.left)
} else if (input == "S") {
move(MoveDirection.down)
} else if (input == "D") {
move(MoveDirection.right)
}
for (y in 0..3) {
for (x in 0..3) _board[x][y].isBlocked = false
}
}
 
addTile() {
for (y in 0..3) {
for (x in 0..3) {
if (_board[x][y].value != 0) continue
var a
var b
while (true) {
a = _rand.int(4)
b = _rand.int(4)
if (_board[a][b].value == 0) break
}
var r = _rand.float()
_board[a][b].value = (r > 0.89) ? 4 : 2
if (canMove()) return
}
}
_isDone = true
}
 
canMove() {
for (y in 0..3) {
for (x in 0..3) {
if (_board[x][y].value == 0) return true
}
}
 
for (y in 0..3) {
for (x in 0..3) {
if (testAdd(x + 1, y, _board[x][y].value) ||
testAdd(x - 1, y, _board[x][y].value) ||
testAdd(x, y + 1, _board[x][y].value) ||
testAdd(x, y - 1, _board[x][y].value)) return true
}
}
 
return false
}
 
testAdd(x, y, value) {
if (x < 0 || x > 3 || y < 0 || y > 3) return false
return _board[x][y].value == value
}
 
moveVertically(x, y, d) {
if (_board[x][y + d].value != 0 &&
_board[x][y + d].value == _board[x][y].value &&
!_board[x][y].isBlocked &&
!_board[x][y + d].isBlocked) {
_board[x][y].value = 0
_board[x][y + d].value = _board[x][y + d].value * 2
_score = _score + _board[x][y + d].value
_board[x][y + d].isBlocked = true
_isMoved = true
} else if (_board[x][y + d].value == 0 && _board[x][y].value != 0) {
_board[x][y + d].value = _board[x][y].value
_board[x][y].value = 0
_isMoved = true
}
 
if (d > 0) {
if (y + d < 3) moveVertically(x, y + d, 1)
} else {
if (y + d > 0) moveVertically(x, y + d, -1)
}
}
 
moveHorizontally(x, y, d) {
if (_board[x + d][y].value != 0 &&
_board[x + d][y].value == _board[x][y].value &&
!_board[x + d][y].isBlocked &&
!_board[x][y].isBlocked) {
_board[x][y].value = 0
_board[x + d][y].value = _board[x + d][y].value * 2
_score = _score + _board[x + d][y].value
_board[x + d][y].isBlocked = true
_isMoved = true
} else if (_board[x + d][y].value == 0 && _board[x][y].value != 0) {
_board[x + d][y].value = _board[x][y].value
_board[x][y].value = 0
_isMoved = true
}
 
if (d > 0) {
if (x + d < 3) moveHorizontally(x + d, y, 1)
} else {
if (x + d > 0) moveHorizontally(x + d, y, -1)
}
}
 
move(direction) {
if (direction == MoveDirection.up) {
for (x in 0..3) {
for (y in 1..3) {
if (_board[x][y].value != 0) moveVertically(x, y, -1)
}
}
} else if (direction == MoveDirection.down) {
for (x in 0..3) {
for (y in 2..0) {
if (_board[x][y].value != 0) moveVertically(x, y, 1)
}
}
} else if (direction == MoveDirection.left) {
for (y in 0..3) {
for (x in 1..3) {
if (_board[x][y].value != 0) moveHorizontally(x, y, -1)
}
}
} else if (direction == MoveDirection.right) {
for (y in 0..3) {
for (x in 2..0) {
if (_board[x][y].value != 0) moveHorizontally(x, y, 1)
}
}
}
}
}
 
var runGame // forward declaration
 
var checkRestart = Fn.new {
var input = Str.upper(Input.option("(N) New game (P) Exit: ", "NPnp"))
if (input == "N") {
runGame.call()
} else if (input == "P") return
}
 
runGame = Fn.new {
var game = G2048.new()
game.loop()
checkRestart.call()
}
 
runGame.call()</syntaxhighlight>
 
{{out}}
Sample game:
<pre>
Score: 3016
 
+------+------+------+------+
| 2 | 8 | 2 | 4 |
+------+------+------+------+
| 16 | 64 | 128 | 2 |
+------+------+------+------+
| 8 | 256 | 4 | 8 |
+------+------+------+------+
| 2 | 4 | 2 | 32 |
+------+------+------+------+
 
 
Game Over!
(N) New game (P) Exit: p
</pre>
 
=={{header|XPL0}}==
<langsyntaxhighlight XPL0lang="xpl0">include c:\cxpl\codes; \intrinsic 'code' declarations
int Box(16), Moved;
 
Line 11,564 ⟶ 16,997:
until Moved;
];
]</langsyntaxhighlight>
416

edits