16 puzzle game: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|REXX}}: used gooder English.)
m (→‎{{header|Wren}}: Minor tidy)
 
(34 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}}==
This REXX version allows the user to choose the grid size for the &nbsp; '''16''' &nbsp; game (puzzle), &nbsp; as
This REXX version allows the user to choose the grid size for the &nbsp; '''16''' &nbsp; game (puzzle), &nbsp; as
well as the difficulity of the puzzle.
well as the difficulty of the puzzle.
<br>The user's responses may have optional whitespace in the answer,
<br>The user's responses may have optional whitespace in the answer,
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 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.

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:

  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>8 then rc -= 4 end if
                d = rc-4
                puts(1,"\b \b"&"UDLR"[d])
            else
                if rc!=-1 then exit end if
            end if
        end while
        if rc=0 then
            puts(1,"\b \b")
        else
            printf(1,"%d\n\n",rc)
            move(d,rc)
            exit
        end if
    end while
    if d=0 then exit end if
end while
Output:

(a level 2 game)

    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!

Raku

For brevity, changed to zero-based and skipped some error handling.

Translation of: Go
# 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-- }
   }
}

REXX

This REXX version allows the user to choose the grid size for the   16   game (puzzle),   as well as the difficulty of the puzzle.
The user's responses may have optional whitespace in the answer, and the answer can be in any case (lower or uppercase).
Not all errors are checked so as to keep the program simpler.

/*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.*/
parse arg N hard seed .                          /*obtain optional arguments from the CL*/
er= '***error***'                                /*literal used to indicate an error msg*/
if    N=='' |    N==","  then    N= 4            /*Not specified?  Then use the default.*/
if hard=='' | hard==","  then hard= 2            /* "      "         "   "   "     "    */
if \isInt(N)  then do;  say sep  er  "grid size isn't an integer: "   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*/
say sep 'Playing a '      N*N       " game with a difficulty level of: "     hard
#=0
         do   r=1  for N                         /* [◄]  build a solution for testing.  */
           do c=1  for N;   #= #+1;    @.r.c= #  /*bump number (count), define a cell.  */
           end   /*c*/
         end     /*r*/
                                                 /* [↓]  HARD  is the puzzle difficulty.*/
     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. */
             else call move substr('abcdefghi',random(1,N), 1)substr("+-",random(1,2),1)
     end   /*hard*/                                                    /* [↓]  move col.*/
                                                 /*play 16─game until  solved  or  quit.*/
   do  until done()                              /*perform moves until puzzle is solved.*/
   call move                                     /*get user's move(s)  and  validate it.*/
   if errMsg\==''  then do;  say sep er errMsg".";  iterate; end   /*possible error msg?*/
   end   /*until*/

call show;     say sep  'Congratulations!   The'      N**2"─puzzle is solved."
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
done: #=0; do r=1 to N; do c=1 to N; #=#+1; if @.r.c\==# then return 0; end; end; return 1
isInt: return datatype( arg(1), 'W')             /*return 1 if arg is a whole number.   */
ghost: do r=1  for n;   do c=1  for n;    !.r.c= @.r.c;  end  /*r*/;   end  /*c*/;  return
/*──────────────────────────────────────────────────────────────────────────────────────*/
move: arg x                                      /*obtain optional move from ARG or ask.*/
      ask1= sep 'Please enter a     row  number    followed by a   L   or   R,       or'
      ask2= sep '       enter a   column letter    followed by a   +   or   -'   @quit
      @quit= '      (or Quit):'
      if x==''  then do
                     if queued()==0  then do;   say;   call show;    say ask1;    say ask2
                                          end
                     pull x;  x= space(x, 0)     /*obtain a response;  elide whitespace.*/
                     end
      y= left(x, 1);          d= right(x, 1)     /*get a number or letter, and also a ± */
      num= isInt(d);        let= datatype(y,'U') /*get direction to shift, based on type*/
      if abbrev('QUIT', x, 1)  then do;  say;  say;  say sep  "quitting.";    exit;    end
               select
               when x == ''                    then errMsg= "nothing entered"
               when length(x)>2                then errMsg= "improper response:  "       x
               when num  &  (y <1   | y >N  )  then errMsg= "row isn't in range: "       y
               when num  &  (d\="L" & d\='R')  then errMsg= "row shift isn't L or R: "   d
               when let  &  (y <"A" | y >HI )  then errMsg= "col isn't in range: "       y
               when let  &  (d\="+" & d\='-')  then errMsg= "col shift isn't + or -: "   d
               otherwise                            errMsg=
               end   /*select*/                  /* [↑]  verify the human entered data. */
      call ghost;    yn= pos(y, 'ABCDEFGHI')     /*create a ghost grid for easy moving. */
      if isInt(y)  then if d=='R'  then  do c=1  for N;  cm= c-1;  if c==1  then cm= c+N-1
                                                         @.y.c= !.y.cm
                                         end
                                   else  do c=1  for N;  cp= c+1;  if c==N  then cp= 1
                                                         @.y.c= !.y.cp
                                         end
                   else if d=='-'  then  do r=1  for N;  rm= r-1;  if r==1  then rm= r+N-1
                                                         @.r.yn= !.rm.yn
                                         end
                                   else  do r=1  for N;  rp= r+1;  if r==N  then rp= 1
                                                         @.r.yn= !.rp.yn
                                         end
      return
/*──────────────────────────────────────────────────────────────────────────────────────*/
show: top= '╔'copies( copies("═", 2)'╦', N);           top= left( top, length(top) - 1)"╗"
      bar= '╠'copies( copies("═", 2)'╬', N);           bar= left( bar, length(bar) - 1)"╣"
      bot= '╚'copies( copies("═", 2)'╩', N);           bot= left( bot, length(bot) - 1)"╝"
      ind= left('',  3 + length(N) )                              /*compute indentation.*/
      col= ind  ind  ind' '   subword("a- b- c- d- e- f- g- h- i-",  1,  n)
      HI= substr('abcdefghi', N, 1);    upper HI
      say col  ind  ind  ind  '-  means shift a column down';            say pad  ind  top
              do    r=1  for N;   z= r'R'    "  ║"                 /*build NxN game grid*/
                 do c=1  for N;   z= z || right(@.r.c, 2)'║'       /*build  row by row. */
                 end   /*c*/
              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==2  then z= z  pad'R  means shift a row right'  /* "   2nd   "    "  */
              say pad z;             if r\==N  then say pad  ind  bar
              end     /*r*/
      say pad  ind  bot;             say;
      say translate(col, '+', "-")   ind  ind  ind  "+  means shift a column up";     say
      return
output   when using the default inputs:
──────── Playing a  16  game with a difficulty level of:  2

                a- b- c- d-                -  means shift a column down
               ╔══╦══╦══╦══╗
          1R   ║ 1║ 2║15║ 4║   1L          L  means shift a row left
               ╠══╬══╬══╬══╣
          2R   ║ 5║ 6║ 3║ 8║   2L          R  means shift a row right
               ╠══╬══╬══╬══╣
          3R   ║12║ 9║ 7║11║   3L
               ╠══╬══╬══╬══╣
          4R   ║13║14║10║16║   4L
               ╚══╩══╩══╩══╝

                a+ b+ c+ d+                +  means shift a column up

──────── Please enter a     row  number    followed by a   L   or   R,       or
────────        enter a   column letter    followed by a   +   or   -       (or Quit):
c +                             ◄■■■■■■■■ user input                                                                                

                a- b- c- d-                -  means shift a column down
               ╔══╦══╦══╦══╗
          1R   ║ 1║ 2║ 3║ 4║   1L          L  means shift a row left
               ╠══╬══╬══╬══╣
          2R   ║ 5║ 6║ 7║ 8║   2L          R  means shift a row right
               ╠══╬══╬══╬══╣
          3R   ║12║ 9║10║11║   3L
               ╠══╬══╬══╬══╣
          4R   ║13║14║15║16║   4L
               ╚══╩══╩══╩══╝

                a+ b+ c+ d+                +  means shift a column up

──────── Please enter a     row  number    followed by a   L   or   R,       or
────────        enter a   column letter    followed by a   +   or   -       (or Quit):
3L                              ◄■■■■■■■■ user input
                a- b- c- d-                -  means shift a column down
               ╔══╦══╦══╦══╗
          1R   ║ 1║ 2║ 3║ 4║   1L          L  means shift a row left
               ╠══╬══╬══╬══╣
          2R   ║ 5║ 6║ 7║ 8║   2L          R  means shift a row right
               ╠══╬══╬══╬══╣
          3R   ║ 9║10║11║12║   3L
               ╠══╬══╬══╬══╣
          4R   ║13║14║15║16║   4L
               ╚══╩══╩══╩══╝

                a+ b+ c+ d+                +  means shift a column up

──────── Congratulations!   The 16─puzzle is solved.

Ring

# Project : Sixteen Puzzle Game

load "guilib.ring"
load "stdlib.ring"

app1 = new qapp {

        t1 = 0
        temp = ""
        table = [][]
        movesnr = 0
        button = list(16) 
        begintiles = list(16)
        pReturn = list(4)
        CounterMan = 0
        saveflag = 0

        stylefusionblack()  
 
        win1 = new qwidget() {
                   move(0,0)
                   resize(360, 600)
                   setwindowtitle("Calmosoft Sixteen Puzzle Game")

                   for n = 1 to 16
                         col = n%4
                         if col = 0 col = 4 ok
                         row = ceil(n/4)
                         button[n] = new qpushbutton(win1)
                         {
                                            setgeometry(60+col*40,60+row*40,40,40)                                            
                                            setstylesheet("color:white")    
                                            setstylesheet("background-color:blue")                                        
                                            settext(string(n))                                                                                        
                          } 
                   next

                  buttonup1 = new qpushbutton(win1)
                  {
                                      setgeometry(100, 60, 40, 40)
                                      settext("up")
                                      setclickevent("up1()")   
                  }

                  buttonup2 = new qpushbutton(win1)
                  {
                                      setgeometry(140, 60, 40, 40)
                                      settext("up")
                                      setclickevent("up2()")   
                  }

                 buttonup3 = new qpushbutton(win1)
                  {
                                      setgeometry(180, 60, 40, 40)
                                      settext("up")
                                      setclickevent("up3()")   
                  }

                 buttonup4 = new qpushbutton(win1)
                  {
                                      setgeometry(220, 60, 40, 40)
                                      settext("up")
                                      setclickevent("up4()")   
                  }

                  buttondown1 = new qpushbutton(win1)
                  {
                                          setgeometry(100, 260, 40, 40)
                                          settext("down")
                                          setclickevent("down1()")   
                  }

                  buttondown2 = new qpushbutton(win1)
                  {
                                          setgeometry(140, 260, 40, 40)
                                          settext("down")
                                          setclickevent("down2()")   
                  }

                  buttondown3 = new qpushbutton(win1)
                  {
                                          setgeometry(180, 260, 40, 40)
                                          settext("down")
                                          setclickevent("down3()")   
                  }

                 buttondown4 = new qpushbutton(win1)
                  {
                                          setgeometry(220, 260, 40, 40)
                                          settext("down")
                                          setclickevent("down4()")   
                  }

                  buttonleft1 = new qpushbutton(win1)
                  {
                                          setgeometry(60, 100, 40, 40)
                                          settext("<<<")
                                          setclickevent("left1()")   
                  }

                  buttonleft2 = new qpushbutton(win1)
                  {
                                          setgeometry(60, 140, 40, 40)
                                          settext("<<<")
                                          setclickevent("left2()")   
                  }

                  buttonleft3 = new qpushbutton(win1)
                  {
                                          setgeometry(60, 180, 40, 40)
                                          settext("<<<")
                                          setclickevent("left3()")   
                  }

                  buttonleft4 = new qpushbutton(win1)
                  {
                                          setgeometry(60, 220, 40, 40)
                                          settext("<<<")
                                          setclickevent("left4()")   
                  }

                  buttonright1 = new qpushbutton(win1)
                  {
                                          setgeometry(260, 100, 40, 40)
                                          settext(">>>")
                                          setclickevent("right1()")   
                  }

                  buttonright2 = new qpushbutton(win1)
                  {
                                          setgeometry(260, 140, 40, 40)
                                          settext(">>>")
                                          setclickevent("right2()")   
                  }

                  buttonright3 = new qpushbutton(win1)
                  {
                                          setgeometry(260, 180, 40, 40)
                                          settext(">>>")
                                          setclickevent("right3()")   
                  }

                  buttonright4 = new qpushbutton(win1)
                  {
                                          setgeometry(260, 220, 40, 40)
                                          settext(">>>")
                                          setclickevent("right4()")   
                  }

                  buttonscramble = new qpushbutton(win1)
                  {
                                             setgeometry(100, 300, 160, 40)
                                             settext("Scarmble")
                                             setclickevent("scramble()")   
                  }

                  buttonreset = new qpushbutton(win1)
                  {
                                        setgeometry(100, 340, 160, 40)
                                        settext("Reset")
                                        setclickevent("reset()")   
                  }

                  buttonsave = new qpushbutton(win1)
                  {
                                   setgeometry(100, 380, 160, 40)
                                   settext("Save Game")
                                   setclickevent("psaveEmpty()")
                  }

                  buttonplay = new qpushbutton(win1)   
                  {
                                 setgeometry(100,420,160,40)  
                                 settext("Replay Game")  
                                 setclickevent("pPlay()")
                  }

                  buttonnr = new qpushbutton(win1)
                  {
                                   setgeometry(100, 460, 160, 40)
                                   settext("Moves : ")
                  }

                  timebtn = new qpushbutton(win1)   
                  {
                                 setgeometry(100,500,160,40)  
                                 settext("Elapsed Time : ")  
                  }
                  t1 = clock()

                  for i = 1 to 16
                       begintiles[i] = string(i)
                  next

                  TimerMan = new qtimer(win1)
                  {
                                    setinterval(0.5)
                                    settimeoutevent("pTime()")
                                    stop()
                  }
                  show()
        }
        exec()
}

func scramble
       reset()
       empty = 16
       movesnr = 0
       buttonnr.settext("Moves : " + movesnr)

       for n= 1 to 1000  
            nr=random(15)+1
            up = (empty = (nr - 4))
            down = (empty = (nr + 4))
            left = ((empty = (nr - 1)) and ((nr % 4) != 1))
            right = ((empty = (nr + 1)) and ((nr % 4) != 0))
            move = up or down or left  or right
            if move = 1 
               temp1 = button[nr].text()
               temp2 = button[empty].text()
               button[empty].settext(temp1)
               button[nr].settext(temp2)
               empty = nr
            ok
       next
       timebtn.settext("Elapsed Time : ")
       t1 = clock()
       table = []
       saveflag = 0
       for n= 1 to 16
             if isstring(button[n].text())
                begintiles[n] = button[n].text()
             else
                begintiles[n] = string(button[n].text())
             ok 
       next

func reset
        movesnr = 0
        buttonnr.settext("Moves : " + movesnr)
        for i = 1 to 16
             button[i] {settext(string(i))}
             button[i].setstylesheet("background-color:blue")
             begintiles[i] = string(i)
        next
        timebtn.settext("Elapsed Time : ")
        t1 = clock()
        table = []
        saveflag = 0
        return

func pClock
        t2 = (clock() - t1)/1000
        timebtn.settext("Elapsed Time : " + t2 + " s")

func psaveEmpty
        timebtn.settext("Elapsed Time : ")
        t1 = clock()
        return

func psave
        if saveflag = 1
           for n = 1 to 4
                add(table, [pReturn[n], button[pReturn[n]].text()])
           next
        ok

func pPlay
        if saveflag = 1
           for n=1 to 16
                 button[n]{settext(begintiles[n])}
                 button[n].setstylesheet("background-color:blue")
           next
           timebtn.settext("Elapsed Time : ")
           movesnr = 0
           buttonnr.settext("Moves : " + movesnr)
           t1 = clock()
           CounterMan = 0
           TimerMan.start()
        ok

func pTime()
        if saveflag = 1
           CounterMan = CounterMan + 1
           if CounterMan > 1
              temp.setstylesheet("background-color:blue")
           ok
           pPlaySleep()
           sleep(1) 
           if CounterMan = len(table)
              TimerMan.stop()
           ok
        ok

func pPlaySleep
        pClock()
        button[table[CounterMan][1]].setstylesheet("background-color:orange") 
        temp =  button[table[CounterMan][1]]
        button[table[CounterMan][1]].settext(table[CounterMan][2])
        movesnr = movesnr + 1
        buttonnr.settext("Moves : " + movesnr)
        return

func up1
        temp = button[1].text()
        button[1].settext(button[5].text())
        button[5].settext(button[9].text())
        button[9].settext(button[13].text())
        button[13].settext(temp)
        movesnr =movesnr + 1
        buttonnr.settext("Moves : " + string(movesnr))
        pClock()
        pReturn = [1,5,9,13]
        saveflag = 1
        psave()
        return

func up2
        temp = button[2].text()
        button[2].settext(button[6].text())
        button[6].settext(button[10].text())
        button[10].settext(button[14].text())
        button[14].settext(temp)
        movesnr =movesnr + 1
        buttonnr.settext("Moves : " + string(movesnr))
        pClock()
        pReturn = [2,6,10,14]
        saveflag = 1
        psave()
        return

func up3
        temp = button[3].text()
        button[3].settext(button[7].text())
        button[7].settext(button[11].text())
        button[11].settext(button[15].text())
        button[15].settext(temp)
        movesnr =movesnr + 1
        buttonnr.settext("Moves : " + string(movesnr))
        pClock()
        pReturn = [3,7,11,15]
        saveflag = 1
        psave()
        return

func up4
        temp = button[4].text()
        button[4].settext(button[8].text())
        button[8].settext(button[12].text())
        button[12].settext(button[16].text())
        button[16].settext(temp)
        movesnr =movesnr + 1
        buttonnr.settext("Moves : " + string(movesnr))
        pClock()
        pReturn = [4,8,12,16]
        saveflag = 1
        psave()
        return

func down1
        temp = button[13].text()
        button[13].settext(button[9].text())
        button[9].settext(button[5].text())
        button[5].settext(button[1].text())
        button[1].settext(temp)
        movesnr =movesnr + 1
        buttonnr.settext("Moves : " + string(movesnr))
        pClock()
        pReturn = [13,9,5,1]
        saveflag = 1
        psave()
        return

func down2
        temp = button[14].text()
        button[14].settext(button[10].text())
        button[10].settext(button[6].text())
        button[6].settext(button[2].text())
        button[2].settext(temp)
        movesnr =movesnr + 1
        buttonnr.settext("Moves : " + string(movesnr))
        pClock()
        pReturn = [14,10,6,2]
        saveflag = 1
        psave()
        return

func down3
        temp = button[15].text()
        button[15].settext(button[11].text())
        button[11].settext(button[7].text())
        button[7].settext(button[3].text())
        button[3].settext(temp)
        movesnr =movesnr + 1
        buttonnr.settext("Moves : " + string(movesnr))
        pClock()
        pReturn = [15,11,7,3]
        saveflag = 1
        psave()
        return

func down4
        temp = button[16].text()
        button[16].settext(button[12].text())
        button[12].settext(button[8].text())
        button[8].settext(button[4].text())
        button[4].settext(temp)
        movesnr =movesnr + 1
        buttonnr.settext("Moves : " + string(movesnr))
        pClock()
        pReturn = [16,12,8,4]
        saveflag = 1
        psave()
        return

func left1
        temp = button[1].text()
        button[1].settext(button[2].text())
        button[2].settext(button[3].text())
        button[3].settext(button[4].text())
        button[4].settext(temp)
        movesnr =movesnr + 1
        buttonnr.settext("Moves : " + string(movesnr))
        pClock()
        pReturn = [1,2,3,4]
        saveflag = 1
        psave()
        return

func left2
        temp = button[5].text()
        button[5].settext(button[6].text())
        button[6].settext(button[7].text())
        button[7].settext(button[8].text())
        button[8].settext(temp)
        movesnr =movesnr + 1
        buttonnr.settext("Moves : " + string(movesnr))
        pClock()
        pReturn = [5,6,7,8]
        saveflag = 1
        psave()
        return

func left3
        temp = button[9].text()
        button[9].settext(button[10].text())
        button[10].settext(button[11].text())
        button[11].settext(button[12].text())
        button[12].settext(temp)
        movesnr =movesnr + 1
        buttonnr.settext("Moves : " + string(movesnr))
        pClock()
        pReturn = [9,10,11,12]
        saveflag = 1
        psave()
        return

func left4
        temp = button[13].text()
        button[13].settext(button[14].text())
        button[14].settext(button[15].text())
        button[15].settext(button[16].text())
        button[16].settext(temp)
        movesnr =movesnr + 1
        buttonnr.settext("Moves : " + string(movesnr))
        pClock()
        pReturn = [13,14,15,16]
        saveflag = 1
        psave()
        return

func right1
        temp = button[4].text()
        button[4].settext(button[3].text())
        button[3].settext(button[2].text())
        button[2].settext(button[1].text())
        button[1].settext(temp)
        movesnr =movesnr + 1
        buttonnr.settext("Moves : " + string(movesnr))
        pClock()
        pReturn = [4,3,2,1]
        saveflag = 1
        psave()
        return

func right2
        temp = button[8].text()
        button[8].settext(button[7].text())
        button[7].settext(button[6].text())
        button[6].settext(button[5].text())
        button[5].settext(temp)
        movesnr =movesnr + 1
        buttonnr.settext("Moves : " + string(movesnr))
        pClock()
        pReturn = [8,7,6,5]
        saveflag = 1
        psave()
        return

func right3
        temp = button[12].text()
        button[12].settext(button[11].text())
        button[11].settext(button[10].text())
        button[10].settext(button[9].text())
        button[9].settext(temp)
        movesnr =movesnr + 1
        buttonnr.settext("Moves : " + string(movesnr))
        pClock()
        pReturn = [12,11,10,9]
        saveflag = 1
        psave()
        return

func right4
        temp = button[16].text()
        button[16].settext(button[15].text())
        button[15].settext(button[14].text())
        button[14].settext(button[13].text())
        button[13].settext(temp)
        movesnr =movesnr + 1
        buttonnr.settext("Moves : " + string(movesnr))
        pClock()
        pReturn = [16,15,14,13]
        saveflag = 1
        psave()
        return

Output image:

16 Puzzle Game

Wren

Translation of: Go
Library: Wren-iterate
Library: Wren-fmt
Library: Wren-ioutil
Library: Wren-str
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.")
        }
    }
}
Output:

Sample (very easy!) 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 ║  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!!