16 puzzle game: Difference between revisions

m (→‎{{header|REXX}}: corrected a misspelling.)
m (→‎{{header|Wren}}: Minor tidy)
 
(33 intermediate revisions by 13 users not shown)
Line 3: Line 3:
[[Category:Games]]
[[Category:Games]]


16 numbered pieces of the puzzle are placed out of order on a 4 X 4 grid. The correct order to win is to order the pieces
as 1 through 16, read left to right, top to bottom:

<pre>
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
</pre>

How to Play: The aim is to get the pieces back in order by clicking on the yellow arrows (choosing a location to rotate a row or column) to slide the pieces left or right, up or down.

<pre>
1 14 3 4 1 2 3 4
5 2 7 8 --> 5 6 7 8
9 6 11 12 9 10 11 12
13 10 15 16 13 14 15 16
^

</pre>
The Easy puzzle target is 3 moves, for the Hard puzzle it is 12 moves (or less!). Can it be that simple?


;Task:
;Task:
Line 8: Line 29:




See details: [http://www.bsswebsite.me.uk/Puzzlewebsite/Fifteenpuzzle/sixteen.htm 16 Puzzle Game]
See details: [https://web.archive.org/web/20190202094051/http://www.bsswebsite.me.uk/Puzzlewebsite/Fifteenpuzzle/sixteen.htm#]




Video: [https://www.google.com/url?q=https%3A%2F%2F1drv.ms%2Fv%2Fs!AqDUIunCqVnIg0bsohQX8b5_dc5G&sa=D&sntz=1&usg=AFQjCNH_eKBfk_1m88kte3Wo7MIii8hn1A 16 Puzzle Game]
Video: [https://www.google.com/url?q=https%3A%2F%2F1drv.ms%2Fv%2Fs!AqDUIunCqVnIg0bsohQX8b5_dc5G&sa=D&sntz=1&usg=AFQjCNH_eKBfk_1m88kte3Wo7MIii8hn1A 16 Puzzle Game]


;Related task:
:* &nbsp; [[15_Puzzle_Game|15 Puzzle Game]]
<br><br>
<br><br>

=={{header|AutoHotkey}}==
With Solver, See [[16_puzzle_game/autohotkey]]

=={{header|FreeBASIC}}==
{{trans|Wren}}
<syntaxhighlight lang="vb">Const easy = 1, hard = 4
Dim Shared As Byte n(1 To 16)

Sub initGrid ()
For i As Byte = 0 To 15
n(i) = i + 1
Next
End Sub

Sub rotate (ix() As Byte)
Dim As Byte last = n(ix(3))
For i As Byte = 3 To 1 Step -1
n(ix(i)) = n(ix(i-1))
Next
n(ix(0)) = last
End Sub

Function hasWon () As Boolean
For i As Byte = 0 To 15
If n(i) <> i+1 Then Return False
Next
Return True
End Function

Sub setDiff (level As Byte)
Dim As Byte moves = Iif(level = easy, 3, 12)
Dim As Byte rc(), j, i
For i = 0 To moves
Redim As Byte rc(20)
Dim As Byte r = Int(Rnd * 2)
Dim As Byte s = Int(Rnd * 4)
If r = 0 Then ' rotate random row
For j = s*4 To (s+1)*4
rc(j) = j
Next
Else ' rotate random column
For j = s To s+16 Step 4
rc(j) = j
Next
End If
rotate(rc())
If hasWon() Then ' do it again
i = -1
End If
i += 1
Next
Print Using !"\nTarget is ## moves."; moves
End Sub

Sub drawGrid ()
Print !"\n D1 D2 D3 D4"
Print " +-------------------+"
Print Using "R1 | ## | ## | ## | ## | L1"; n(0); n(1); n(2); n(3)
Print " |----+----+----+----|"
Print Using "R2 | ## | ## | ## | ## | L2"; n(4); n(5); n(6); n(7)
Print " |----+----+----+----|"
Print Using "R3 | ## | ## | ## | ## | L3"; n(8); n(9); n(10); n(11)
Print " |----+----+----+----|"
Print Using "R4 | ## | ## | ## | ## | L4"; n(12); n(13); n(14); n(15)
Print " +-------------------+"
Print !" U1 U2 U3 U4\n"
End Sub

'--- Programa Principal ---
Randomize Timer
Dim As Byte level = easy
Dim As String diff
Print "Enter difficulty level easy or hard E/H: ";
Do
Input ; "", diff
Loop Until Instr("eEhH", diff)
If Ucase(diff) = "H" Then level = hard

Cls
Print "Sixteen Puzzle"
initGrid()
setDiff(level)

Dim As Byte ix(0 To 3)
Print "When entering moves, you can also enter Q to quit or S to start again."
Dim As Byte c, moves = 0
Dim As String*2 move
Do
drawGrid()
If hasWon() Then
Print "Congratulations, you have won the game in"; moves; " moves!!"
While Inkey = "": Wend
Exit Do
End If
Do
Print "Moves so far = "; moves
Input "Enter move : ", move
Select Case Trim(Ucase(move))
Case "D1", "D2", "D3", "D4"
c = Cint(Right(move,1)) - 49
ix(0) = 0 + c
ix(1) = 4 + c
ix(2) = 8 + c
ix(3) = 12 + c
rotate(ix())
moves += 1
Exit Do
Case "L1", "L2", "L3", "L4"
c = Cint(Right(move,1)) - 49
ix(0) = 3 + 4*c
ix(1) = 2 + 4*c
ix(2) = 1 + 4*c
ix(3) = 0 + 4*c
rotate(ix())
moves += 1
Exit Do
Case "U1", "U2", "U3", "U4"
c = Cint(Right(move,1)) - 49
ix(0) = 12 + c
ix(1) = 8 + c
ix(2) = 4 + c
ix(3) = 0 + c
rotate(ix())
moves += 1
Exit Do
Case "R1", "R2", "R3", "R4"
c = Cint(Right(move,1)) - 49
ix(0) = 0 + 4*c
ix(1) = 1 + 4*c
ix(2) = 2 + 4*c
ix(3) = 3 + 4*c
rotate(ix())
moves += 1
Exit Do
Case "Q"
Exit Do, Do
Case "S"
Cls
initGrid()
setDiff(level)
moves = 0
Exit Do
Case Else
Print "Invalid move, try again."
End Select
Loop
Loop
'--------------------------
Sleep</syntaxhighlight>

=={{header|FutureBasic}}==
<syntaxhighlight lang="future basic">
begin enum
_down = 1
_right
_up
_left
_new = 100
_restrt
_help
_end
end enum
str63 board, startPos, winBoard

void local fn init
window 1,,(0,0,340,340)
int x
for x = 1 to 4
button 10+x,,,@"⬇️",(x*50+20,270,50,50),,NSBezelStyleTexturedSquare
ControlSetFontWithName( 10+x, @"Menlo", 32 )
button 30+x,,,@"⬆️",(x*50+20, 20,50,50),,NSBezelStyleTexturedSquare
ControlSetFontWithName( 30+x, @"Menlo", 32 )
button 25-x,,,@"➡️",( 20,x*50+20,50,50),,NSBezelStyleTexturedSquare
ControlSetFontWithName( 25-x, @"Menlo", 32 )
button 45-x,,,@"⬅️",(270,x*50+20,50,50),,NSBezelStyleTexturedSquare
ControlSetFontWithName( 45-x, @"Menlo", 32 )
next
button _new ,,,@"New", ( 20,270,50,50),,NSBezelStyleTexturedSquare
button _end ,,,@"Quit", ( 20, 20,50,50),,NSBezelStyleTexturedSquare
button _restrt,,,@"Redo", (270,270,50,50),,NSBezelStyleTexturedSquare
button _help ,,,@"Help", (270, 20,50,50),,NSBezelStyleTexturedSquare
for x = 1 to 16
winBoard += chr$(x)
next
board = winBoard
end fn

void local fn drawBoard
int c = 1, x, y, z
cls
for y = 70 to 220 step 50
for x = 70 to 220 step 50
rect fill (x,y,48,48), fn coloryellow
if board[c] > 9 then z = x-3 else z = x+6
print %(z,y+6) str(board[c]);
c++
next
next
end fn

void local fn move( tag as int )
int r, d, rc = (tag mod 10)
select tag / 10
case _up : d = +4
case _right : d = -1 : rc *= 4
case _down : d = -4 : rc += 12
case else : d = +1 : rc = rc * 4 - 3
end select
for r = rc to rc + 2 * d step d
swap board[r], board[r+d]
next
if board == winBoard then window 1, @"!!! YOU WON !!!" : text,,fn colorRed
fn drawBoard
end fn

void local fn newGame
window 1, @"16 PUZZLE GAME"
int r
for r = 1 to 16
swap board[r], board[rnd(16)]
next
startPos = board
text @"Arial bold", 32, fn colorblue
fn drawBoard
end fn

void local fn ask( tag as long )
CFStringRef s1, s2 : int btn
select tag
case _help
s1 = @"Use the arrow buttons to move numbers in rows and columns.\n¬
Win by arranging the numbers in order, left to right, top to bottom:"
s2 = @" 1 2 3 4 \n 5 6 7 8 \n 9 10 11 12\n 13 14 15 16"
btn = alert 1, NSAlertStyleInformational, s1, s2, @"Okay"
case _new : if board == winBoard then fn newGame : exit fn
s1 = @"Leave this puzzle\nand start a new one?"
btn = alert 1, NSAlertStyleInformational, s1,,@"New puzzle;Cancel"
if btn == NSAlertFirstButtonReturn then fn newGame
case _restrt
s1 = @"Restart this puzzle\nfrom the beginning?"
btn = alert 1, NSAlertStyleInformational,s1,,@"Restart;Cancel"
if btn == NSAlertFirstButtonReturn then board = startPos : fn drawBoard
case _end
btn = alert 1, NSAlertStyleInformational,@"Quit 16 GAME?",,@"Quit;Cancel"
if btn == NSAlertFirstButtonReturn then end
end select
end fn

void local fn doDialog(ev as long, tag as long)
select ev
case _btnClick : if tag < _new then fn move( tag ) else fn ask( tag )
case _windowWillClose : end
end select
end fn

on dialog fn doDialog
fn init
fn newGame

handleevents
</syntaxhighlight>
{{out}}
[[File:16 Puzzle Game.png]]

=={{header|Go}}==
<syntaxhighlight lang="go">package main

import (
"bufio"
"fmt"
"log"
"math/rand"
"os"
"strings"
"time"
)

const (
easy = 1
hard = 4
)

var n [16]int

func initGrid() {
for i := 0; i < 16; i++ {
n[i] = i + 1
}
}

func setDiff(level int) {
moves := 3
if level == hard {
moves = 12
}
rc := make([]int, 0, 4)
for i := 0; i < moves; i++ {
rc = rc[:0]
r := rand.Intn(2)
s := rand.Intn(4)
if r == 0 { // rotate random row
for j := s * 4; j < (s+1)*4; j++ {
rc = append(rc, j)
}
} else { // rotate random column
for j := s; j < s+16; j += 4 {
rc = append(rc, j)
}
}
var rca [4]int
copy(rca[:], rc)
rotate(rca)
if hasWon() { // do it again
i = -1
}
}
fmt.Println("Target is", moves, "moves.")
}

func drawGrid() {
fmt.Println()
fmt.Println(" D1 D2 D3 D4")
fmt.Println(" ╔════╦════╦════╦════╗")
fmt.Printf("R1 ║ %2d ║ %2d ║ %2d ║ %2d ║ L1\n", n[0], n[1], n[2], n[3])
fmt.Println(" ╠════╬════╬════╬════╣")
fmt.Printf("R2 ║ %2d ║ %2d ║ %2d ║ %2d ║ L2\n", n[4], n[5], n[6], n[7])
fmt.Println(" ╠════╬════╬════╬════╣")
fmt.Printf("R3 ║ %2d ║ %2d ║ %2d ║ %2d ║ L3\n", n[8], n[9], n[10], n[11])
fmt.Println(" ╠════╬════╬════╬════╣")
fmt.Printf("R4 ║ %2d ║ %2d ║ %2d ║ %2d ║ L4\n", n[12], n[13], n[14], n[15])
fmt.Println(" ╚════╩════╩════╩════╝")
fmt.Println(" U1 U2 U3 U4\n")
}

func rotate(ix [4]int) {
last := n[ix[3]]
for i := 3; i >= 1; i-- {
n[ix[i]] = n[ix[i-1]]
}
n[ix[0]] = last
}

func hasWon() bool {
for i := 0; i < 16; i++ {
if n[i] != i+1 {
return false
}
}
return true
}

func check(err error) {
if err != nil {
log.Fatal(err)
}
}

func main() {
initGrid()
rand.Seed(time.Now().UnixNano())
level := easy
scanner := bufio.NewScanner(os.Stdin)
for {
fmt.Print("Enter difficulty level easy or hard E/H : ")
scanner.Scan()
diff := strings.ToUpper(strings.TrimSpace(scanner.Text()))
if diff != "E" && diff != "H" {
fmt.Println("Invalid response, try again.")
} else {
if diff == "H" {
level = hard
}
break
}
}
check(scanner.Err())
setDiff(level)
var ix [4]int
fmt.Println("When entering moves, you can also enter Q to quit or S to start again.")
moves := 0
outer:
for {
drawGrid()
if hasWon() {
fmt.Println("Congratulations, you have won the game in", moves, "moves!!")
return
}
for {
fmt.Println("Moves so far =", moves, "\n")
fmt.Print("Enter move : ")
scanner.Scan()
move := strings.ToUpper(strings.TrimSpace(scanner.Text()))
check(scanner.Err())
switch move {
case "D1", "D2", "D3", "D4":
c := int(move[1] - 49)
ix[0] = 0 + c
ix[1] = 4 + c
ix[2] = 8 + c
ix[3] = 12 + c
rotate(ix)
moves++
continue outer
case "L1", "L2", "L3", "L4":
c := int(move[1] - 49)
ix[0] = 3 + 4*c
ix[1] = 2 + 4*c
ix[2] = 1 + 4*c
ix[3] = 0 + 4*c
rotate(ix)
moves++
continue outer
case "U1", "U2", "U3", "U4":
c := int(move[1] - 49)
ix[0] = 12 + c
ix[1] = 8 + c
ix[2] = 4 + c
ix[3] = 0 + c
rotate(ix)
moves++
continue outer
case "R1", "R2", "R3", "R4":
c := int(move[1] - 49)
ix[0] = 0 + 4*c
ix[1] = 1 + 4*c
ix[2] = 2 + 4*c
ix[3] = 3 + 4*c
rotate(ix)
moves++
continue outer
case "Q":
return
case "S":
initGrid()
setDiff(level)
moves = 0
continue outer
default:
fmt.Println("Invalid move, try again.")
}
}
}
}</syntaxhighlight>

{{out}}
Sample game:
<pre>
Enter difficulty level easy or hard E/H : e
Target is 3 moves.
When entering moves, you can also enter Q to quit or S to start again.

D1 D2 D3 D4
╔════╦════╦════╦════╗
R1 ║ 1 ║ 2 ║ 3 ║ 4 ║ L1
╠════╬════╬════╬════╣
R2 ║ 7 ║ 8 ║ 5 ║ 6 ║ L2
╠════╬════╬════╬════╣
R3 ║ 9 ║ 10 ║ 11 ║ 12 ║ L3
╠════╬════╬════╬════╣
R4 ║ 16 ║ 13 ║ 14 ║ 15 ║ L4
╚════╩════╩════╩════╝
U1 U2 U3 U4

Moves so far = 0

Enter move : l4

D1 D2 D3 D4
╔════╦════╦════╦════╗
R1 ║ 1 ║ 2 ║ 3 ║ 4 ║ L1
╠════╬════╬════╬════╣
R2 ║ 7 ║ 8 ║ 5 ║ 6 ║ L2
╠════╬════╬════╬════╣
R3 ║ 9 ║ 10 ║ 11 ║ 12 ║ L3
╠════╬════╬════╬════╣
R4 ║ 13 ║ 14 ║ 15 ║ 16 ║ L4
╚════╩════╩════╩════╝
U1 U2 U3 U4

Moves so far = 1

Enter move : l2

D1 D2 D3 D4
╔════╦════╦════╦════╗
R1 ║ 1 ║ 2 ║ 3 ║ 4 ║ L1
╠════╬════╬════╬════╣
R2 ║ 8 ║ 5 ║ 6 ║ 7 ║ L2
╠════╬════╬════╬════╣
R3 ║ 9 ║ 10 ║ 11 ║ 12 ║ L3
╠════╬════╬════╬════╣
R4 ║ 13 ║ 14 ║ 15 ║ 16 ║ L4
╚════╩════╩════╩════╝
U1 U2 U3 U4

Moves so far = 2

Enter move : l2

D1 D2 D3 D4
╔════╦════╦════╦════╗
R1 ║ 1 ║ 2 ║ 3 ║ 4 ║ L1
╠════╬════╬════╬════╣
R2 ║ 5 ║ 6 ║ 7 ║ 8 ║ L2
╠════╬════╬════╬════╣
R3 ║ 9 ║ 10 ║ 11 ║ 12 ║ L3
╠════╬════╬════╬════╣
R4 ║ 13 ║ 14 ║ 15 ║ 16 ║ L4
╚════╩════╩════╩════╝
U1 U2 U3 U4

Congratulations, you have won the game in 3 moves!!
</pre>

=={{header|J}}==
Assumes a recent release of jqt:<syntaxhighlight lang="j">require'ide/qt/gl2'
coinsert'jgl2'

NB. event handlers
game_reset_button=: {{ draw COUNT=: #SETUP=: EMPTY [BOARD=: WIN }}
game_restart_button=: {{ draw COUNT=: 0 [rotate"1 SETUP [BOARD=: WIN }}
game_easy_button=: {{ setup 3 }}
game_hard_button=: {{ setup 15 }}
game_board_mbldown=: {{
loc=. (20+40*i.5)I.2{._".sysdata
if. 1=#ndx=. loc -. 0 5 do.
side=. 2#.<:>.loc%4 NB. _2: left, _1 top, 1 bottom, 2 right
draw rotate side, ndx
end.
}}

NB. game logic
BOARD=: WIN=: 1+i.4 4
message=: {{
color=. (COUNT>#SETUP){::;:'black red'
A=. '<span style="color: ',color,'">' [Z=. '</span>'
if. BOARD-:WIN do. A,'You win',Z return. end.
A,(":COUNT),Z,' of ',":#SETUP
}}
setup=: {{ game_restart_button SETUP=: (_2 _1 1 2{~?y#4),.1+?y#4 }}
rotate=: {{
COUNT=: COUNT+1
'side ndx'=. y-0 1
flip=. |: if. 2=|side do. flip=. ] end.
BOARD=: flip ((*side)|.ndx{flip BOARD) ndx} flip BOARD
}}

NB. rendering
wd {{)n
pc game closeok;
cc board isidraw;
set board wh 200 200;
cc msg static center;
bin h;
cc easy button;
set easy tooltip start game which can be completed in 3 moves;
cc hard button;
set hard tooltip start game which can be completed in 15 moves;
bin z; bin h;
cc restart button;
cc reset button;
set reset tooltip set board to initial position, ending any current game;
pshow;
}}

draw=: {{
glclear''
glbrush glrgb 3#224 NB. silver
glrect 0 0 200 200
glbrush glrgb 0 0 255 NB. blue
glrect T=:20 20 40 40+"1]40*4 4 1 1#:i.4 4
glbrush glrgb 255 255 0 NB. yellow
glpolygon (,200-])(,;"1@(_2<@|.\"1]))0 30 0 50 10 40+"1(i.4)*/6$0 40
gltextcolor glrgb 3#255 NB. white
glfont '"lucidia console" 16'
BOARD {{ gltext ":x [ gltextxy y+5 0*_1^1<#":x }}"_2(30+40*4 4#:|:i.4 4)
if. EMPTY-:SETUP do.
wd {{)n
set msg text <b>easy</b> or <b>hard</b> to start;
set restart enable 0;
set restart caption;
}} else. wd {{)n
set msg text MESSAGE;
set restart enable 1;
set restart caption restart;
}} rplc 'MESSAGE';message''
end.
glpaint''
}}

NB. start:
game_reset_button''</syntaxhighlight>

=={{header|Javascript}}==
Try it [http://paulo-jorente.de/webgames/repos/16Puzzle/ here].

You'll also need a html file:
<pre>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link href="https://fonts.googleapis.com/css?family=Ubuntu+Mono&display=swap" rel="stylesheet">
<link rel="stylesheet" type="text/css" media="screen" href="./css/main.css">
<title>16 Puzzle</title>
</head>
<body>
<div id="done">WELL DONE!</div>
<div id="board"></div>
<div id="moves"></div>
<button id="shuffle">SHUFFLE</button>
<script src="./src/index.js" type="module"></script>
</body>
</html>
</pre>
And css file:
<pre>
* {
margin: 0;
border: 0;
text-align: center;
font-family: 'Ubuntu Mono', monospace;
user-select: none;
}
button {
border-radius: 5px;
width: 300px;
height: 80px;
font-size: 40px;
margin-top: 60px;
}
#board {
width: 410px;
height: 410px;
margin: 120px auto 30px auto;
}
#done {
font-size: 140px;
padding: 20px;
color: #fff;
background-color: rgba(0, 23, 56, .5);
border: 1px solid rgb(0, 90, 220);
width: 700px;
position: absolute;
top: 250px;
left: calc(50% - 380px);
}
#moves {
font-size: 40px;
line-height: 80px;
height: 80px;
width: 300px;
margin: auto;
border: 1px solid #000;
border-radius: 5px;
}
.btn,
.numbers,
.hide {
float: left;
width: 64px;
height: 64px;
line-height: 65px;
font-size: 40px;
border: 1px solid black;
color: black;
background-color: white;
cursor: none;
margin: 1px;
transition: all .3s;
}
.btn:hover {
background-color: rgba(71, 231, 71, 0.5);
cursor: pointer;
}
.hide {
border: 1px solid white;
cursor: none;
}
</pre>
<syntaxhighlight lang="javascript">
class Puzzle {
constructor() {
this.moves;
this.started;

this.board = document.getElementById("board");
document.getElementById("shuffle").addEventListener("click", () => {
this.shuffle();
});
this.reset();
}

reset() {
while (this.board.hasChildNodes()) {
this.board.removeChild(this.board.firstChild);
}

this.moves = 0;
this.started = false;
document.getElementById("moves").innerText = this.moves;
document.getElementById("done").style.visibility = "hidden";

let t = 1;
for (let y = 0; y < 6; y++) {
for (let x = 0; x < 6; x++) {
const d = document.createElement("div");
d.id = `${x}_${y}`;
if (y === 0 || x === 0 || y === 5 || x === 5) {
if (((y === 0 || y === 5) && (x === 0 || x === 5))) {
d.className = "hide";
} else {
d.className = "btn";
if (y === 0) {
d.innerText = "🡇";
d.func = () => {
this.rollDownRight(x, true);
};
} else if (y === 5) {
d.innerText = "🡅";
d.func = () => {
this.rollUpLeft(x, true);
};
}
if (x === 0) {
d.innerText = "🡆";
d.func = () => {
this.rollDownRight(y, false);
};
} else if (x === 5) {
d.innerText = "🡄";
d.func = () => {
this.rollUpLeft(y, false);
};
}
d.addEventListener("click", (ev) => {
ev.srcElement.func();
})
}
} else {
d.className = "numbers";
d.innerText = `${t}`;
t++;
}
this.board.appendChild(d);
}
}
document.getElementById("shuffle").innerText = "SHUFFLE";
}

shuffle() {
if (this.started) {
this.reset();
} else {
this.started = true;
const e = Math.floor(Math.random() * 30) + 30;
for (let z = 0; z < e; z++) {
switch (Math.floor(Math.random() * 4)) {
case 0:
this.rollDownRight(Math.floor(Math.random() * 4) + 1, false);
break;
case 1:
this.rollUpLeft(Math.floor(Math.random() * 4) + 1, true);
break;
case 2:
this.rollUpLeft(Math.floor(Math.random() * 4) + 1, false);
break;
case 3:
this.rollDownRight(Math.floor(Math.random() * 4) + 1, true);
break;
}
}
this.moves = 0;
document.getElementById("moves").innerText = this.moves;
document.getElementById("shuffle").innerText = "RESTART";
}
}

getElements(l, col) {
const z = Array.from(document.querySelectorAll(".numbers"));
for (let e = 15; e > -1; e--) {
if (z[e].id[(col ? 0 : 2)] != l) {
z.splice(e, 1)
}
}
return z;
}

rollDownRight(x, col) {
if (!this.started) return;
const z = this.getElements(x, col),
a = z[3].innerText;
for (let r = 3; r > 0; r--) {
z[r].innerText = z[r - 1].innerText;
}
z[0].innerText = a;
this.updateMoves();
this.checkSolved();
}

rollUpLeft(x, col) {
if (!this.started) return;
const z = this.getElements(x, col),
a = z[0].innerText;
for (let r = 0; r < 3; r++) {
z[r].innerText = z[r + 1].innerText;
}
z[3].innerText = a;
this.updateMoves();
this.checkSolved();
}

updateMoves() {
this.moves++;
document.getElementById("moves").innerText = this.moves;
}

checkSolved() {
function check() {
const z = document.querySelectorAll(".numbers");
let u = 1;
for (let r of z) {
if (r.innerText != u) return false;
u++;
}
return true;
}
if (this.started && check()) {
document.getElementById("done").style.visibility = "visible";
}
}
}

new Puzzle();
</syntaxhighlight>

=={{header|Julia}}==
<syntaxhighlight lang="julia">using Gtk, Random

function puzzle16app(bsize)
aclock, clock = "\u27f2", "\u27f3"
win = GtkWindow("16 Game", 300, 300) |> (GtkFrame() |> (box = GtkBox(:v)))
toolbar = GtkToolbar()
newgame = GtkToolButton("New Game")
set_gtk_property!(newgame, :label, "New Game")
set_gtk_property!(newgame, :is_important, true)
push!(toolbar, newgame)
grid = GtkGrid()
map(w -> push!(box, w),[toolbar, grid])
buttons = Array{Gtk.GtkButtonLeaf,2}(undef, bsize + 2, bsize + 2)
for i in 1:bsize+2, j in 1:bsize+2
grid[i,j] = buttons[i,j] = GtkButton()
set_gtk_property!(buttons[i,j], :expand, true)
end

inorder = string.(reshape(1:bsize*bsize, bsize, bsize))
puzzle = shuffle(inorder)
rotatecol(puzzle, col, n) = puzzle[:, col] .= circshift(puzzle[:, col], n)
rotaterow(puzzle, row, n) = puzzle[row, :] .= circshift(puzzle[row, :], n)
iswon() = puzzle == inorder
won = false

function findrowcol(button)
for i in 1:bsize+2, j in 1:bsize+2
if buttons[i, j] == button
return i, j
end
end
return 0, 0
end

function playerclicked(button)
if !won
i, j = findrowcol(button)
if i == 1
rotatecol(puzzle, j - 1, 1)
elseif i == bsize + 2
rotatecol(puzzle, j - 1, -1)
elseif j == 1
rotaterow(puzzle, i - 1, 1)
elseif j == bsize + 2
rotaterow(puzzle, i - 1, -1)
end
end
update!()
end

function setup!()
for i in 1:bsize+2, j in 1:bsize+2
if 1 < j < bsize + 2
if i == 1
signal_connect(playerclicked, buttons[i, j], "clicked")
elseif i == bsize + 2
signal_connect(playerclicked, buttons[i, j], "clicked")
end
elseif 1 < i < bsize + 2
if j == 1
signal_connect(playerclicked, buttons[i, j], "clicked")
elseif j == bsize + 2
signal_connect(playerclicked, buttons[i, j], "clicked")
end
end
end
end

function update!()
for i in 1:bsize+2, j in 1:bsize+2
if 1 < j < bsize + 2
if i == 1
set_gtk_property!(buttons[i, j], :label, clock)
elseif i == bsize + 2
set_gtk_property!(buttons[i, j], :label, aclock)
else
set_gtk_property!(buttons[i, j], :label, puzzle[i-1, j-1])
end
elseif 1 < i < bsize + 2
if j == 1
set_gtk_property!(buttons[i, j], :label, clock)
elseif j == bsize + 2
set_gtk_property!(buttons[i, j], :label, aclock)
end
end
end
if iswon()
won = true
info_dialog("Game over.\nScore: $score", win)
end
showall(win)
end

function initialize!(w)
puzzle = shuffle(inorder)
won = false
update!()
end
setup!()
condition = Condition()
endit(w) = notify(condition)
signal_connect(initialize!, newgame, :clicked)
signal_connect(endit, win, :destroy)
initialize!(win)
showall(win)
wait(condition)
end

puzzle16app(4)
</syntaxhighlight>

=={{header|Nim}}==
{{trans|Julia}}
{{libheader|gintro}}
Not a direct translation as there are a lot of differences, but, at least, the graphical interface is similar and the logic is the same.
<syntaxhighlight lang="nim">import random, sequtils, strutils
import gintro/[glib, gobject, gtk, gio]

const

BoardSize = 4
GridSize = BoardSize + 2
Clock = "\u27f2"
AClock = "\u27f3"

type

Value = 1..16
Puzzle = array[BoardSize, array[BoardSize, Value]]

PuzzleApp = ref object of Application
inOrder: Puzzle # Target grid.
puzzle: Puzzle # Current grid.
buttons: array[GridSize, array[GridSize, Button]] # Button grid.
won: bool # True if game won.
moves: Natural # Count of moves.

#---------------------------------------------------------------------------------------------------

proc initPuzzle(puzzle: var Puzzle; data: openArray[Value]) =
## Initialize the puzzle with a list of values.
var i = 0
for row in puzzle.mitems:
for cell in row.mitems:
cell = data[i]
inc i

#---------------------------------------------------------------------------------------------------

proc showMessage(app: PuzzleApp) =
## As "gintro" doesn't provide "MessageDialog" yet, we will use a simple dialog.
let dialog = newDialog()
dialog.setModal(true)
let label = newLabel("You won in $# move(s)".format(app.moves))
dialog.contentArea.add(label)
discard dialog.addButton("Ok", ord(ResponseType.ok))
dialog.showAll()
discard dialog.run()
dialog.destroy()

#---------------------------------------------------------------------------------------------------

proc onQuit(button: ToolButton; window: ApplicationWindow) =
## Procedure called when clicking quit button.
window.destroy()

#---------------------------------------------------------------------------------------------------

proc rotateRow(puzzle: var Puzzle; row: Natural; left: bool) =
## Rotate a row left or right.
if left:
let first = puzzle[row][0]
for i in 1..puzzle.high: puzzle[row][i-1] = puzzle[row][i]
puzzle[row][^1] = first
else:
let last = puzzle[row][^1]
for i in countdown(puzzle.high, 1): puzzle[row][i] = puzzle[row][i-1]
puzzle[row][0] = last

#---------------------------------------------------------------------------------------------------

proc rotateCol(puzzle: var Puzzle; col: Natural; up: bool) =
## Rotate a column up or down.
if up:
let first = puzzle[0][col]
for i in 1..puzzle.high: puzzle[i-1][col] = puzzle[i][col]
puzzle[^1][col] = first
else:
let last = puzzle[^1][col]
for i in countdown(puzzle[0].high, 1): puzzle[i][col] =puzzle[i-1][col]
puzzle[0][col] = last

#---------------------------------------------------------------------------------------------------

proc findRowCol(app: PuzzleApp; button: Button): (int, int) =
## Find the row and column of a button.
for i in [0, BoardSize+1]:
for j in 1..Boardsize:
if app.buttons[i][j] == button: return (i, j)
for j in [0, BoardSize+1]:
for i in 1..Boardsize:
if app.buttons[i][j] == button: return (i, j)

#---------------------------------------------------------------------------------------------------

proc update(app: PuzzleApp) =
## Update the grid.
for i in 0..BoardSize+1:
for j in 0..BoardSize+1:
if j in 1..BoardSize:
if i == 0:
app.buttons[i][j].setLabel(Clock)
elif i == BoardSize + 1:
app.buttons[i][j].setLabel(AClock)
else:
app.buttons[i][j].setLabel($app.puzzle[i-1][j-1])
elif i in 1..BoardSize:
if j == 0:
app.buttons[i][j].setLabel(Clock)
elif j == BoardSize + 1:
app.buttons[i][j].setLabel(AClock)

if app.puzzle == app.inOrder:
app.won = true
app.showMessage()

#---------------------------------------------------------------------------------------------------

proc onClick(button: Button; app: PuzzleApp) =
## Procedure called when the user cliked a grid button.
if not app.won:
inc app.moves
let (i, j) = app.findRowCol(button)
if i == 0:
app.puzzle.rotateCol(j - 1, true)
elif i == BoardSize + 1:
app.puzzle.rotateCol(j - 1, false)
elif j == 0:
app.puzzle.rotateRow(i - 1, true)
elif j == BoardSize + 1:
app.puzzle.rotateRow(i - 1, false)
app.update()

#---------------------------------------------------------------------------------------------------

proc newGame(button: ToolButton; app: PuzzleApp) =
## Prepare a new game.
var values = toSeq(Value.low..Value.high)
values.shuffle()
app.puzzle.initPuzzle(values)
app.won = false
app.update()

#---------------------------------------------------------------------------------------------------

proc activate(app: PuzzleApp) =
## Activate the application.

let window = app.newApplicationWindow()
window.setTitle("16 puzzle game")
window.setSizeRequest(300, 340)

let box = newBox(Orientation.vertical, 0)
window.add box

let toolbar = newToolbar()
let newGameButton = newToolButton(label = "New game")
toolbar.insert(newGameButton, 0)
let quitButton = newToolButton(label = "Quit")
toolbar.insert(quitButton, 1)
box.add toolbar

let grid = newGrid()
box.add grid

for i in 0..BoardSize+1:
for j in 0..BoardSize+1:
let button = newButton()
button.setHexpand(true)
button.setVexpand(true)
app.buttons[i][j] = button
grid.attach(button, j, i, 1, 1)

var values = toSeq(Value.low..Value.high)
app.inOrder.initPuzzle(values)
values.shuffle()
app.puzzle.initPuzzle(values)

for i in [0, BoardSize + 1]:
for j in 1..BoardSize:
app.buttons[i][j].connect("clicked", onClick, app)
for j in [0, BoardSize + 1]:
for i in 1..BoardSize:
app.buttons[i][j].connect("clicked", onClick, app)

newGameButton.connect("clicked", newGame, app)
quitButton.connect("clicked", onQuit, window)

app.won = false
app.update()

window.showAll()

#———————————————————————————————————————————————————————————————————————————————————————————————————

randomize()
let app = newApplication(PuzzleApp, "Rosetta.Puzzle16Game")
discard app.connect("activate", activate)
discard app.run()</syntaxhighlight>

=={{header|Perl}}==
<syntaxhighlight lang="perl">#!/usr/bin/perl

use strict; # http://www.rosettacode.org/wiki/16_Puzzle_Game
use warnings;
use List::Util qw( any );
use Tk;

my $size = $ARGV[0] // 4;
my $width = length $size ** 2;
my $message = '';
my $steps;
my @board;
my @again;
my $easy = 3;

my $mw = MainWindow->new( -title => '16 Puzzle in Tk' );
$mw->geometry( '+470+300' );
$mw->optionAdd('*font' => 'sans 14');
my $frame = $mw->Frame(-bg => 'gray', -relief => 'ridge',
-borderwidth => 5)->pack;
my $label = $mw->Label( -textvariable => \$message, -font => 'times-bold 30',
)->pack;
$mw->Button( -text => "Exit", -command => sub {$mw->destroy},
)->pack(-side => 'right');
$mw->Button( -text => "Reset", -command => sub {
@board = @again;
show();
$message = $steps = 0;
$label->configure(-fg => 'black');
},)->pack(-side => 'right');
$mw->Button( -text => "Easy", -command => sub {$easy = 3; generate()},
)->pack(-side => 'left');
$mw->Button( -text => "Hard", -command => sub {$easy = 12; generate()},
)->pack(-side => 'left');

my @cells = map {
$frame->Label(-text => $_, -relief => 'sunken', -borderwidth => 2,
-fg => 'white', -bg => 'blue', -font => 'sans 24',
-padx => 7, -pady => 7, -width => $width,
)->grid(-row => int( $_ / $size + 2 ), -column => $_ % $size + 2,
-sticky => "nsew",
) } 0 .. $size ** 2 - 1;

for my $i (1 .. $size)
{
$frame->Button(-text => ">", -command => sub {move("R$i") },
)->grid(-row => $i + 1, -column => 1, -sticky => "nsew");
$frame->Button(-text => "<", -command => sub {move("L$i") },
)->grid(-row => $i + 1, -column => $size + 2, -sticky => "nsew");
$frame->Button(-text => "v", -command => sub {move("D$i") },
)->grid(-row => 1, -column => $i + 1, -sticky => "nsew");
$frame->Button(-text => "^", -command => sub {move("U$i") },
)->grid(-row => $size + 2, -column => $i + 1, -sticky => "nsew");
}

generate();

MainLoop;
-M $0 < 0 and exec $0, @ARGV; # restart if source file modified since start

sub randommove { move( qw(U D L R)[rand 4] . int 1 + rand $size ) }

sub show { $cells[$_]->configure(-text => $board[$_]) for 0 .. $size ** 2 - 1 }

sub success { not any { $_ + 1 != $board[$_] } 0 .. $size ** 2 - 1 }

sub move
{
my ($dir, $index) = split //, shift;
$index--;
my @from = map {
$dir =~ /L|R/i ? $_ + $size * $index : $_ * $size + $index
} 0 .. $size - 1;
@board[@from] = (@board[@from])[ ($dir =~ /L|U/i || -1) .. $size - 1, 0 ];
show();
$message = ++$steps;
$label->configure(-fg => success() ? 'red' : 'black');
success() and $message = "Solved in $steps";
}

sub generate
{
@board = 1 .. $size ** 2;
randommove() for 1 .. 1 + int rand $easy;
success() and randommove();
@again = @board;
$message = $steps = 0;
}</syntaxhighlight>

=={{header|Phix}}==
NB arrow keys not tested on linux, but "UDLR" should work...

<!--<syntaxhighlight lang="phix">-->
<span style="color: #008080;">constant</span> <span style="color: #000000;">level</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">5<span style="color: #0000FF;">,</span>
<span style="color: #000000;">ESC<span style="color: #0000FF;">=<span style="color: #000000;">27<span style="color: #0000FF;">,</span> <span style="color: #000000;">UP<span style="color: #0000FF;">=<span style="color: #000000;">328<span style="color: #0000FF;">,</span> <span style="color: #000000;">DOWN<span style="color: #0000FF;">=<span style="color: #000000;">336<span style="color: #0000FF;">,</span> <span style="color: #000000;">LEFT<span style="color: #0000FF;">=<span style="color: #000000;">331<span style="color: #0000FF;">,</span> <span style="color: #000000;">RIGHT<span style="color: #0000FF;">=<span style="color: #000000;">333</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">board</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">tagset<span style="color: #0000FF;">(<span style="color: #000000;">16<span style="color: #0000FF;">)<span style="color: #0000FF;">,</span> <span style="color: #000000;">solve</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">board</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">print_board<span style="color: #0000FF;">(<span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf<span style="color: #0000FF;">(<span style="color: #000000;">1<span style="color: #0000FF;">,<span style="color: #008000;">" 1 2 3 4\n"<span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">r<span style="color: #0000FF;">=<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: #7060A8;">printf<span style="color: #0000FF;">(<span style="color: #000000;">1<span style="color: #0000FF;">,<span style="color: #008000;">"%d: %2d %2d %2d %2d\n"<span style="color: #0000FF;">,<span style="color: #000000;">r<span style="color: #0000FF;">&<span style="color: #000000;">board<span style="color: #0000FF;">[<span style="color: #000000;">r<span style="color: #0000FF;">*<span style="color: #000000;">4<span style="color: #0000FF;">-<span style="color: #000000;">3<span style="color: #0000FF;">..<span style="color: #000000;">r<span style="color: #0000FF;">*<span style="color: #000000;">4<span style="color: #0000FF;">]<span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">puts<span style="color: #0000FF;">(<span style="color: #000000;">1<span style="color: #0000FF;">,<span style="color: #008000;">"\n"<span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">move<span style="color: #0000FF;">(<span style="color: #004080;">integer</span> <span style="color: #000000;">d<span style="color: #0000FF;">,<span style="color: #000000;">rc<span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- d is 1..4 for up/down/left/right
-- rc is 1..4 for row(d>=3)/column(d<=2)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">idx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat<span style="color: #0000FF;">(<span style="color: #000000;">0<span style="color: #0000FF;">,<span style="color: #000000;">4<span style="color: #0000FF;">)<span style="color: #0000FF;">,</span>
<span style="color: #000000;">tiles</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat<span style="color: #0000FF;">(<span style="color: #000000;">0<span style="color: #0000FF;">,<span style="color: #000000;">4<span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i<span style="color: #0000FF;">=<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;">idx<span style="color: #0000FF;">[<span style="color: #000000;">i<span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff<span style="color: #0000FF;">(<span style="color: #000000;">d<span style="color: #0000FF;"><=<span style="color: #000000;">2<span style="color: #0000FF;">?<span style="color: #000000;">rc<span style="color: #0000FF;">+<span style="color: #0000FF;">(<span style="color: #000000;">i<span style="color: #0000FF;">-<span style="color: #000000;">1<span style="color: #0000FF;">)<span style="color: #0000FF;">*<span style="color: #000000;">4<span style="color: #0000FF;">:<span style="color: #0000FF;">(<span style="color: #000000;">rc<span style="color: #0000FF;">-<span style="color: #000000;">1<span style="color: #0000FF;">)<span style="color: #0000FF;">*<span style="color: #000000;">4<span style="color: #0000FF;">+<span style="color: #000000;">i<span style="color: #0000FF;">)</span>
<span style="color: #000000;">tiles<span style="color: #0000FF;">[<span style="color: #000000;">i<span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">board<span style="color: #0000FF;">[<span style="color: #000000;">idx<span style="color: #0000FF;">[<span style="color: #000000;">i<span style="color: #0000FF;">]<span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000080;font-style:italic;">-- ?{d,rc,idx}</span>
<span style="color: #000000;">idx</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff<span style="color: #0000FF;">(<span style="color: #7060A8;">mod<span style="color: #0000FF;">(<span style="color: #000000;">d<span style="color: #0000FF;">,<span style="color: #000000;">2<span style="color: #0000FF;">)<span style="color: #0000FF;">?<span style="color: #000000;">idx<span style="color: #0000FF;">[<span style="color: #000000;">4<span style="color: #0000FF;">]<span style="color: #0000FF;">&<span style="color: #000000;">idx<span style="color: #0000FF;">[<span style="color: #000000;">1<span style="color: #0000FF;">..<span style="color: #000000;">3<span style="color: #0000FF;">]<span style="color: #0000FF;">:<span style="color: #000000;">idx<span style="color: #0000FF;">[<span style="color: #000000;">2<span style="color: #0000FF;">..<span style="color: #000000;">4<span style="color: #0000FF;">]<span style="color: #0000FF;">&<span style="color: #000000;">idx<span style="color: #0000FF;">[<span style="color: #000000;">1<span style="color: #0000FF;">]<span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i<span style="color: #0000FF;">=<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;">board<span style="color: #0000FF;">[<span style="color: #000000;">idx<span style="color: #0000FF;">[<span style="color: #000000;">i<span style="color: #0000FF;">]<span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tiles<span style="color: #0000FF;">[<span style="color: #000000;">i<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;">procedure</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i<span style="color: #0000FF;">=<span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">level</span> <span style="color: #008080;">do</span> <span style="color: #000000;">move<span style="color: #0000FF;">(<span style="color: #7060A8;">rand<span style="color: #0000FF;">(<span style="color: #000000;">4<span style="color: #0000FF;">)<span style="color: #0000FF;">,<span style="color: #7060A8;">rand<span style="color: #0000FF;">(<span style="color: #000000;">4<span style="color: #0000FF;">)<span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">print_board<span style="color: #0000FF;">(<span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">board<span style="color: #0000FF;">=<span style="color: #000000;">solve</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">puts<span style="color: #0000FF;">(<span style="color: #000000;">1<span style="color: #0000FF;">,<span style="color: #008000;">"Solved!\n"<span style="color: #0000FF;">)</span>
<span style="color: #008080;">exit</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">puts<span style="color: #0000FF;">(<span style="color: #000000;">1<span style="color: #0000FF;">,<span style="color: #008000;">"Your move (escape|Up/Down|Left/Right & 1/2/3/4):"<span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">d<span style="color: #0000FF;">,</span> <span style="color: #000000;">rc</span>
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">d</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find<span style="color: #0000FF;">(<span style="color: #7060A8;">upper<span style="color: #0000FF;">(<span style="color: #7060A8;">wait_key<span style="color: #0000FF;">(<span style="color: #0000FF;">)<span style="color: #0000FF;">)<span style="color: #0000FF;">,<span style="color: #0000FF;">{<span style="color: #000000;">ESC<span style="color: #0000FF;">,<span style="color: #000000;">UP<span style="color: #0000FF;">,<span style="color: #000000;">DOWN<span style="color: #0000FF;">,<span style="color: #000000;">LEFT<span style="color: #0000FF;">,<span style="color: #000000;">RIGHT<span style="color: #0000FF;">}<span style="color: #0000FF;">&<span style="color: #008000;">"UDLR"<span style="color: #0000FF;">)<span style="color: #0000FF;">-<span style="color: #000000;">1</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">d<span style="color: #0000FF;">!=<span style="color: #0000FF;">-<span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</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;">if</span> <span style="color: #000000;">d<span style="color: #0000FF;">=<span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">puts<span style="color: #0000FF;">(<span style="color: #000000;">1<span style="color: #0000FF;">,<span style="color: #008000;">"\n\nYou gave up!\n"<span style="color: #0000FF;">)</span>
<span style="color: #008080;">exit</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">d<span style="color: #0000FF;">><span style="color: #000000;">4</span> <span style="color: #008080;">then</span> <span style="color: #000000;">d<span style="color: #0000FF;">-=<span style="color: #000000;">4</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">puts<span style="color: #0000FF;">(<span style="color: #000000;">1<span style="color: #0000FF;">,<span style="color: #008000;">"UDLR"<span style="color: #0000FF;">[<span style="color: #000000;">d<span style="color: #0000FF;">]<span style="color: #0000FF;">)</span>
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">rc</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find<span style="color: #0000FF;">(<span style="color: #7060A8;">upper<span style="color: #0000FF;">(<span style="color: #7060A8;">wait_key<span style="color: #0000FF;">(<span style="color: #0000FF;">)<span style="color: #0000FF;">)<span style="color: #0000FF;">,<span style="color: #000000;">ESC<span style="color: #0000FF;">&<span style="color: #008000;">"1234UDLR"<span style="color: #0000FF;">&<span style="color: #0000FF;">{<span style="color: #000000;">UP<span style="color: #0000FF;">,<span style="color: #000000;">DOWN<span style="color: #0000FF;">,<span style="color: #000000;">LEFT<span style="color: #0000FF;">,<span style="color: #000000;">RIGHT<span style="color: #0000FF;">}<span style="color: #0000FF;">)<span style="color: #0000FF;">-<span style="color: #000000;">1</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">rc<span style="color: #0000FF;">><span style="color: #000000;">4</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">rc<span style="color: #0000FF;">><span style="color: #000000;">8</span> <span style="color: #008080;">then</span> <span style="color: #000000;">rc</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">4</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">d</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rc<span style="color: #0000FF;">-<span style="color: #000000;">4</span>
<span style="color: #7060A8;">puts<span style="color: #0000FF;">(<span style="color: #000000;">1<span style="color: #0000FF;">,<span style="color: #008000;">"\b \b"<span style="color: #0000FF;">&<span style="color: #008000;">"UDLR"<span style="color: #0000FF;">[<span style="color: #000000;">d<span style="color: #0000FF;">]<span style="color: #0000FF;">)</span>
<span style="color: #008080;">else</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">rc<span style="color: #0000FF;">!=<span style="color: #0000FF;">-<span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</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;">while</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">rc<span style="color: #0000FF;">=<span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">puts<span style="color: #0000FF;">(<span style="color: #000000;">1<span style="color: #0000FF;">,<span style="color: #008000;">"\b \b"<span style="color: #0000FF;">)</span>
<span style="color: #008080;">else</span>
<span style="color: #7060A8;">printf<span style="color: #0000FF;">(<span style="color: #000000;">1<span style="color: #0000FF;">,<span style="color: #008000;">"%d\n\n"<span style="color: #0000FF;">,<span style="color: #000000;">rc<span style="color: #0000FF;">)</span>
<span style="color: #000000;">move<span style="color: #0000FF;">(<span style="color: #000000;">d<span style="color: #0000FF;">,<span style="color: #000000;">rc<span style="color: #0000FF;">)</span>
<span style="color: #008080;">exit</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;">if</span> <span style="color: #000000;">d<span style="color: #0000FF;">=<span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while
<!--</syntaxhighlight>-->
{{out}}
(a level 2 game)
<pre>
1 2 3 4
1: 1 2 7 4
2: 5 6 11 8
3: 9 10 16 12
4: 14 15 3 13

Your move (escape|Up/Down|Left/Right & 1/2/3/4):D3

1 2 3 4
1: 1 2 3 4
2: 5 6 7 8
3: 9 10 11 12
4: 14 15 16 13

Your move (escape|Up/Down|Left/Right & 1/2/3/4):R4

1 2 3 4
1: 1 2 3 4
2: 5 6 7 8
3: 9 10 11 12
4: 13 14 15 16

Solved!
</pre>

=={{header|Raku}}==
For brevity, changed to zero-based and skipped some error handling.
{{trans|Go}}
<syntaxhighlight lang="raku" line># 20210914 Raku programming solution

my (\easy,\hard) = 1,4 ; my @n = ^16; my \level = $ = easy ; my \moves = $ = 0;

sub hasWon { @n eq ^16 }

sub setDiff($level) {
say "\nTarget is ", ( moves = $level == hard ?? 12 !! 3 ).Str, " moves.";
for ^moves {
my \s = (^4).roll;
@n[ ( [ s, s+4 ... s+12 ] , [ s*4 .. s*4+3 ] ).roll ] .= rotate ;
redo if hasWon
}
}

sub drawGrid {
say "\n U1 U2 U3 U4";
say " ╔════╦════╦════╦════╗";
printf "L1 ║ %2d ║ %2d ║ %2d ║ %2d ║ R1\n", @n[0..3];
say " ╠════╬════╬════╬════╣";
printf "L2 ║ %2d ║ %2d ║ %2d ║ %2d ║ R2\n", @n[4..7];
say " ╠════╬════╬════╬════╣";
printf "L3 ║ %2d ║ %2d ║ %2d ║ %2d ║ R3\n", @n[8..11];
say " ╠════╬════╬════╬════╣";
printf "L4 ║ %2d ║ %2d ║ %2d ║ %2d ║ R4\n", @n[12..15];
say " ╚════╩════╩════╩════╝";
say " D1 D2 D3 D4\n"
}

sub init {
loop {
print "Enter difficulty level easy or hard E/H : ";
given $*IN.get.uc {
when 'E'|'H' { level = $_ eq 'H' ?? hard !! easy ; last }
default { say "Invalid response, try again." }
}
}
setDiff(level);
moves = 0;
}

init;

loop {
drawGrid;
if hasWon() {
say "Congratulations, you have won the game in {moves} moves.\n" and exit
}
say "When entering moves, you can also enter Q to quit or S to start again.";
say "\nMoves so far = {moves}\n";
print "Enter move : " ;
given $*IN.get.uc {
my \c = .substr(*-1).ord - 49 ; moves++ ;
when 'D1'|'D2'|'D3'|'D4' { @n[ (12,8,4,0) >>+>> c ] .= rotate }
when 'L1'|'L2'|'L3'|'L4' { @n[ (0,1,2,3) >>+>> 4*c ] .= rotate }
when 'U1'|'U2'|'U3'|'U4' { @n[ (0,4,8,12) >>+>> c ] .= rotate }
when 'R1'|'R2'|'R3'|'R4' { @n[ (3,2,1,0) >>+>> 4*c ] .= rotate }
when 'Q' { exit }
when 'S' { init }
default { say "\nInvalid move, try again." and moves-- }
}
}</syntaxhighlight>


=={{header|REXX}}==
=={{header|REXX}}==
Line 20: Line 1,453:
and the answer can be in any case (lower or uppercase).
and the answer can be in any case (lower or uppercase).
<br>Not all errors are checked so as to keep the program simpler.
<br>Not all errors are checked so as to keep the program simpler.
<lang rexx>/*REXX pgm implements the 16 game; displays game grid, prompts for a move, game won? */
<syntaxhighlight lang="rexx">/*REXX pgm implements the 16 game; displays game grid, prompts for a move, game won? */
sep= copies('',8); pad=left('',1+length(sep) ) /*pad=9 blanks. SEP is used for msgs.*/
sep= copies("",8); pad=left('',1+length(sep) ) /*pad=9 blanks. SEP is used for msgs.*/
parse arg N hard seed . /*obtain optional arguments from the CL*/
parse arg N hard seed . /*obtain optional arguments from the CL*/
er= '***error***' /*literal used to indicate an error msg*/
er= '***error***' /*literal used to indicate an error msg*/
Line 29: Line 1,462:
if N<2 | N>9 then do; say sep er "grid size is out of range: " N; exit 1; end
if N<2 | N>9 then do; say sep er "grid size is out of range: " N; exit 1; end
if isInt(seed) then call random , , seed /*use repeatability seed for RANDOM BIF*/
if isInt(seed) then call random , , seed /*use repeatability seed for RANDOM BIF*/
say sep 'Playing a ' N*N " game with a difficulity level of: " hard
say sep 'Playing a ' N*N " game with a difficulty level of: " hard
#=0
#=0
do r=1 for N /* [◄] build a solution for testing. */
do r=1 for N /* [◄] build a solution for testing. */
Line 35: Line 1,468:
end /*c*/
end /*c*/
end /*r*/
end /*r*/
/* [↓] HARD is the puzzle difficulity*/
/* [↓] HARD is the puzzle difficulty.*/
do hard; row= random(1) /*scramble the grid HARD # of times.*/
do hard; row= random(1) /*scramble the grid HARD # of times.*/
if row then call move random(1,N)substr('LR', random(1, 2), 1) /* ◄── move row. */
if row then call move random(1,N)substr('LR', random(1, 2), 1) /* ◄── move row. */
else call move substr('abcdefghi',random(1,N), 1)substr('+-',random(1,2),1)
else call move substr('abcdefghi',random(1,N), 1)substr("+-",random(1,2),1)
end /*hard*/ /* [↓] move col.*/
end /*hard*/ /* [↓] move col.*/
/*play 16─game until solved or quit.*/
/*play 16─game until solved or quit.*/
Line 93: Line 1,526:
bot= '╚'copies( copies("═", 2)'╩', N); bot= left( bot, length(bot) - 1)"╝"
bot= '╚'copies( copies("═", 2)'╩', N); bot= left( bot, length(bot) - 1)"╝"
ind= left('', 3 + length(N) ) /*compute indentation.*/
ind= left('', 3 + length(N) ) /*compute indentation.*/
col= ind ind ind' ' subword('a- b- c- d- e- f- g- h- i-', 1, n)
col= ind ind ind' ' subword("a- b- c- d- e- f- g- h- i-", 1, n)
HI= substr('abcdefghi', N, 1); upper HI
HI= substr('abcdefghi', N, 1); upper HI
say col ind ind ind '- means shift a column down'; say pad ind top
say col ind ind ind '- means shift a column down'; say pad ind top
Line 99: Line 1,532:
do c=1 for N; z= z || right(@.r.c, 2)'║' /*build row by row. */
do c=1 for N; z= z || right(@.r.c, 2)'║' /*build row by row. */
end /*c*/
end /*c*/
z= z ' ' r"L" /*add rightside info.*/
z= z ' ' r"L" /*add right-side info*/
if r==1 then z= z pad'L means shift a row left' /* " 1st help info.*/
if r==1 then z= z pad'L means shift a row left' /* " 1st help info.*/
if r==2 then z= z pad'R means shift a row right' /* " 2nd " " */
if r==2 then z= z pad'R means shift a row right' /* " 2nd " " */
Line 105: Line 1,538:
end /*r*/
end /*r*/
say pad ind bot; say;
say pad ind bot; say;
say translate(col, '+', "-") ind ind ind '+ means shift a column up'; say
say translate(col, '+', "-") ind ind ind "+ means shift a column up"; say
return</lang>
return</syntaxhighlight>
{{out|output|text=&nbsp; when using the default inputs:}}
{{out|output|text=&nbsp; when using the default inputs:}}
<pre>
<pre>
──────── Playing a 16 game with a difficulity level of: 2
──────── Playing a 16 game with a difficulty level of: 2


a- b- c- d- - means shift a column down
a- b- c- d- - means shift a column down
Line 161: Line 1,594:


=={{header|Ring}}==
=={{header|Ring}}==
<lang ring>
<syntaxhighlight lang="ring">
# Project : Sixteen Puzzle Game
# Project : Sixteen Puzzle Game


Line 689: Line 2,122:
psave()
psave()
return
return
</syntaxhighlight>
</lang>
Output image:
Output image:


[https://www.dropbox.com/s/dy1zmw6xpo2o55v/CalmoSoftSixteenPuzzleGame.jpg?dl=0 16 Puzzle Game]
[https://www.dropbox.com/s/dy1zmw6xpo2o55v/CalmoSoftSixteenPuzzleGame.jpg?dl=0 16 Puzzle Game]

=={{header|Wren}}==
{{trans|Go}}
{{libheader|Wren-iterate}}
{{libheader|Wren-fmt}}
{{libheader|Wren-ioutil}}
{{libheader|Wren-str}}
<syntaxhighlight lang="wren">import "random" for Random
import "./iterate" for Stepped
import "./fmt" for Fmt
import "./ioutil" for Input
import "./str" for Str

var rand = Random.new()

var easy = 1
var hard = 4

var n = List.filled(16, 0)

var initGrid = Fn.new {
for (i in 0..15) n[i] = i + 1
}

var rotate = Fn.new { |ix|
var last = n[ix[3]]
for (i in 3..1) n[ix[i]] = n[ix[i-1]]
n[ix[0]] = last
}

var hasWon = Fn.new {
for (i in 0...15) {
if (n[i] != i+1) return false
}
return true
}

var setDiff = Fn.new { |level|
var moves = (level == easy) ? 3 : 12
var rc = []
var i = 0
while (i < moves) {
rc.clear()
var r = rand.int(2)
var s = rand.int(4)
if (r == 0) { // rotate random row
for (j in s*4...(s+1)*4) rc.add(j)
} else { // rotate random column
for (j in Stepped.new(s...s+16, 4)) rc.add(j)
}
var rca = rc.toList
rotate.call(rca)
if (hasWon.call()) { // do it again
i = -1
}
i = i + 1
}
System.print("Target is %(moves) moves.")
}

var drawGrid = Fn.new {
System.print()
System.print(" D1 D2 D3 D4")
System.print(" ╔════╦════╦════╦════╗")
Fmt.print ("R1 ║ $2d ║ $2d ║ $2d ║ $2d ║ L1", n[0], n[1], n[2], n[3])
System.print(" ╠════╬════╬════╬════╣")
Fmt.print ("R2 ║ $2d ║ $2d ║ $2d ║ $2d ║ L2", n[4], n[5], n[6], n[7])
System.print(" ╠════╬════╬════╬════╣")
Fmt.print ("R3 ║ $2d ║ $2d ║ $2d ║ $2d ║ L3", n[8], n[9], n[10], n[11])
System.print(" ╠════╬════╬════╬════╣")
Fmt.print ("R4 ║ $2d ║ $2d ║ $2d ║ $2d ║ L4", n[12], n[13], n[14], n[15])
System.print(" ╚════╩════╩════╩════╝")
System.print(" U1 U2 U3 U4\n")
}

initGrid.call()
var level = easy
var diff = Input.option("Enter difficulty level easy or hard E/H : ", "eEhH")
if (diff == "h" || diff == "H") level = hard
setDiff.call(level)
var ix = List.filled(4, 0)
System.print("When entering moves, you can also enter Q to quit or S to start again.")
var moves = 0
while (true) {
drawGrid.call()
if (hasWon.call()) {
System.print("Congratulations, you have won the game in %(moves) moves!!")
return
}
while (true) {
System.print("Moves so far = %(moves)\n")
var move = Str.upper(Input.text("Enter move : ", 1).trim())
if (move == "D1" || move == "D2" || move == "D3" || move == "D4") {
var c = move[1].bytes[0] - 49
ix[0] = 0 + c
ix[1] = 4 + c
ix[2] = 8 + c
ix[3] = 12 + c
rotate.call(ix)
moves = moves + 1
break
} else if (move == "L1" || move == "L2" || move == "L3" || move == "L4") {
var c = move[1].bytes[0] - 49
ix[0] = 3 + 4*c
ix[1] = 2 + 4*c
ix[2] = 1 + 4*c
ix[3] = 0 + 4*c
rotate.call(ix)
moves = moves + 1
break
} else if (move == "U1" || move == "U2" || move == "U3" || move == "U4") {
var c = move[1].bytes[0] - 49
ix[0] = 12 + c
ix[1] = 8 + c
ix[2] = 4 + c
ix[3] = 0 + c
rotate.call(ix)
moves = moves + 1
break
} else if (move == "R1" || move == "R2" || move == "R3" || move == "R4") {
var c = move[1].bytes[0] - 49
ix[0] = 0 + 4*c
ix[1] = 1 + 4*c
ix[2] = 2 + 4*c
ix[3] = 3 + 4*c
rotate.call(ix)
moves = moves + 1
break
} else if (move == "Q") {
return
} else if (move == "S") {
initGrid.call()
setDiff.call(level)
moves = 0
break
} else {
System.print("Invalid move, try again.")
}
}
}</syntaxhighlight>

{{out}}
Sample (very easy!) game:
<pre>
Enter difficulty level easy or hard E/H : e
Target is 3 moves.
When entering moves, you can also enter Q to quit or S to start again.

D1 D2 D3 D4
╔════╦════╦════╦════╗
R1 ║ 3 ║ 4 ║ 1 ║ 2 ║ L1
╠════╬════╬════╬════╣
R2 ║ 5 ║ 6 ║ 7 ║ 8 ║ L2
╠════╬════╬════╬════╣
R3 ║ 9 ║ 10 ║ 11 ║ 12 ║ L3
╠════╬════╬════╬════╣
R4 ║ 16 ║ 13 ║ 14 ║ 15 ║ L4
╚════╩════╩════╩════╝
U1 U2 U3 U4

Moves so far = 0

Enter move : l1

D1 D2 D3 D4
╔════╦════╦════╦════╗
R1 ║ 4 ║ 1 ║ 2 ║ 3 ║ L1
╠════╬════╬════╬════╣
R2 ║ 5 ║ 6 ║ 7 ║ 8 ║ L2
╠════╬════╬════╬════╣
R3 ║ 9 ║ 10 ║ 11 ║ 12 ║ L3
╠════╬════╬════╬════╣
R4 ║ 16 ║ 13 ║ 14 ║ 15 ║ L4
╚════╩════╩════╩════╝
U1 U2 U3 U4

Moves so far = 1

Enter move : l1

D1 D2 D3 D4
╔════╦════╦════╦════╗
R1 ║ 1 ║ 2 ║ 3 ║ 4 ║ L1
╠════╬════╬════╬════╣
R2 ║ 5 ║ 6 ║ 7 ║ 8 ║ L2
╠════╬════╬════╬════╣
R3 ║ 9 ║ 10 ║ 11 ║ 12 ║ L3
╠════╬════╬════╬════╣
R4 ║ 16 ║ 13 ║ 14 ║ 15 ║ L4
╚════╩════╩════╩════╝
U1 U2 U3 U4

Moves so far = 2

Enter move : l4

D1 D2 D3 D4
╔════╦════╦════╦════╗
R1 ║ 1 ║ 2 ║ 3 ║ 4 ║ L1
╠════╬════╬════╬════╣
R2 ║ 5 ║ 6 ║ 7 ║ 8 ║ L2
╠════╬════╬════╬════╣
R3 ║ 9 ║ 10 ║ 11 ║ 12 ║ L3
╠════╬════╬════╬════╣
R4 ║ 13 ║ 14 ║ 15 ║ 16 ║ L4
╚════╩════╩════╩════╝
U1 U2 U3 U4

Congratulations, you have won the game in 3 moves!!
</pre>

Latest revision as of 11:27, 5 November 2023

16 numbered pieces of the puzzle are placed out of order on a 4 X 4 grid. The correct order to win is to order the pieces as 1 through 16, read left to right, top to bottom:

16 puzzle game is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
  1  2  3  4
  5  6  7  8
  9 10 11 12
 13 14 15 16

How to Play: The aim is to get the pieces back in order by clicking on the yellow arrows (choosing a location to rotate a row or column) to slide the pieces left or right, up or down.

  1 14  3  4          1  2  3  4
  5  2  7  8   -->    5  6  7  8
  9  6 11 12          9 10 11 12
 13 10 15 16         13 14 15 16
     ^

The Easy puzzle target is 3 moves, for the Hard puzzle it is 12 moves (or less!). Can it be that simple?

Task

Create 16 Puzzle Game.


See details: [1]


Video: 16 Puzzle Game


Related task



AutoHotkey

With Solver, See 16_puzzle_game/autohotkey

FreeBASIC

Translation of: Wren
Const easy = 1, hard = 4
Dim Shared As Byte n(1 To 16)

Sub initGrid ()
    For i As Byte = 0 To 15
        n(i) = i + 1
    Next
End Sub

Sub rotate (ix() As Byte)
    Dim As Byte last = n(ix(3))
    For i As Byte = 3 To 1 Step -1
        n(ix(i)) = n(ix(i-1))
    Next
    n(ix(0)) = last
End Sub

Function hasWon () As Boolean
    For i As Byte = 0 To 15
        If n(i) <> i+1 Then Return False
    Next
    Return True
End Function

Sub setDiff (level As Byte)
    Dim As Byte moves = Iif(level = easy, 3, 12)
    Dim As Byte rc(), j, i
    For i = 0 To moves
        Redim As Byte rc(20)
        Dim As Byte r = Int(Rnd * 2)
        Dim As Byte s = Int(Rnd * 4)
        If r = 0 Then  ' rotate random row
            For j = s*4 To (s+1)*4
                rc(j) = j
            Next
        Else  ' rotate random column
            For j = s To s+16 Step 4
                rc(j) = j
            Next
        End If
        rotate(rc())
        If hasWon() Then ' do it again
            i = -1
        End If
        i += 1
    Next
    Print Using !"\nTarget is ## moves."; moves
End Sub

Sub drawGrid ()
    Print !"\n     D1   D2   D3   D4"
    Print "   +-------------------+"
    Print Using "R1 | ## | ## | ## | ## | L1"; n(0); n(1); n(2); n(3)
    Print "   |----+----+----+----|"
    Print Using "R2 | ## | ## | ## | ## | L2"; n(4); n(5); n(6); n(7)
    Print "   |----+----+----+----|"
    Print Using "R3 | ## | ## | ## | ## | L3"; n(8); n(9); n(10); n(11)
    Print "   |----+----+----+----|"
    Print Using "R4 | ## | ## | ## | ## | L4"; n(12); n(13); n(14); n(15)
    Print "   +-------------------+"
    Print !"      U1   U2   U3   U4\n"
End Sub

'--- Programa Principal ---
Randomize Timer
Dim As Byte level = easy
Dim As String diff
Print "Enter difficulty level easy or hard E/H: ";
Do
    Input ; "", diff
Loop Until Instr("eEhH", diff)
If Ucase(diff) = "H" Then level = hard

Cls
Print "Sixteen Puzzle"
initGrid()
setDiff(level)

Dim As Byte ix(0 To 3)
Print "When entering moves, you can also enter Q to quit or S to start again."
Dim As Byte c, moves = 0
Dim As String*2 move 
Do
    drawGrid()
    If hasWon() Then
        Print "Congratulations, you have won the game in"; moves; " moves!!"
        While Inkey = "": Wend
        Exit Do
    End If
    Do
        Print "Moves so far = "; moves
        Input "Enter move : ", move
        Select Case Trim(Ucase(move))
        Case "D1", "D2", "D3", "D4"
            c = Cint(Right(move,1)) - 49
            ix(0) =  0 + c
            ix(1) =  4 + c
            ix(2) =  8 + c
            ix(3) = 12 + c
            rotate(ix())
            moves += 1
            Exit Do
        Case "L1", "L2", "L3", "L4"
            c = Cint(Right(move,1)) - 49
            ix(0) = 3 + 4*c
            ix(1) = 2 + 4*c
            ix(2) = 1 + 4*c
            ix(3) = 0 + 4*c
            rotate(ix())
            moves += 1
            Exit Do
        Case "U1", "U2", "U3", "U4"
            c = Cint(Right(move,1)) - 49
            ix(0) = 12 + c
            ix(1) =  8 + c
            ix(2) =  4 + c
            ix(3) =  0 + c
            rotate(ix())
            moves += 1
            Exit Do
        Case "R1", "R2", "R3", "R4"
            c = Cint(Right(move,1)) - 49
            ix(0) = 0 + 4*c
            ix(1) = 1 + 4*c
            ix(2) = 2 + 4*c
            ix(3) = 3 + 4*c
            rotate(ix())
            moves += 1
            Exit Do
        Case "Q"
            Exit Do, Do
        Case "S"
            Cls
            initGrid()
            setDiff(level)
            moves = 0
            Exit Do
        Case Else
            Print "Invalid move, try again."
        End Select
    Loop
Loop
'--------------------------
Sleep

FutureBasic

begin enum
  _down = 1
  _right
  _up
  _left
  _new  = 100
  _restrt
  _help
  _end
end enum
str63 board, startPos, winBoard

void local fn init
  window 1,,(0,0,340,340)
  int x
  for x = 1 to 4
    button 10+x,,,@"⬇️",(x*50+20,270,50,50),,NSBezelStyleTexturedSquare
    ControlSetFontWithName( 10+x, @"Menlo", 32 )
    button 30+x,,,@"⬆️",(x*50+20, 20,50,50),,NSBezelStyleTexturedSquare
    ControlSetFontWithName( 30+x, @"Menlo", 32 )
    button 25-x,,,@"➡️",( 20,x*50+20,50,50),,NSBezelStyleTexturedSquare
    ControlSetFontWithName( 25-x, @"Menlo", 32 )
    button 45-x,,,@"⬅️",(270,x*50+20,50,50),,NSBezelStyleTexturedSquare
    ControlSetFontWithName( 45-x, @"Menlo", 32 )
  next
  button _new   ,,,@"New",   ( 20,270,50,50),,NSBezelStyleTexturedSquare
  button _end   ,,,@"Quit",  ( 20, 20,50,50),,NSBezelStyleTexturedSquare
  button _restrt,,,@"Redo",  (270,270,50,50),,NSBezelStyleTexturedSquare
  button _help  ,,,@"Help",  (270, 20,50,50),,NSBezelStyleTexturedSquare
  for x = 1 to 16
    winBoard += chr$(x)
  next
  board = winBoard
end fn

void local fn drawBoard
  int c = 1, x, y, z
  cls
  for y = 70 to 220 step 50
    for x = 70 to 220 step 50
      rect fill (x,y,48,48), fn coloryellow
      if board[c] > 9 then z = x-3 else z = x+6
      print %(z,y+6) str(board[c]);
      c++
    next
  next
end fn

void local fn move( tag as int )
  int r, d, rc = (tag mod 10)
  select tag / 10
    case _up    : d = +4        
    case _right : d = -1 : rc *= 4     
    case _down  : d = -4 : rc += 12    
    case else   : d = +1 : rc  = rc * 4 - 3 
  end select
  for r = rc to rc + 2 * d step d
    swap board[r], board[r+d]
  next
  if board == winBoard then window 1, @"!!! YOU WON !!!" : text,,fn colorRed
  fn drawBoard
end fn

void local fn newGame
  window 1, @"16 PUZZLE GAME"
  int r
  for r = 1 to 16
    swap board[r], board[rnd(16)]
  next
  startPos = board
  text @"Arial bold", 32, fn colorblue
  fn drawBoard
end fn

void local fn ask( tag as long )
  CFStringRef s1, s2 : int btn
  select tag
    case _help
      s1  = @"Use the arrow buttons to move numbers in rows and columns.\n¬
      Win by arranging the numbers in order, left to right, top to bottom:"
      s2  = @" 1   2   3   4 \n 5   6   7   8 \n 9  10  11  12\n 13 14 15 16"
      btn = alert 1, NSAlertStyleInformational, s1, s2, @"Okay"
    case _new : if board == winBoard then fn newGame : exit fn
      s1  = @"Leave this puzzle\nand start a new one?"
      btn = alert 1, NSAlertStyleInformational, s1,,@"New puzzle;Cancel"
      if btn == NSAlertFirstButtonReturn then fn newGame
    case _restrt
      s1  = @"Restart this puzzle\nfrom the beginning?"
      btn = alert 1, NSAlertStyleInformational,s1,,@"Restart;Cancel"
      if btn == NSAlertFirstButtonReturn then board = startPos : fn drawBoard
    case _end
      btn = alert 1, NSAlertStyleInformational,@"Quit 16 GAME?",,@"Quit;Cancel"
      if btn == NSAlertFirstButtonReturn then end
  end select
end fn

void local fn doDialog(ev as long, tag as long)
  select ev
    case _btnClick : if tag < _new then fn move( tag ) else fn ask( tag )
    case _windowWillClose : end
  end select
end fn

on dialog fn doDialog
fn init
fn newGame

handleevents
Output:

File:16 Puzzle Game.png

Go

package main

import (
    "bufio"
    "fmt"
    "log"
    "math/rand"
    "os"
    "strings"
    "time"
)

const (
    easy = 1
    hard = 4
)

var n [16]int

func initGrid() {
    for i := 0; i < 16; i++ {
        n[i] = i + 1
    }
}

func setDiff(level int) {
    moves := 3
    if level == hard {
        moves = 12
    }
    rc := make([]int, 0, 4)
    for i := 0; i < moves; i++ {
        rc = rc[:0]
        r := rand.Intn(2)
        s := rand.Intn(4)
        if r == 0 { // rotate random row
            for j := s * 4; j < (s+1)*4; j++ {
                rc = append(rc, j)
            }
        } else { // rotate random column
            for j := s; j < s+16; j += 4 {
                rc = append(rc, j)
            }
        }
        var rca [4]int
        copy(rca[:], rc)
        rotate(rca)
        if hasWon() { // do it again
            i = -1
        }
    }
    fmt.Println("Target is", moves, "moves.")
}

func drawGrid() {
    fmt.Println()
    fmt.Println("     D1   D2   D3   D4")
    fmt.Println("   ╔════╦════╦════╦════╗")
    fmt.Printf("R1 ║ %2d ║ %2d ║ %2d ║ %2d ║ L1\n", n[0], n[1], n[2], n[3])
    fmt.Println("   ╠════╬════╬════╬════╣")
    fmt.Printf("R2 ║ %2d ║ %2d ║ %2d ║ %2d ║ L2\n", n[4], n[5], n[6], n[7])
    fmt.Println("   ╠════╬════╬════╬════╣")
    fmt.Printf("R3 ║ %2d ║ %2d ║ %2d ║ %2d ║ L3\n", n[8], n[9], n[10], n[11])
    fmt.Println("   ╠════╬════╬════╬════╣")
    fmt.Printf("R4 ║ %2d ║ %2d ║ %2d ║ %2d ║ L4\n", n[12], n[13], n[14], n[15])
    fmt.Println("   ╚════╩════╩════╩════╝")
    fmt.Println("     U1   U2   U3   U4\n")
}

func rotate(ix [4]int) {
    last := n[ix[3]]
    for i := 3; i >= 1; i-- {
        n[ix[i]] = n[ix[i-1]]
    }
    n[ix[0]] = last
}

func hasWon() bool {
    for i := 0; i < 16; i++ {
        if n[i] != i+1 {
            return false
        }
    }
    return true
}

func check(err error) {
    if err != nil {
        log.Fatal(err)
    }
}

func main() {
    initGrid()
    rand.Seed(time.Now().UnixNano())
    level := easy
    scanner := bufio.NewScanner(os.Stdin)
    for {
        fmt.Print("Enter difficulty level easy or hard E/H : ")
        scanner.Scan()
        diff := strings.ToUpper(strings.TrimSpace(scanner.Text()))
        if diff != "E" && diff != "H" {
            fmt.Println("Invalid response, try again.")
        } else {
            if diff == "H" {
                level = hard
            }
            break
        }
    }
    check(scanner.Err())
    setDiff(level)
    var ix [4]int
    fmt.Println("When entering moves, you can also enter Q to quit or S to start again.")
    moves := 0
outer:
    for {
        drawGrid()
        if hasWon() {
            fmt.Println("Congratulations, you have won the game in", moves, "moves!!")
            return
        }
        for {
            fmt.Println("Moves so far =", moves, "\n")
            fmt.Print("Enter move : ")
            scanner.Scan()
            move := strings.ToUpper(strings.TrimSpace(scanner.Text()))
            check(scanner.Err())
            switch move {
            case "D1", "D2", "D3", "D4":
                c := int(move[1] - 49)
                ix[0] = 0 + c
                ix[1] = 4 + c
                ix[2] = 8 + c
                ix[3] = 12 + c
                rotate(ix)
                moves++
                continue outer
            case "L1", "L2", "L3", "L4":
                c := int(move[1] - 49)
                ix[0] = 3 + 4*c
                ix[1] = 2 + 4*c
                ix[2] = 1 + 4*c
                ix[3] = 0 + 4*c
                rotate(ix)
                moves++
                continue outer
            case "U1", "U2", "U3", "U4":
                c := int(move[1] - 49)
                ix[0] = 12 + c
                ix[1] = 8 + c
                ix[2] = 4 + c
                ix[3] = 0 + c
                rotate(ix)
                moves++
                continue outer
            case "R1", "R2", "R3", "R4":
                c := int(move[1] - 49)
                ix[0] = 0 + 4*c
                ix[1] = 1 + 4*c
                ix[2] = 2 + 4*c
                ix[3] = 3 + 4*c
                rotate(ix)
                moves++
                continue outer
            case "Q":
                return
            case "S":
                initGrid()
                setDiff(level)
                moves = 0
                continue outer
            default:
                fmt.Println("Invalid move, try again.")
            }
        }
    }
}
Output:

Sample game:

Enter difficulty level easy or hard E/H : e
Target is 3 moves.
When entering moves, you can also enter Q to quit or S to start again.

     D1   D2   D3   D4
   ╔════╦════╦════╦════╗
R1 ║  1 ║  2 ║  3 ║  4 ║ L1
   ╠════╬════╬════╬════╣
R2 ║  7 ║  8 ║  5 ║  6 ║ L2
   ╠════╬════╬════╬════╣
R3 ║  9 ║ 10 ║ 11 ║ 12 ║ L3
   ╠════╬════╬════╬════╣
R4 ║ 16 ║ 13 ║ 14 ║ 15 ║ L4
   ╚════╩════╩════╩════╝
     U1   U2   U3   U4

Moves so far = 0 

Enter move : l4

     D1   D2   D3   D4
   ╔════╦════╦════╦════╗
R1 ║  1 ║  2 ║  3 ║  4 ║ L1
   ╠════╬════╬════╬════╣
R2 ║  7 ║  8 ║  5 ║  6 ║ L2
   ╠════╬════╬════╬════╣
R3 ║  9 ║ 10 ║ 11 ║ 12 ║ L3
   ╠════╬════╬════╬════╣
R4 ║ 13 ║ 14 ║ 15 ║ 16 ║ L4
   ╚════╩════╩════╩════╝
     U1   U2   U3   U4

Moves so far = 1 

Enter move : l2

     D1   D2   D3   D4
   ╔════╦════╦════╦════╗
R1 ║  1 ║  2 ║  3 ║  4 ║ L1
   ╠════╬════╬════╬════╣
R2 ║  8 ║  5 ║  6 ║  7 ║ L2
   ╠════╬════╬════╬════╣
R3 ║  9 ║ 10 ║ 11 ║ 12 ║ L3
   ╠════╬════╬════╬════╣
R4 ║ 13 ║ 14 ║ 15 ║ 16 ║ L4
   ╚════╩════╩════╩════╝
     U1   U2   U3   U4

Moves so far = 2 

Enter move : l2

     D1   D2   D3   D4
   ╔════╦════╦════╦════╗
R1 ║  1 ║  2 ║  3 ║  4 ║ L1
   ╠════╬════╬════╬════╣
R2 ║  5 ║  6 ║  7 ║  8 ║ L2
   ╠════╬════╬════╬════╣
R3 ║  9 ║ 10 ║ 11 ║ 12 ║ L3
   ╠════╬════╬════╬════╣
R4 ║ 13 ║ 14 ║ 15 ║ 16 ║ L4
   ╚════╩════╩════╩════╝
     U1   U2   U3   U4

Congratulations, you have won the game in 3 moves!!

J

Assumes a recent release of jqt:

require'ide/qt/gl2'
coinsert'jgl2'

NB. event handlers
game_reset_button=: {{ draw COUNT=: #SETUP=: EMPTY [BOARD=: WIN }}
game_restart_button=: {{ draw COUNT=: 0 [rotate"1 SETUP [BOARD=: WIN }}
game_easy_button=: {{ setup 3 }}
game_hard_button=: {{ setup 15 }}
game_board_mbldown=: {{ 
  loc=. (20+40*i.5)I.2{._".sysdata
  if. 1=#ndx=. loc -. 0 5 do.
    side=. 2#.<:>.loc%4 NB. _2: left, _1 top, 1 bottom, 2 right
    draw rotate side, ndx
  end.
}}

NB. game logic
BOARD=: WIN=: 1+i.4 4
message=: {{
  color=. (COUNT>#SETUP){::;:'black red'
  A=. '<span style="color: ',color,'">' [Z=. '</span>'
  if. BOARD-:WIN do. A,'You win',Z return. end.
  A,(":COUNT),Z,' of ',":#SETUP
}}
setup=: {{ game_restart_button SETUP=: (_2 _1 1 2{~?y#4),.1+?y#4 }}
rotate=: {{
  COUNT=: COUNT+1
  'side ndx'=. y-0 1
  flip=. |: if. 2=|side do. flip=. ] end.
  BOARD=: flip ((*side)|.ndx{flip BOARD) ndx} flip BOARD
}}

NB. rendering
wd {{)n
  pc game closeok;
  cc board isidraw;
  set board wh 200 200;
  cc msg static center;
  bin h;
    cc easy button;
    set easy tooltip start game which can be completed in 3 moves;
    cc hard button;
    set hard tooltip start game which can be completed in 15 moves;
  bin z; bin h;
    cc restart button;
    cc reset button;
    set reset tooltip set board to initial position, ending any current game;
  pshow;
}}

draw=: {{
  glclear''
  glbrush glrgb 3#224     NB. silver
  glrect 0 0 200 200
  glbrush glrgb 0 0 255   NB. blue
  glrect T=:20 20 40 40+"1]40*4 4 1 1#:i.4 4
  glbrush glrgb 255 255 0 NB. yellow
  glpolygon (,200-])(,;"1@(_2<@|.\"1]))0 30 0 50 10 40+"1(i.4)*/6$0 40
  gltextcolor glrgb 3#255 NB. white
  glfont '"lucidia console" 16'
  BOARD {{ gltext ":x [ gltextxy y+5 0*_1^1<#":x }}"_2(30+40*4 4#:|:i.4 4)
  if. EMPTY-:SETUP do.
    wd {{)n
     set msg text <b>easy</b> or <b>hard</b> to start;
     set restart enable 0;
     set restart caption;
}} else. wd {{)n
    set msg text MESSAGE;
    set restart enable 1;
    set restart caption restart;
}} rplc 'MESSAGE';message''
  end.
  glpaint''
}}

NB. start:
game_reset_button''

JavaScript

Try it here.

You'll also need a html file:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <meta http-equiv="X-UA-Compatible" content="ie=edge">
 <link href="https://fonts.googleapis.com/css?family=Ubuntu+Mono&display=swap" rel="stylesheet">
 <link rel="stylesheet" type="text/css" media="screen" href="./css/main.css">
 <title>16 Puzzle</title>
</head>
<body>
 <div id="done">WELL DONE!</div>
 <div id="board"></div>
 <div id="moves"></div>
 <button id="shuffle">SHUFFLE</button>
 <script src="./src/index.js" type="module"></script>
</body>
</html>

And css file:

* {
 margin: 0;
 border: 0;
 text-align: center;
 font-family: 'Ubuntu Mono', monospace;
 user-select: none;
}
button {
 border-radius: 5px;
 width: 300px;
 height: 80px;
 font-size: 40px;
 margin-top: 60px;
}
#board {
 width: 410px;
 height: 410px;
 margin: 120px auto 30px auto;
}
#done {
 font-size: 140px;
 padding: 20px;
 color: #fff;
 background-color: rgba(0, 23, 56, .5);
 border: 1px solid rgb(0, 90, 220);
 width: 700px;
 position: absolute;
 top: 250px;
 left: calc(50% - 380px);
}
#moves {
 font-size: 40px;
 line-height: 80px;
 height: 80px;
 width: 300px;
 margin: auto;
 border: 1px solid #000;
 border-radius: 5px;
}
.btn,
.numbers,
.hide {
 float: left;
 width: 64px;
 height: 64px;
 line-height: 65px;
 font-size: 40px;
 border: 1px solid black;
 color: black;
 background-color: white;
 cursor: none;
 margin: 1px;
 transition: all .3s;
}
.btn:hover {
 background-color: rgba(71, 231, 71, 0.5);
 cursor: pointer;
}
.hide {
 border: 1px solid white;
 cursor: none;
}
class Puzzle {
 constructor() {
  this.moves;
  this.started;

  this.board = document.getElementById("board");
  document.getElementById("shuffle").addEventListener("click", () => {
   this.shuffle();
  });
  this.reset();
 }

 reset() {
  while (this.board.hasChildNodes()) {
   this.board.removeChild(this.board.firstChild);
  }

  this.moves = 0;
  this.started = false;
  document.getElementById("moves").innerText = this.moves;
  document.getElementById("done").style.visibility = "hidden";

  let t = 1;
  for (let y = 0; y < 6; y++) {
   for (let x = 0; x < 6; x++) {
    const d = document.createElement("div");
    d.id = `${x}_${y}`;
    if (y === 0 || x === 0 || y === 5 || x === 5) {
     if (((y === 0 || y === 5) && (x === 0 || x === 5))) {
      d.className = "hide";
     } else {
      d.className = "btn";
      if (y === 0) {
       d.innerText = "🡇";
       d.func = () => {
        this.rollDownRight(x, true);
       };
      } else if (y === 5) {
       d.innerText = "🡅";
       d.func = () => {
        this.rollUpLeft(x, true);
       };
      }
      if (x === 0) {
       d.innerText = "🡆";
       d.func = () => {
        this.rollDownRight(y, false);
       };
      } else if (x === 5) {
       d.innerText = "🡄";
       d.func = () => {
        this.rollUpLeft(y, false);
       };
      }
      d.addEventListener("click", (ev) => {
       ev.srcElement.func();
      })
     }
    } else {
     d.className = "numbers";
     d.innerText = `${t}`;
     t++;
    }
    this.board.appendChild(d);
   }
  }
  document.getElementById("shuffle").innerText = "SHUFFLE";
 }

 shuffle() {
  if (this.started) {
   this.reset();
  } else {
   this.started = true;
   const e = Math.floor(Math.random() * 30) + 30;
   for (let z = 0; z < e; z++) {
    switch (Math.floor(Math.random() * 4)) {
     case 0:
      this.rollDownRight(Math.floor(Math.random() * 4) + 1, false);
      break;
     case 1:
      this.rollUpLeft(Math.floor(Math.random() * 4) + 1, true);
      break;
     case 2:
      this.rollUpLeft(Math.floor(Math.random() * 4) + 1, false);
      break;
     case 3:
      this.rollDownRight(Math.floor(Math.random() * 4) + 1, true);
      break;
    }
   }
   this.moves = 0;
   document.getElementById("moves").innerText = this.moves;
   document.getElementById("shuffle").innerText = "RESTART";
  }
 }

 getElements(l, col) {
  const z = Array.from(document.querySelectorAll(".numbers"));
  for (let e = 15; e > -1; e--) {
   if (z[e].id[(col ? 0 : 2)] != l) {
    z.splice(e, 1)
   }
  }
  return z;
 }

 rollDownRight(x, col) {
  if (!this.started) return;
  const z = this.getElements(x, col),
   a = z[3].innerText;
  for (let r = 3; r > 0; r--) {
   z[r].innerText = z[r - 1].innerText;
  }
  z[0].innerText = a;
  this.updateMoves();
  this.checkSolved();
 }

 rollUpLeft(x, col) {
  if (!this.started) return;
  const z = this.getElements(x, col),
   a = z[0].innerText;
  for (let r = 0; r < 3; r++) {
   z[r].innerText = z[r + 1].innerText;
  }
  z[3].innerText = a;
  this.updateMoves();
  this.checkSolved();
 }

 updateMoves() {
  this.moves++;
  document.getElementById("moves").innerText = this.moves;
 }

 checkSolved() {
  function check() {
   const z = document.querySelectorAll(".numbers");
   let u = 1;
   for (let r of z) {
    if (r.innerText != u) return false;
    u++;
   }
   return true;
  }
  if (this.started && check()) {
   document.getElementById("done").style.visibility = "visible";
  }
 }
}

new Puzzle();

Julia

using Gtk, Random

function puzzle16app(bsize)
    aclock, clock = "\u27f2", "\u27f3"
    win = GtkWindow("16 Game", 300, 300) |> (GtkFrame() |> (box = GtkBox(:v)))
    toolbar = GtkToolbar()
    newgame = GtkToolButton("New Game")
    set_gtk_property!(newgame, :label, "New Game")
    set_gtk_property!(newgame, :is_important, true)
    push!(toolbar, newgame)
    grid = GtkGrid()
    map(w -> push!(box, w),[toolbar, grid])
    buttons = Array{Gtk.GtkButtonLeaf,2}(undef, bsize + 2, bsize + 2)
    for i in 1:bsize+2, j in 1:bsize+2
        grid[i,j] = buttons[i,j] = GtkButton()
        set_gtk_property!(buttons[i,j], :expand, true)
    end

    inorder = string.(reshape(1:bsize*bsize, bsize, bsize))
    puzzle = shuffle(inorder)
    rotatecol(puzzle, col, n) = puzzle[:, col] .= circshift(puzzle[:, col], n)
    rotaterow(puzzle, row, n) = puzzle[row, :] .= circshift(puzzle[row, :], n)
    iswon() = puzzle == inorder
    won = false

    function findrowcol(button)
        for i in 1:bsize+2, j in 1:bsize+2
            if buttons[i, j] == button
                return i, j
            end
        end
        return 0, 0
    end

    function playerclicked(button)
        if !won
        i, j = findrowcol(button)
            if i == 1
                rotatecol(puzzle, j - 1, 1)
            elseif i == bsize + 2
                rotatecol(puzzle, j - 1, -1)
            elseif j == 1
                rotaterow(puzzle, i - 1, 1)
            elseif j == bsize + 2
                rotaterow(puzzle, i - 1, -1)
            end
        end
        update!()
    end

    function setup!()
        for i in 1:bsize+2, j in 1:bsize+2
            if 1 < j < bsize + 2
                if i == 1
                    signal_connect(playerclicked, buttons[i, j], "clicked")
                elseif i == bsize + 2
                    signal_connect(playerclicked, buttons[i, j], "clicked")
                end
            elseif 1 < i < bsize + 2
                if j == 1
                    signal_connect(playerclicked, buttons[i, j], "clicked")
                elseif j == bsize + 2
                    signal_connect(playerclicked, buttons[i, j], "clicked")
                end
            end
        end
    end

    function update!()
        for i in 1:bsize+2, j in 1:bsize+2
            if 1 < j < bsize + 2
                if i == 1
                    set_gtk_property!(buttons[i, j], :label, clock)
                elseif i == bsize + 2
                    set_gtk_property!(buttons[i, j], :label, aclock)
                else
                    set_gtk_property!(buttons[i, j], :label, puzzle[i-1, j-1])
                end
            elseif 1 < i < bsize + 2
                if j == 1
                    set_gtk_property!(buttons[i, j], :label, clock)
                elseif j == bsize + 2
                    set_gtk_property!(buttons[i, j], :label, aclock)
                end
            end
        end
        if iswon()
            won = true
            info_dialog("Game over.\nScore: $score", win)
        end
        showall(win)
    end

    function initialize!(w)
        puzzle = shuffle(inorder)
        won = false
        update!()
    end
    
    setup!()
    condition = Condition()
    endit(w) = notify(condition)
    signal_connect(initialize!, newgame, :clicked)
    signal_connect(endit, win, :destroy)
    initialize!(win)
    showall(win)
    wait(condition)
end

puzzle16app(4)

Nim

Translation of: Julia
Library: gintro

Not a direct translation as there are a lot of differences, but, at least, the graphical interface is similar and the logic is the same.

import random, sequtils, strutils
import gintro/[glib, gobject, gtk, gio]

const

  BoardSize = 4
  GridSize = BoardSize + 2
  Clock = "\u27f2"
  AClock = "\u27f3"

type

  Value = 1..16
  Puzzle = array[BoardSize, array[BoardSize, Value]]

  PuzzleApp = ref object of Application
    inOrder: Puzzle                                     # Target grid.
    puzzle: Puzzle                                      # Current grid.
    buttons: array[GridSize, array[GridSize, Button]]   # Button grid.
    won: bool                                           # True if game won.
    moves: Natural                                      # Count of moves.

#---------------------------------------------------------------------------------------------------

proc initPuzzle(puzzle: var Puzzle; data: openArray[Value]) =
  ## Initialize the puzzle with a list of values.
  var i = 0
  for row in puzzle.mitems:
    for cell in row.mitems:
      cell = data[i]
      inc i

#---------------------------------------------------------------------------------------------------

proc showMessage(app: PuzzleApp) =
  ## As "gintro" doesn't provide "MessageDialog" yet, we will use a simple dialog.
  let dialog = newDialog()
  dialog.setModal(true)
  let label = newLabel("You won in $# move(s)".format(app.moves))
  dialog.contentArea.add(label)
  discard dialog.addButton("Ok", ord(ResponseType.ok))
  dialog.showAll()
  discard dialog.run()
  dialog.destroy()

#---------------------------------------------------------------------------------------------------

proc onQuit(button: ToolButton; window: ApplicationWindow) =
  ## Procedure called when clicking quit button.
  window.destroy()

#---------------------------------------------------------------------------------------------------

proc rotateRow(puzzle: var Puzzle; row: Natural; left: bool) =
  ## Rotate a row left or right.
  if left:
    let first = puzzle[row][0]
    for i in 1..puzzle.high: puzzle[row][i-1] = puzzle[row][i]
    puzzle[row][^1] = first
  else:
    let last = puzzle[row][^1]
    for i in countdown(puzzle.high, 1): puzzle[row][i] = puzzle[row][i-1]
    puzzle[row][0] = last

#---------------------------------------------------------------------------------------------------

proc rotateCol(puzzle: var Puzzle; col: Natural; up: bool) =
  ## Rotate a column up or down.
  if up:
    let first = puzzle[0][col]
    for i in 1..puzzle.high: puzzle[i-1][col] = puzzle[i][col]
    puzzle[^1][col] = first
  else:
    let last = puzzle[^1][col]
    for i in countdown(puzzle[0].high, 1): puzzle[i][col] =puzzle[i-1][col]
    puzzle[0][col] = last

#---------------------------------------------------------------------------------------------------

proc findRowCol(app: PuzzleApp; button: Button): (int, int) =
  ## Find the row and column of a button.
  for i in [0, BoardSize+1]:
    for j in 1..Boardsize:
      if app.buttons[i][j] == button: return (i, j)
  for j in [0, BoardSize+1]:
    for i in 1..Boardsize:
      if app.buttons[i][j] == button: return (i, j)

#---------------------------------------------------------------------------------------------------

proc update(app: PuzzleApp) =
  ## Update the grid.
  for i in 0..BoardSize+1:
    for j in 0..BoardSize+1:
      if j in 1..BoardSize:
        if i == 0:
          app.buttons[i][j].setLabel(Clock)
        elif i == BoardSize + 1:
          app.buttons[i][j].setLabel(AClock)
        else:
          app.buttons[i][j].setLabel($app.puzzle[i-1][j-1])
      elif i in 1..BoardSize:
        if j == 0:
          app.buttons[i][j].setLabel(Clock)
        elif j == BoardSize + 1:
          app.buttons[i][j].setLabel(AClock)

  if app.puzzle == app.inOrder:
    app.won = true
    app.showMessage()

#---------------------------------------------------------------------------------------------------

proc onClick(button: Button; app: PuzzleApp) =
  ## Procedure called when the user cliked a grid button.
  if not app.won:
    inc app.moves
    let (i, j) = app.findRowCol(button)
    if i == 0:
      app.puzzle.rotateCol(j - 1, true)
    elif i == BoardSize + 1:
      app.puzzle.rotateCol(j - 1, false)
    elif j == 0:
      app.puzzle.rotateRow(i - 1, true)
    elif j == BoardSize + 1:
      app.puzzle.rotateRow(i - 1, false)
    app.update()

#---------------------------------------------------------------------------------------------------

proc newGame(button: ToolButton; app: PuzzleApp) =
  ## Prepare a new game.
  var values = toSeq(Value.low..Value.high)
  values.shuffle()
  app.puzzle.initPuzzle(values)
  app.won = false
  app.update()

#---------------------------------------------------------------------------------------------------

proc activate(app: PuzzleApp) =
  ## Activate the application.

  let window = app.newApplicationWindow()
  window.setTitle("16 puzzle game")
  window.setSizeRequest(300, 340)

  let box = newBox(Orientation.vertical, 0)
  window.add box

  let toolbar = newToolbar()
  let newGameButton = newToolButton(label = "New game")
  toolbar.insert(newGameButton, 0)
  let quitButton = newToolButton(label = "Quit")
  toolbar.insert(quitButton, 1)
  box.add toolbar

  let grid = newGrid()
  box.add grid

  for i in 0..BoardSize+1:
    for j in 0..BoardSize+1:
      let button = newButton()
      button.setHexpand(true)
      button.setVexpand(true)
      app.buttons[i][j] = button
      grid.attach(button, j, i, 1, 1)

  var values = toSeq(Value.low..Value.high)
  app.inOrder.initPuzzle(values)
  values.shuffle()
  app.puzzle.initPuzzle(values)

  for i in [0, BoardSize + 1]:
    for j in 1..BoardSize:
      app.buttons[i][j].connect("clicked", onClick, app)
  for j in [0, BoardSize + 1]:
    for i in 1..BoardSize:
      app.buttons[i][j].connect("clicked", onClick, app)

  newGameButton.connect("clicked", newGame, app)
  quitButton.connect("clicked", onQuit, window)

  app.won = false
  app.update()

  window.showAll()

#———————————————————————————————————————————————————————————————————————————————————————————————————

randomize()
let app = newApplication(PuzzleApp, "Rosetta.Puzzle16Game")
discard app.connect("activate", activate)
discard app.run()

Perl

#!/usr/bin/perl

use strict; # http://www.rosettacode.org/wiki/16_Puzzle_Game
use warnings;
use List::Util qw( any );
use Tk;

my $size = $ARGV[0] // 4;
my $width = length $size ** 2;
my $message = '';
my $steps;
my @board;
my @again;
my $easy = 3;

my $mw = MainWindow->new( -title => '16 Puzzle in Tk' );
$mw->geometry( '+470+300' );
$mw->optionAdd('*font' => 'sans 14');
my $frame = $mw->Frame(-bg => 'gray', -relief => 'ridge',
  -borderwidth => 5)->pack;
my $label = $mw->Label( -textvariable => \$message, -font => 'times-bold 30',
  )->pack;
$mw->Button( -text => "Exit", -command => sub {$mw->destroy},
  )->pack(-side => 'right');
$mw->Button( -text => "Reset", -command => sub {
  @board = @again;
  show();
  $message = $steps = 0;
  $label->configure(-fg => 'black');
  },)->pack(-side => 'right');
$mw->Button( -text => "Easy", -command => sub {$easy = 3; generate()},
  )->pack(-side => 'left');
$mw->Button( -text => "Hard", -command => sub {$easy = 12; generate()},
  )->pack(-side => 'left');

my @cells = map {
  $frame->Label(-text => $_, -relief => 'sunken', -borderwidth => 2,
    -fg => 'white', -bg => 'blue', -font => 'sans 24',
    -padx => 7, -pady => 7, -width => $width,
    )->grid(-row => int( $_ / $size + 2 ), -column => $_ % $size + 2,
    -sticky => "nsew",
  ) } 0 .. $size ** 2 - 1;

for my $i (1 .. $size)
  {
  $frame->Button(-text => ">", -command => sub {move("R$i") },
    )->grid(-row => $i + 1, -column => 1, -sticky => "nsew");
  $frame->Button(-text => "<", -command => sub {move("L$i") },
    )->grid(-row => $i + 1, -column => $size + 2, -sticky => "nsew");
  $frame->Button(-text => "v", -command => sub {move("D$i") },
    )->grid(-row => 1, -column => $i + 1, -sticky => "nsew");
  $frame->Button(-text => "^", -command => sub {move("U$i") },
    )->grid(-row => $size + 2, -column => $i + 1, -sticky => "nsew");
  }

generate();

MainLoop;
-M $0 < 0 and exec $0, @ARGV; # restart if source file modified since start

sub randommove { move( qw(U D L R)[rand 4] . int 1 + rand $size ) }

sub show { $cells[$_]->configure(-text => $board[$_]) for 0 .. $size ** 2 - 1 }

sub success { not any { $_ + 1 != $board[$_] } 0 .. $size ** 2 - 1 }

sub move
  {
  my ($dir, $index) = split //, shift;
  $index--;
  my @from = map {
    $dir =~ /L|R/i ? $_ + $size * $index : $_ * $size + $index
    } 0 .. $size - 1;
  @board[@from] = (@board[@from])[ ($dir =~ /L|U/i || -1) .. $size - 1, 0 ];
  show();
  $message = ++$steps;
  $label->configure(-fg => success() ? 'red' : 'black');
  success() and $message = "Solved in $steps";
  }

sub generate
  {
  @board = 1 .. $size ** 2;
  randommove() for 1 .. 1 + int rand $easy;
  success() and randommove();
  @again = @board;
  $message = $steps = 0;
  }

Phix

NB arrow keys not tested on linux, but "UDLR" should work...

constant level = 5,
         ESC=27, UP=328, DOWN=336, LEFT=331, RIGHT=333
 
sequence board = tagset(16), solve = board
 
procedure print_board()
    printf(1,"    1  2  3  4\n")
    for r=1 to 4 do
        printf(1,"%d: %2d %2d %2d %2d\n",r&board[r*4-3..r*4])
    end for
    puts(1,"\n")
end procedure
 
procedure move(integer d,rc)
    -- d is 1..4 for up/down/left/right
    -- rc is 1..4 for row(d>=3)/column(d<=2)
    sequence idx = repeat(0,4),
             tiles = repeat(0,4)
    for i=1 to 4 do
        idx[i] = iff(d<=2?rc+(i-1)*4:(rc-1)*4+i)
        tiles[i] = board[idx[i]]
    end for
--  ?{d,rc,idx}
    idx = iff(mod(d,2)?idx[4]&idx[1..3]:idx[2..4]&idx[1])
    for i=1 to 4 do
        board[idx[i]] = tiles[i]
    end for
end procedure
 
for i=1 to level do move(rand(4),rand(4)) end for
while 1 do
    print_board()
    if board=solve then
        puts(1,"Solved!\n")
        exit
    end if
    puts(1,"Your move (escape|Up/Down|Left/Right & 1/2/3/4):")
    integer d, rc
    while true do
        while true do
            d = find(upper(wait_key()),{ESC,UP,DOWN,LEFT,RIGHT}&"UDLR")-1
            if d!=-1 then exit end if
        end while
        if d=0 then
            puts(1,"\n\nYou gave up!\n")
            exit
        end if
        if d>4 then d-=4 end if
        puts(1,"UDLR"[d])
        while true do
            rc = find(upper(wait_key()),ESC&"1234UDLR"&{UP,DOWN,LEFT,RIGHT})-1
            if rc>4 then
                if rc>