Here I am sharing a 1 to 15 number puzzle game using a shell script for Linux/Unix systems. You can see the game in the featured GIF image of this article to have an idea about the game.
1 to 15 Number Puzzle Game Using Shell Script
To start the game press Enter and the numbers will shuffle in the board. Now you have to solve the puzzle by making the sequence from 1 to 15 using the arrow keys. Press an up-arrow key to move the digit up on the blank space and similarly down, left and right arrow keys will work. Press q to exit the game. Create the following script and give any name, for example, numpuzzle.sh.
numpuzzle.sh
#!/bin/bash
scriptname=${0##*/}
board=( {1..15} "" ) ## The basic board array
target=( "${board[@]}" ) ## A copy for comparison (the target)
empty=15 ## The empty square
last=0 ## The last move made
A=0 B=1 C=2 D=3 ## Indices into array of possible moves
topleft='\e[0;0H' ## Move cursor to top left corner of window
nocursor='\e[?25l' ## Make cursor invisible
normal=\e[0m\e[?12l\e[?25h ## Resume normal operation
## Board layout is a printf format string
## At its most basic, it could be a simple:
fmt="$nocursor$topleft
%2s %2s %2s %2s
%2s %2s %2s %2s
%2s %2s %2s %2s
%2s %2s %2s %2s
"
## I prefer this ASCII board
fmt="\e[?25l\e[0;0H\n
\t+----+----+----+----+
\t| | | | |
\t| %2s | %2s | %2s | %2s |
\t| | | | |
\t+----+----+----+----+
\t| | | | |
\t| %2s | %2s | %2s | %2s |
\t| | | | |
\t+----+----+----+----+
\t| | | | |
\t| %2s | %2s | %2s | %2s |
\t| | | | |
\t+----+----+----+----+
\t| | | | |
\t| %2s | %2s | %2s | %2s |
\t| | | | |
\t+----+----+----+----+\n\n"
print_board() #@ What the name says
{
printf "$fmt" "${board[@]}"
}
borders() #@ List squares bordering on the empty square
{
## Calculate x/y co-ordinates of the empty square
local x=$(( ${empty:=0} % 4 )) y=$(( $empty / 4 ))
## The array, bordering, has 4 elements, corresponding to the 4 directions
## If a move in any direction would be off the board, that element is empty
##
unset bordering ## clear array before setting it
[ $y -lt 3 ] && bordering[$A]=$(( $empty + 4 ))
[ $y -gt 0 ] && bordering[$B]=$(( $empty - 4 ))
[ $x -gt 0 ] && bordering[$C]=$(( $empty - 1 ))
[ $x -lt 3 ] && bordering[$D]=$(( $empty + 1 ))
}
check() #@ Check whether puzzle has been solved
{
## Compare current board with target
if [ "${board[*]}" = "${target[*]}" ]
then
## Puzzle is completed, print message and exit
print_board
printf "\a\tCompleted in %d moves\n\n" "$moves"
exit
fi
}
move() #@ Move the square in $1
{
movelist="$empty $movelist" ## add current empty square to the move list
moves=$(( $moves + 1 )) ## increment move counter
board[$empty]=${board[$1]} ## put $1 into the current empty square
board[$1]="" ## remove number from new empty square
last=$empty ## .... and put it in old empty square
empty=$1 ## set new value for empty-square pointer
}
random_move() #@ Move one of the squares in the arguments
{
## The arguments to random_move are the squares that can be moved
## (as generated by the borders function)
local sq
while :
do
sq=$(( $RANDOM % $# + 1 ))
sq=${!sq}
[ $sq -ne ${last:-666} ] && ## do not undo last move
break
done
move "$sq"
}
shuffle()
{
local n=0 max=$(( $RANDOM % 100 + 150 )) ## number of moves to make
while [ $(( n += 1 )) -lt $max ]
do
borders ## generate list of possible moves
random_move "${bordering[@]}" ## move to one of them at random
done
}
trap 'printf "$normal"' EXIT ## return terminal to normal state on exit
clear
print_board
echo
printf "
Use the cursor keys to move the tiles around.
The game is finished when you return to the
position shown above.
Try to complete the puzzle in as few moves
as possible.
Press \e[1mENTER\e[0m to continue
"
shuffle ## randomize board
moves=0 ## reset move counter
read -s ## wait for user
clear ## clear the screen
while :
do
borders
print_board
printf "\t %d move" "$moves"
[ $moves -ne 1 ] && printf "s"
check
## read a single character without waiting for <ENTER>
read -sn1 -p $' \e[K' key
## The cursor keys generate three characters: ESC, [ and A, B, C, or D;
## this loop will run three times for each press of a cursor key
## but will not do anything until it receives a letter
## from the cursor key (or entered directly with A etc.), or a 'q' to exit
case $key in
A) [ -n "${bordering[$A]}" ] && move "${bordering[$A]}" ;;
B) [ -n "${bordering[$B]}" ] && move "${bordering[$B]}" ;;
C) [ -n "${bordering[$C]}" ] && move "${bordering[$C]}" ;;
D) [ -n "${bordering[$D]}" ] && move "${bordering[$D]}" ;;
q) echo; break ;;
esac
done
Make the file executable
chmod +x numpuzzle.sh
Test
./numpuzzle.sh
The output would be the same as shown in the featured image of this article.