15 puzzle game: Difference between revisions
m
→{{header|EasyLang}}
Basicgames (talk | contribs) |
|||
(46 intermediate revisions by 12 users not shown) | |||
Line 144:
{{out}}
The same as in Python.
=={{header|68000 Assembly}}==
Line 3,238 ⟶ 3,237:
=={{header|BASIC}}==
==={{header|Applesoft BASIC}}===
<syntaxhighlight lang="basic"> 100 GOSUB 500INITIALIZE
110 FOR Q = 1 TO 1
120 IF I <> X OR J <> Y THEN GOSUB 200MOVE
130 ON W GOSUB 330,450
140 LET I = K(0, K) + X
150 LET J = K(1, K) + Y
160 LET Q = K(2, K) OR W = 3
170 NEXT Q
180 VTAB T + 3
190 END
REM MOVE
200 IF I < 0 THEN RETURN
210 IF I > 3 THEN RETURN
220 IF J < 0 THEN RETURN
230 IF J > 3 THEN RETURN
240 LET M = (I + J * 4) * 3
250 LET N = (X + Y * 4) * 3
260 IF N > M GOTO 290SWAP
270 LET N = M
280 LET M = (X + Y * 4) * 3
REM SWAP
290 LET A$ = MID$(A$, 1, M) + MID$(A$, N + 1, 2) + MID$(A$,M + 3, N - M - 2) + MID$(A$, M + 1, 2) + MID$(A$, N + 3)
300 LET X = I
310 LET Y = J
320 ON W GOTO 440,400
REM RANDOM MOVE
330 VTAB T + 3
340 HTAB 2
350 PRINT MID$(S$, S + 1, 10);
360 LET S = NOT S
370 LET K = INT(RND(1) * 4) + 1
380 IF PEEK(49152) < 128 OR A$ = W$ THEN RETURN
390 LET K = PEEK(49168) * 0
REM SHOW
400 VTAB T
410 HTAB 1
420 PRINT A$;
430 LET W = (A$ = W$) + 2
REM DON'T SHOW
440 RETURN
REM GET KEY
450 VTAB T + Y
460 HTAB X * 3 + 2
470 GET K$
480 LET K = ASC (K$)
490 RETURN
REM INITIALIZE
500 PRINT " 15-PUZZLE"
REM KEYBOARD
REM ARROW KEYS TWO HANDED CLASSIC T REVERSE T SEQUENCED
REM ^K A I G ^C
REM ^H ^J ^U , Z . J K L H T F ^B ^D ^A
REM RIGHT , J H ^A
510 DATA8,44,74,106,72,104,1
REM LEFT . L F ^B
520 DATA21,46,76,108,70,102,2
REM DOWN A I G ^C
530 DATA11,65,97,73,105,71,103,3
REM UP Z K T ^D
540 DATA10,90,122,75,107,84,116,4
REM QUIT ^Q ESC
550 DATA0,17,27,0
560 DIM K(2,127)
570 FOR V = 0 TO 2
580 FOR D = - 1 TO 1 STEP 2
590 FOR R = 1 TO 1
600 READ K
610 LET K(V,K) = D
620 LET R = K < 5
630 NEXT R,D,V
640 LET A$ = " 1 2 3 4"
650 LET M$ = CHR$ (13)
660 LET L$ = " 5 6 7 8"
670 LET A$ = A$ + M$ + L$
680 LET L$ = " 9 10 11 12"
690 LET A$ = A$ + M$ + L$
700 LET L$ = "13 14 15 "
710 LET A$ = A$ + M$ + L$
720 LET W$ = A$
730 DATA3,3,3,3,1,0
740 READ X,Y,I,J,W,k(2, 0)
750 PRINT "PRESS A KEY"
760 PRINT " TO STOP"
770 LET S$ = " SHUFFLING "
780 LET T = PEEK(37) - 2
790 RETURN</syntaxhighlight>
==={{header|Commodore BASIC}}===
<syntaxhighlight lang="basic">10 REM 15-PUZZLE GAME
Line 4,620 ⟶ 4,717:
=={{header|Craft Basic}}==
[[File:15 puzzle craft basic.png|thumb]]
<syntaxhighlight lang="basic">
define size = 16, correct = 0, moves = 0
Line 4,639 ⟶ 4,736:
title "15 Puzzle"
bgcolor 0,128,0
cls graphics
resize 0, 0, 170, 270
center
let x = 0
let y = 30
for i = 0 to size - 1
if x = 112 then
Line 4,664 ⟶ 4,760:
buttonform x, y, 25, 20
next i
formid 17
Line 4,711 ⟶ 4,805:
updateform
formid i + 1
Line 4,720 ⟶ 4,812:
let list[i] = 0
let t = 0
let i = 0
do
let n = 120 - t
formid i + 1
formtext n
updateform
let list[i] = n
break
endif
for f = 0 to size - 1
let n =
let s = 0
for c = 0 to i - 1
if n = list[c] then
let s = 1
break c
endif
if s = 0 and list[i] = 0 then
Line 4,756 ⟶ 4,857:
let list[i] = n
let t = t + n
let i = i + 1
endif
wait
next f
loop i < size - 1
Line 4,778 ⟶ 4,878:
do
let click =
if click > 0 and click < 17 and start = 1 then
Line 4,818 ⟶ 4,918:
if click = 21 then
alert "15 Puzzle",
endif
Line 4,905 ⟶ 5,005:
let correct = 0
for i = 0 to size - 2
if list[i] = i + 1 then
let correct = correct + 1
endif
next i
formid 18
formtext "Correct: ", correct
updateform
if correct = size - 1 then
wait
alert "You win! Moves: ", moves
Line 4,930 ⟶ 5,028:
return</syntaxhighlight>
=={{header|Delphi}}==
{{works with|Delphi|6.0}}
{{libheader|Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, Grids, MMSystem}}
This is a pure Delphi version of the program. Rather than use a console based
display, this version uses a Delphi Form for the game and a string grid
for the display. The users selects a move by clicking on the a particular
cell in the grid.
<syntaxhighlight lang="Delphi">
const BoardWidth = 4; BoardHeight = 4;
const CellCount = BoardWidth * BoardHeight;
var GameBoard: array [0..BoardWidth-1,0..BoardHeight-1] of integer;
procedure BuildBoard;
{Put all number in the game board}
var I,X,Y: integer;
begin
for I:=0 to CellCount-1 do
begin
Y:=I div BoardHeight;
X:=I mod BoardWidth;
GameBoard[X,Y]:=I;
end;
end;
function IsWinner: boolean;
{Check to see if tiles are winning in order}
var I,X,Y: integer;
begin
Result:=False;
for I:=1 to CellCount-1 do
begin
Y:=(I-1) div BoardHeight;
X:=(I-1) mod BoardWidth;
if GameBoard[X,Y]<>I then exit;
end;
Result:=True;
end;
procedure DisplayGameBoard(Grid: TStringGrid);
{Display game on TStringGrid component}
var Tile,X,Y: integer;
var S: string;
begin
for Y:=0 to High(GameBoard) do
begin
S:='';
for X:=0 to High(GameBoard[0]) do
begin
Tile:=GameBoard[X,Y];
if Tile=0 then Form1.GameGrid.Cells[X,Y]:=''
else Grid.Cells[X,Y]:=IntToStr(GameBoard[X,Y]);
end;
end;
end;
procedure ExchangePieces(P1,P2: TPoint);
{Exchange the pieces specified by P1 and P2}
var T: integer;
begin
T:=GameBoard[P1.X,P1.Y];
GameBoard[P1.X,P1.Y]:=GameBoard[P2.X,P2.Y];
GameBoard[P2.X,P2.Y]:=T;
end;
procedure Randomize;
{Scramble piece by exchanging random pieces}
var I: integer;
var P1,P2: TPoint;
begin
for I:=0 to 100 do
begin
P1:=Point(Random(BoardWidth),Random(BoardHeight));
P2:=Point(Random(BoardWidth),Random(BoardHeight));
ExchangePieces(P1,P2);
end;
end;
procedure NewGame;
{Initiate new game by randomizing tiles}
begin
BuildBoard;
Randomize;
DisplayGameBoard(Form1.GameGrid);
end;
function FindEmptyNeighbor(P: TPoint): TPoint;
{Find the empty neighbor cell if any}
{Returns Point(-1,-1) if none found}
begin
Result:=Point(-1,-1);
if (P.X>0) and (GameBoard[P.X-1,P.Y]=0) then Result:=Point(P.X-1,P.Y)
else if (P.X<(BoardWidth-1)) and (GameBoard[P.X+1,P.Y]=0) then Result:=Point(P.X+1,P.Y)
else if (P.Y>0) and (GameBoard[P.X,P.Y-1]=0) then Result:=Point(P.X,P.Y-1)
else if (P.Y<(BoardHeight-1)) and (GameBoard[P.X,P.Y+1]=0) then Result:=Point(P.X,P.Y+1);
end;
procedure ShowStatus(S: string; BellCount: integer);
{Display status string and ring bell specified number of times}
var I: integer;
begin
Form1.StatusMemo.Lines.Add(S);
for I:=1 to BellCount do PlaySound('DeviceFail', 0, SND_SYNC);
end;
procedure HandleMouseClick(X,Y: integer; Grid: TStringGrid);
{Handle mouse click on specified grid}
var Pos,Empty: TPoint;
var Item: integer;
begin
Grid.MouseToCell(X, Y,Pos.X, Pos.Y);
Item:=GameBoard[Pos.X,Pos.Y];
Empty:=FindEmptyNeighbor(Pos);
if (Item>0) and (Empty.X>=0) then
begin
ExchangePieces(Empty,Pos);
DisplayGameBoard(Grid);
if IsWinner then ShowStatus('Winner', 5);
end
else ShowStatus('Invalid Command.', 1);
end;
procedure TForm1.NewGameBtnClick(Sender: TObject);
{Create new game when button pressed}
begin
NewGame;
end;
procedure TForm1.GameGridMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
{Use the mouse click event to select a move}
begin
HandleMouseClick(X,Y,GameGrid);
end;
procedure TForm1.FormCreate(Sender: TObject);
{Start new game when the program starts running}
begin
NewGame;
end;
</syntaxhighlight>
{{out}}
[[File:Delphi15Puzzle.png|frame|none]]
=={{header|EasyLang}}==
[https://easylang.
<syntaxhighlight
sys topleft
background 432
textsize 13
len f[] 16
clear
for i = 1 to 16
h = f[i]
if h < 16
x = (i - 1) mod 4 * 24 + 3
y = (i - 1) div 4 * 24 + 3
color 210
move x y
rect 22 22
move x + 4 y + 6
if h < 10
move x + 6 y + 6
.
color 885
text h
.
.
.
global done .
move x y
color 000
move
circle s / 3
move x + 3.5 y - 3.5
curve
.
proc init . .
done = 0
for i = 1 to 16
f[i] = i
.
# shuffle
for i = 15 downto 2
r = randint i
swap f[r] f[i]
.
# make it solvable
inv = 0
for i = 1 to 15
for j = 1 to i - 1
if f[j] > f[i]
inv += 1
.
.
if inv mod 2 <> 0
.
textsize 12
draw
.
c = mouse_x div 25
r = mouse_y div 25
i = r * 4 + c + 1
if c > 0 and f[i - 1] = 16
swap f[i] f[i - 1]
elif r > 0 and f[i - 4] = 16
swap f[i] f[i - 4]
elif r < 3 and f[i + 4] = 16
swap f[i] f[i + 4]
elif c < 3 and f[i + 1] = 16
swap f[i] f[i + 1]
.
done = 1
.
on mouse_down
if done =
elif done = 3
.
.
on timer
if done = 1
smiley
done = 2
timer 2
else
done = 3
.
.
init
</syntaxhighlight>
=={{header|F_Sharp|F#}}==
Line 5,486 ⟶ 5,770:
print
drawboard B()</syntaxhighlight>
=={{header|FutureBasic}}==
<syntaxhighlight lang="FutureBasic">
// 15 Puzzle // 26 september 2023 //
begin globals
CFMutableStringRef board : board = fn MutableStringNew
end globals
void local fn buildUI
Long i, j, k = 1 // k is button number
window 1, @"15 Puzzle", ( 0, 0, 200, 200 ), 3
for j = 3 to 0 step -1 : for i = 0 to 3 // Top to bottom, left to right
button k, Yes, 1, @"", ( 20 + 40 * i, 20 + 40 * j , 40, 40 ), , NSBezelStyleShadowlessSquare
ControlSetFont(k, fn FontSystemFontOfSize( 21 ) )
ControlSetAlignment( k, NSTextAlignmentCenter )
k ++
next : next
menu 1, , 1, @"File": menu 1, 1, , @"Close", @"w" : MenuItemSetAction( 1, 1, @"performClose:" )
editmenu 2 : menu 2, 0, No : menu 3, , , @"Level"
for i = 1 to 8 : menu 3, i, , str( i ) : next
MenuSetOneItemOnState( 3, 3 )
end fn
void local fn newGame
CFStringRef s
Long i, m, n = 16, p = 0 // n is empty starting tile, p holds previous move
Bool ok
MutableStringSetString (board, @" 123456789ABCDEF " )
for i = 1 to fn MenuSelectedItem( 3 )^2 // Number of shuffles is square of level
do : ok = Yes
m = n + int( 2.6 * rnd( 4 ) - 6.5 ) // Choose a random move, but
if m < 1 or m > 16 or m == p then ok = No // not of bounds or previous,
if n mod 4 = 0 and m = n + 1 then ok = No // and don't exchange eg tile 4 and 5
if n mod 4 = 1 and m = n - 1 then ok = No // or 9 and 8
until ok = Yes // Found a move, swap in board string
s = mid( board, m, 1 ) : mid( board, m, 1 ) = @" " : mid( board, n, 1 ) = s
p = n : n = m
next
for i = 1 to 16 // Stamp the buttons, p is unicode of board char, s is button title
p = (Long) fn StringCharacterAtIndex( board, i )
if p > 64 then s = fn StringWithFormat ( @"%d", p - 55 ) else s = mid( board, i, 1 )
button i, Yes, 1, s
if fn StringIsEqual( s, @" ") == Yes then button i, No
next
end fn
void local fn move ( n as Long )
CFStringRef s
Long i, m, x = -1 // x is empty plot
Bool ok
for i = 1 to 4 // see if clicked button is next to empty plot
m = n + int( 2.6 * i - 6.5 ) // -4. -1, +1, +4
ok = Yes
if m < 1 or m > 16 then ok = No // Not out of bounds etc
if n mod 4 = 0 and m = n + 1 then ok = No
if n mod 4 = 1 and m = n - 1 then ok = No
if ok == Yes
if fn StringIsEqual( mid( board, m, 1 ), @" " ) then x = m
end if
next
if x > -1 // Swap places in board string and button titles
s = mid( board, n, 1 ) : mid( board, n, 1 ) = @" " : mid( board, x, 1 ) = s
button x, Yes, 1 , fn ButtonTitle( n ) : button n, No, 1, @" "
end if
if fn StringIsEqual( board, @" 123456789ABCDEF " )
alert 112, , @"Well done.", @"Another game?", @"Yes;No", Yes
end if
end fn
void local fn doMenu( mnu as Long, itm as Long )
if mnu == 3 then MenuSetOneItemOnState( 3, itm ) : fn newGame
end fn
void local fn DoDialog( evt as Long, tag as Long )
select evt
case _btnClick : fn move( tag )
case _alertDidEnd : if tag == NSAlertFirstButtonReturn then fn newGame else end
end select
end fn
fn buildUI
fn newGame
on dialog fn doDialog
on menu fn doMenu
handleevents
</syntaxhighlight>
[[File:FB 15.png]]
=={{header|Gambas}}==
Line 6,828 ⟶ 7,210:
Possible moves are: ["13", "12", "9"], 0 to exit. Your move? =>
</pre>
=={{header|Koka}}==
Imperative Version
{{trans|C}}
<syntaxhighlight lang="koka">
import std/num/random
import std/os/readline
struct board
cells: vector<vector<int>>
hole-pos: (int, int)
size: (int, int)
type move
MUp
MDown
MLeft
MRight
fun delta(move: move): (int, int)
match move
MUp -> (0, 1)
MDown -> (0, -1)
MLeft -> (1, 0)
MRight -> (-1, 0)
inline extern unsafe-assign : forall<a> ( v : vector<a>, i : ssize_t, x : a ) -> total ()
c "kk_vector_unsafe_assign"
fun update(game: board, move: move): exn board
val (dx, dy) = move.delta
val (hx, hy) = game.hole-pos
val (nx, ny) = (hx + dx, hy + dy)
val (w, h) = game.size
if nx >= 0 && nx < w && ny >= 0 && ny < h then
game.cells[hx].unsafe-assign(hy.ssize_t, game.cells[nx][ny])
game.cells[nx].unsafe-assign(ny.ssize_t, 0)
game(hole-pos=(nx, ny))
else
game
val num_shuffles = 100
fun random-move(): random move
match random-int() % 4
0 -> MUp
1 -> MDown
2 -> MLeft
_ -> MRight
fun setup(size: (int, int)): <exn,random> board
val (w, h) = size
val cells = vector-init(w, fn(x) vector-init(h, fn(y) x*h + y + 1))
var game := Board(cells, (w - 1, h - 1), size)
for(0,num_shuffles) fn(_)
game := game.update(random-move())
game
effect break<a>
final ctl break(a: a) : b
fun finished(game: board): exn bool
val (w, h) = game.size
var i := 1
with final ctl break(a:bool)
a
for(0,w - 1) fn(x)
for(0,h - 1) fn(y)
if game.cells[x][y] != i then
break(False)
else
i := i + 1
True
fun display(game: board): <console,exn> ()
println("")
val (w, h) = game.size
for(0, h - 1) fn(y)
for(0, w - 1) fn(x)
val c = game.cells[x][y]
if c == 0 then
print(" ")
else
print(" " ++ c.show ++ " ")
println("")
println("")
fun get_move(): <div,console,exn,break<string>> move
val c = readline()
match c.trim()
"w" -> MUp
"s" -> MDown
"a" -> MLeft
"d" -> MRight
"q" -> break("Finished")
_ -> get_move()
fun main()
var game := setup((4, 4))
with final ctl break(a:string)
a.println
while {!game.finished}
game.display
val move = get_move()
game := game.update(move)
println("You won!")
</syntaxhighlight>
=={{header|Kotlin}}==
Line 7,637 ⟶ 8,125:
Seed = time(NULL);
").</syntaxhighlight>
=={{header|MiniScript}}==
===Text-based version===
Text-based game that works with both command-line and [http://miniscript.org/MiniMicro Mini Micro] versions of MiniScript. The Mini Micro has animation showing the changes in the board when the tiles are being shuffled or a move is made.
<syntaxhighlight lang="miniscript">
isMiniMicro = version.hostName == "Mini Micro"
// These coordinates are [row,col] not [x,y]
Directions = {"up": [-1,0], "right": [0,1], "down": [1, 0], "left": [0,-1]}
TileNum = range(1, 15)
Puzzle15 = {"grid":[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]],
"blankPos": [3,3]}
Puzzle15.__setTile = function(position, value)
row = position[0]; col = position[1]
self.grid[row][col] = value
end function
Puzzle15.__getTile = function(position)
row = position[0]; col = position[1]
return self.grid[row][col]
end function
Puzzle15.__getOppositeDirection = function(direction)
directions = Directions.indexes
oppix = (directions.indexOf(direction) + 2) % 4
return directions[oppix]
end function
Puzzle15.getState = function
return self.grid
end function
Puzzle15.getBlankPos = function
return self.blankPos
end function
Puzzle15.hasWon = function
count = 1
for r in range(0, 3)
for c in range(0, 3)
if self.grid[r][c] != count then return false
count += 1
end for
end for
return true
end function
Puzzle15.move = function(direction)
if not Directions.hasIndex(direction) then return false
move = Directions[direction]
curPos = self.blankPos[:]
newPos = [curPos[0] + move[0], curPos[1] + move[1]]
if (-1 < newPos[0] < 4) and (-1 < newPos[1] < 4) then
value = self.__getTile(newPos)
self.__setTile(curPos, value)
self.__setTile(newPos, 16) // 16 is the blank tile
self.blankPos = newPos
return true
else
return false
end if
end function
Puzzle15.shuffle = function(n)
lastMove = ""
directions = Directions.indexes
for i in range(1, 50)
while true
moveTo = directions[floor(rnd * 4)]
oppMove = self.__getOppositeDirection(moveTo)
if self.__getOppositeDirection(moveTo) != lastMove and self.move(moveTo) then
lastMove = moveTo
if isMiniMicro then
self.displayBoard
wait 1/33
end if
break
end if
end while
end for
end function
Puzzle15.displayBoard = function
if isMiniMicro then clear
for r in range(0, 3)
for c in range(0, 3)
grid = self.getState
if grid[r][c] == 16 then
s = " "
else
s = (" " + grid[r][c])[-3:]
end if
print s, ""
end for
print
end for
end function
Puzzle15.shuffle
while not Puzzle15.hasWon
if isMiniMicro then
clear
else
print
end if
Puzzle15.displayBoard
while true
print
move = input("Enter the direction to move the blank in (up, down, left, right): ")
move = move.lower
if Directions.hasIndex(move) and Puzzle15.move(move) then break
print "Please enter a valid move."
end while
end while
print "Congratulations! You solved the puzzle!"</syntaxhighlight>
===Fully animated version===
This fully animated implementation is for use with [http://miniscript.org/MiniMicro Mini Micro]. It uses assets that come with the Mini Micro as well as a sound file of wood blocks scrapping and hitting each other that is separate from this code. This scrip will still run without it and will not simulate the sound of the tiles moving. You may find this file on [https://github.com/chinhouse/MiniScript/blob/main/Puzzle-15/small_wooden_bricks_movement.mp3 Github].
<syntaxhighlight lang="miniscript">
woodSound = file.loadSound("small_wooden_bricks_movement.mp3")
puzzleTiles = function
gfx.scale = 2
woodImg = file.loadImage("/sys/pics/textures/Wood.png")
gfx.drawImage woodImg,0,0
gfx.color = color.black
gfx.drawRect 6,6, 244,244
bgBoard = new Sprite
bgBoard.image = gfx.getImage(0, 0, 256, 256)
bgBoard.scale = 1.6
bgBoard.x = (960 - 1.6 * 256) / 2 + 128 * 1.6
bgBoard.y = (640 - 1.6 * 256) / 2 + 128 * 1.6
bgBoard.tint = color.rgb(102,51,0)
sprites = [bgBoard]
gfx.clear
gfx.drawImage woodImg,0,0
positions = range(1,15)
positions.shuffle
spriteScale = 1.5
spriteSize = 64
tileXOffset = (960 - 3 * spriteSize * spriteScale) / 2
tileYOffset = (640 - 3 * spriteSize * spriteScale) / 2
for i in range(0,14)
s = str(i+1)
pos = positions[i]
x = pos % 4
y = floor(pos / 4)
xp = x * spriteSize + (spriteSize - (s.len * 14 + 2)) / 2
yp = y * spriteSize + 20
gfx.print s, xp, yp, color.black, "normal"
sprite = new Sprite
sprite.image = gfx.getImage(x * spriteSize, y * spriteSize, spriteSize, spriteSize)
sprite.scale = spriteScale
xs = i % 4; ys = 3 - floor(i / 4)
sprite.x = spriteSize * (xs) * spriteScale + tileXOffset
sprite.y = spriteSize * ys * spriteScale + tileYOffset
sprite.localBounds = new Bounds
sprite.localBounds.width = spriteSize
sprite.localBounds.height = spriteSize
// tint the blocks with different shades of brown
sat = floor(rnd * 47 - 10) * 3
sprite.tint = color.rgb(153 + sat, 102 + sat, 51 + sat)
sprites.push(sprite)
end for
return sprites
end function
moveTiles = function(sprites, instructions, t = 6, mute = false)
direction = instructions[0]
delta = Directions[direction]
if not mute and woodSound and direction then woodSound.play 0.1
for i in range(96, 1, -t)
for tile in instructions[1:]
sprites[tile].x += delta[1] * t
sprites[tile].y += -delta[0] * t
end for
wait 1/3200
end for
end function
// These coordinates are [row,col] not [x,y]
Directions = {"up": [-1,0], "right": [0,1], "down": [1, 0], "left": [0,-1]}
TileNum = range(1, 15)
Puzzle15 = {"grid":[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]],
"blankPos": [3,3], "movesToShuffled": [], "movesMade": [], "moveCount": 0}
Puzzle15.__setTile = function(position, value)
row = position[0]; col = position[1]
self.grid[row][col] = value
end function
Puzzle15.__getTile = function(position)
row = position[0]; col = position[1]
return self.grid[row][col]
end function
Puzzle15.__getOppositeDirection = function(direction)
directions = Directions.indexes
oppix = (directions.indexOf(direction) + 2) % 4
return directions[oppix]
end function
Puzzle15.__getDirectionToTile = function(n)
for row in range(0, 3)
for col in range(0, 3)
if self.grid[row][col] == n then
dr = row - self.getBlankPos[0]
dc = col - self.getBlankPos[1]
return Directions.indexOf([sign(dr), sign(dc)])
end if
end for
end for
return null
end function
Puzzle15.getState = function
return self.grid
end function
Puzzle15.getBlankPos = function
return self.blankPos
end function
Puzzle15.hasWon = function
count = 1
for r in range(0, 3)
for c in range(0, 3)
if self.grid[r][c] != count then return false
count += 1
end for
end for
return true
end function
Puzzle15.move = function(direction)
if not Directions.hasIndex(direction) then return false
move = Directions[direction]
curPos = self.blankPos[:]
newPos = [curPos[0] + move[0], curPos[1] + move[1]]
if (-1 < newPos[0] < 4) and (-1 < newPos[1] < 4) then
value = self.__getTile(newPos)
self.__setTile(curPos, value)
self.__setTile(newPos, 16) // 16 is the blank tile
self.blankPos = newPos
if self.movesMade.len > 0 then
lastMove = self.movesMade[-1]
else
lastMove = ""
end if
if lastMove != "" and self.__getOppositeDirection(lastMove) == direction then
self.movesMade.pop
else
self.movesMade.push(direction)
end if
self.moveCount += 1
return value // return tile that was moved
else
return false
end if
end function
Puzzle15.moveNumber = function(n)
direction = Puzzle15.__getDirectionToTile(n)
origDir = direction
if direction == null then return 0
tiles = [self.__getOppositeDirection(direction)]
while origDir == direction
tileNum = self.move(origDir)
tiles.insert(1, tileNum)
direction = self.__getDirectionToTile(n)
end while
return tiles
end function
Puzzle15.shuffle = function(n, sprites)
lastMove = ""
directions = Directions.indexes
cnt = 0
instructions = []
while self.movesToShuffled.len < n
if self.movesToShuffled.len == 0 then
lastMove = ""
else
lastMove = self.movesToShuffled[-1]
end if
moveTo = directions[floor(rnd * 4)]
cnt += 1
oppMove = self.__getOppositeDirection(moveTo)
tileMoved = self.move(moveTo)
if oppMove != lastMove and tileMoved then
instructions.push([oppMove, tileMoved])
lastMove = moveTo
self.movesToShuffled.push(moveTo)
else if oppMove == lastMove then
self.movesToShuffled.pop
instructions.pop
end if
end while
for i in instructions
moveTiles(sprites, i, 96, true)
end for
end function
clear
display(4).sprites = puzzleTiles
gfx.clear
Puzzle15.shuffle(200, display(4).sprites)
while not Puzzle15.hasWon
if mouse.button and not wasPressed then
tile = 16
for i in range(1, 15)
sprite = display(4).sprites[i]
//print sprite.localBounds
if sprite.contains(mouse) then tile = i
end for
if tile != 16 then
instructions = Puzzle15.moveNumber(tile)
if instructions then moveTiles(display(4).sprites, instructions)
end if
end if
wasPressed = mouse.button
yield
end while
fanfare = file.loadSound("/sys/sounds/fanfare.wav")
fanfare.play 0.25
while fanfare.isPlaying
end while
key.get
</syntaxhighlight>
=={{header|MUMPS}}==
Line 8,520 ⟶ 9,350:
=== console only ===
Kept simple. Obviously, increase the 5 random moves for more of a challenge.
<!--(phixonline)-->
<syntaxhighlight lang="phix">
constant ESC=27, UP=328, LEFT=331, RIGHT=333, DOWN=336
sequence board = tagset(15)&0, solve = board
integer pos = 16
procedure print_board()
for i=1 to length(board) do
puts(1,iff(i=pos?" ":sprintf("%3d",{board[i]})))
if mod(i,4)=0 then puts(1,"\n") end if
end for
puts(1,"\n")
end procedure
procedure move(integer d)
integer new_pos = pos+{+4,+1,-1,-4}[d]
if new_pos>=1 and new_pos<=16
and (mod(pos,4)=mod(new_pos,4) -- same col, or row:
or floor((pos-1)/4)=floor((new_pos-1)/4)) then
{board[pos],board[new_pos]} = {board[new_pos],0}
pos = new_pos
end if
end procedure
for i=1 to 5 do move(rand(4)) end for
while 1 do
print_board()
if board=solve then exit end if
integer c = find(wait_key(),{ESC,UP,LEFT,RIGHT,DOWN})-1
if c=0 then exit end if
move(c)
end while
puts(1,"solved!\n")
</syntaxhighlight>
{{out}}
<pre>
Line 8,582 ⟶ 9,413:
solved!
</pre>
=== GUI version ===
{{libheader|Phix/pGUI}}
Line 9,509 ⟶ 10,341:
line(self.x + 2, self.y + 1, self.x +
piece_side_length - 1, self.y + 1)</syntaxhighlight>
=={{header|Prolog}}==
Works with SWI-Prolog
<syntaxhighlight lang="prolog">
% map the sequence of cells
next_cell(1,Y,2,Y).
next_cell(2,Y,3,Y).
next_cell(3,Y,4,Y).
next_cell(4,1,1,2).
next_cell(4,2,1,3).
next_cell(4,3,1,4).
% map the game items, and how to print
item(1,2, ' 1 ').
item(2,3, ' 2 ').
item(3,4, ' 3 ').
item(4,5, ' 4 ').
item(5,6, ' 5 ').
item(6,7, ' 6 ').
item(7,8, ' 7 ').
item(8,9, ' 8 ').
item(9,10, ' 9 ').
item(10,11, ' 10 ').
item(11,12, ' 11 ').
item(12,13, ' 12 ').
item(13,14, ' 13 ').
item(14,15, ' 14 ').
item(15,0, ' 15 ').
% Move - find the current blank space, and the new place and swap them
move_1(1,2).
move_1(2,3).
move_1(3,4).
move(up, X, Y, X, Y1) :- move_1(Y1,Y).
move(down, X, Y, X, Y1) :- move_1(Y, Y1).
move(left, X, Y, X1, Y) :- move_1(X1, X).
move(right, X, Y, X1, Y) :- move_1(X, X1).
move(Dir, Board, [p(X1,Y1,0),p(X,Y,P)|B2]) :-
select(p(X, Y, 0), Board, B1),
move(Dir, X,Y,X1,Y1),
select(p(X1, Y1, P), B1, B2).
% Solved - the game is solved if running through the next_cell sequence produces the item sequence.
solved(Board) :-
select(p(1,1,1),Board,Remaining),
solved(Remaining,p(1,1,1)).
solved([p(4,4,0)], p(_,_,15)).
solved(Board,p(Xp,Yp,Prev)) :-
item(Prev,P,_),
select(p(X,Y,P),Board,Remaining),
next_cell(Xp,Yp,X,Y),
solved(Remaining, p(X,Y,P)).
% Print - run through the next_cell sequence printing the found items.
print(Board) :-
select(p(1,1,P),Board,Remaining),
nl, write_cell(P),
print(Remaining,p(1,1)).
print([],_) :- nl.
print(Board,p(X,Y)) :-
next_cell(X,Y,X1,Y1),
select(p(X1,Y1,P),Board,Remaining),
write_cell(P),
end_line_or_not(X1),
print(Remaining,p(X1,Y1)).
write_cell(0) :- write(' ').
write_cell(P) :- item(P,_,W), write(W).
end_line_or_not(1).
end_line_or_not(2).
end_line_or_not(3).
end_line_or_not(4) :- nl.
% Next Move - get the player input.
next_move_by_player(Move) :-
repeat,
get_single_char(Char),
key_move(Char, Move).
key_move(119, up). % 'w'
key_move(115, down). % 'd'
key_move(97, left). % 'a'
key_move(100, right). % 'd'
% Play - loop over the player moves until solved.
play(Board) :-
solved(Board) -> (
print(Board),
write('You Win!\n'))
; (
print(Board),
next_move_by_player(Move),
move(Move, Board, NewBoard),
play(NewBoard)).
play :-
test_board(Board),
play(Board),
!.
test_board(
[p(1,1,9),p(2,1,1),p(3,1,4),p(4,1,7),
p(1,2,6),p(2,2,5),p(3,2,3),p(4,2,2),
p(1,3,13),p(2,3,10),p(3,3,0),p(4,3,8),
p(1,4,14),p(2,4,15),p(3,4,11),p(4,4,12)]).
</syntaxhighlight>
=={{header|PureBasic}}==
Line 11,479 ⟶ 12,421:
[https://youtu.be/IZqpYctv8Zs CalmoSoft Fifteen Puzzle Game in Ring - video]
=== newer version ===
This was added, out of place, 3rd November 2023, but dated a year earlier than the one last updated 29th September 2021...
<syntaxhighlight lang="ring">
/*
**
** Game : CalmoSoft Fifteen Puzzle Game 3D
** Date : 2017/09/01
** Author : CalmoSoft <calmosoft@gmail.com>, Mahmoud Fayed
**
*/
# Load Libraries
load "gamelib.ring" # RingAllegro Library
load "opengl21lib.ring" # RingOpenGL Library
butSize = 3
texture = list(9)
cube = list(9)
rnd = list(9)
rndok = 0
for n=1 to 9
rnd[n] = 0
next
for n=1 to 9
while true
rndok = 0
ran = random(8) + 1
for nr=1 to 9
if rnd[nr] = ran
rndok = 1
ok
next
if rndok = 0
rnd[n] = ran
exit
ok
end
next
for n=1 to 9
if rnd[n] = 9
empty = n
ok
next
#==============================================================
# To Support MacOS X
al_run_main()
func al_game_start # Called by al_run_main()
main() # Now we call our main function
#==============================================================
func main
new TicTacToe3D {
start()
}
class TicTacToe3D from GameLogic
FPS = 60
TITLE = "CalmoSoft Fifteen Puzzle Game 3D"
oBackground = new GameBackground
oGameSound = new GameSound
oGameCube = new GameCube
oGameInterface = new GameInterface
func loadresources
oGameSound.loadresources()
oBackGround.loadresources()
oGameCube.loadresources()
func drawScene
oBackground.update()
oGameInterface.update(self)
func MouseClickEvent
oGameInterface.MouseClickEvent(self)
class GameInterface
func Update oGame
prepare()
cubes(oGame)
func Prepare
w = 1024 h = 768
ratio = w / h
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(-120,ratio,1,120)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glEnable(GL_TEXTURE_2D)
glShadeModel(GL_SMOOTH)
glClearColor(0.0, 0.0, 0.0, 0.5)
glClearDepth(1.0)
glEnable(GL_DEPTH_TEST)
glEnable(GL_CULL_FACE)
glDepthFunc(GL_LEQUAL)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
func Cubes oGame
oGame.oGameCube {
aGameMap = oGame.aGameMap
cube[1] = cube( 5 , -3 , -5 , texture[rnd[1]] )
cube[2] = cube( 0 , -3 , -5 , texture[rnd[2]] )
cube[3] = cube( -5 , -3 , -5 , texture[rnd[3]] )
cube[4] = cube( 5 , 1 , -5 , texture[rnd[4]] )
cube[5] = cube( 0 , 1 , -5 , texture[rnd[5]] )
cube[6] = cube( -5 , 1 , -5 , texture[rnd[6]] )
cube[7] = cube( 5 , 5 , -5 , texture[rnd[7]] )
cube[8] = cube( 0 , 5 , -5 , texture[rnd[8]] )
cube[9] = cube( -5 , 5 , -5 , texture[rnd[9]] )
rotate()
}
func MouseClickEvent oGame
oGame {
aBtn = Point2Button(Mouse_X,Mouse_Y)
move = 0
nRow = aBtn[1]
nCol = aBtn[2]
tile = (nRow-1)*3 + nCol
up = (empty = (tile - butSize))
down = (empty = (tile + butSize))
left = ((empty = (tile- 1)) and ((tile % butSize) != 1))
right = ((empty = (tile + 1)) and ((tile % butSize) != 0))
move = up or down or left or right
if move = 1
temp = rnd[empty]
rnd[empty] = rnd[tile]
rnd[tile] = temp
empty = tile
oGame.oGameCube {
aGameMap = oGame.aGameMap
cube[1] = cube( 5 , -3 , -5 , texture[rnd[1]] )
cube[2] = cube( 0 , -3 , -5 , texture[rnd[2]] )
cube[3] = cube( -5 , -3 , -5 , texture[rnd[3]] )
cube[4] = cube( 5 , 1 , -5 , texture[rnd[4]] )
cube[5] = cube( 0 , 1 , -5 , texture[rnd[5]] )
cube[6] = cube( -5 , 1 , -5 , texture[rnd[6]] )
cube[7] = cube( 5 , 5 , -5 , texture[rnd[7]] )
cube[8] = cube( 0 , 5 , -5 , texture[rnd[8]] )
cube[9] = cube( -5 , 5 , -5 , texture[rnd[9]] )
rotate()
}
ok
}
Class GameLogic from GraphicsAppBase
aGameMap = [
[ :n , :n , :n ] ,
[ :n , :n , :n ] ,
[ :n , :n , :n ]
]
aGameButtons = [ # x1,y1,x2,y2
[176,88,375,261], # [1,1]
[423,88,591,261], # [1,2]
[645,88,876,261], # [1,3]
[176,282,375,428], # [2,1]
[423,282,591,428], # [2,2]
[645,282,876,428], # [2,3]
[176,454,375,678], # [3,1]
[423,454,591,678], # [3,2]
[645,454,876,678] # [3,3]
]
cActivePlayer = :x
func point2button x,y
nRow = 0
nCol = 0
for t = 1 to len(aGameButtons)
rect = aGameButtons[t]
if x >= rect[1] and x <= rect[3] and
y >= rect[2] and y <= rect[4]
switch t
on 1 nRow = 1 nCol = 1
on 2 nRow = 1 nCol = 2
on 3 nRow = 1 nCol = 3
on 4 nRow = 2 nCol = 1
on 5 nRow = 2 nCol = 2
on 6 nRow = 2 nCol = 3
on 7 nRow = 3 nCol = 1
on 8 nRow = 3 nCol = 2
on 9 nRow = 3 nCol = 3
off
exit
ok
next
return [nRow,nCol]
class GameCube
bitmap bitmap2 bitmap3
textureX textureO textureN
xrot = 0.0
yrot = 0.0
zrot = 0.0
func loadresources
bitmp1 = al_load_bitmap("image/n1.jpg")
texture[1] = al_get_opengl_texture(bitmp1)
bitmp2 = al_load_bitmap("image/n2.jpg")
texture[2] = al_get_opengl_texture(bitmp2)
bitmp3 = al_load_bitmap("image/n3.jpg")
texture[3] = al_get_opengl_texture(bitmp3)
bitmp4 = al_load_bitmap("image/n4.jpg")
texture[4] = al_get_opengl_texture(bitmp4)
bitmp5 = al_load_bitmap("image/n5.jpg")
texture[5] = al_get_opengl_texture(bitmp5)
bitmp6 = al_load_bitmap("image/n6.jpg")
texture[6] = al_get_opengl_texture(bitmp6)
bitmp7 = al_load_bitmap("image/n7.jpg")
texture[7] = al_get_opengl_texture(bitmp7)
bitmp8 = al_load_bitmap("image/n8.jpg")
texture[8] = al_get_opengl_texture(bitmp8)
bitmp9 = al_load_bitmap("image/empty.png")
texture[9] = al_get_opengl_texture(bitmp9)
func cube(x,y,z,nTexture)
glLoadIdentity()
glTranslatef(x,y,z)
glRotatef(xrot,1.0,0.0,0.0)
glRotatef(yrot,0.0,1.0,0.0)
glRotatef(zrot,0.0,0.0,1.0)
setCubeTexture(nTexture)
drawCube()
func setCubeTexture cTexture
glBindTexture(GL_TEXTURE_2D, cTexture)
func Rotate
xrot += 0.3 * 5
yrot += 0.2 * 5
zrot += 0.4 * 5
func drawcube
glBegin(GL_QUADS)
// Front Face
glTexCoord2f(0.0, 0.0) glVertex3f(-1.0, -1.0, 1.0)
glTexCoord2f(1.0, 0.0) glVertex3f( 1.0, -1.0, 1.0)
glTexCoord2f(1.0, 1.0) glVertex3f( 1.0, 1.0, 1.0)
glTexCoord2f(0.0, 1.0) glVertex3f(-1.0, 1.0, 1.0)
// Back Face
glTexCoord2f(1.0, 0.0) glVertex3f(-1.0, -1.0, -1.0)
glTexCoord2f(1.0, 1.0) glVertex3f(-1.0, 1.0, -1.0)
glTexCoord2f(0.0, 1.0) glVertex3f( 1.0, 1.0, -1.0)
glTexCoord2f(0.0, 0.0) glVertex3f( 1.0, -1.0, -1.0)
// Top Face
glTexCoord2f(0.0, 1.0) glVertex3f(-1.0, 1.0, -1.0)
glTexCoord2f(0.0, 0.0) glVertex3f(-1.0, 1.0, 1.0)
glTexCoord2f(1.0, 0.0) glVertex3f( 1.0, 1.0, 1.0)
glTexCoord2f(1.0, 1.0) glVertex3f( 1.0, 1.0, -1.0)
// Bottom Face
glTexCoord2f(1.0, 1.0) glVertex3f(-1.0, -1.0, -1.0)
glTexCoord2f(0.0, 1.0) glVertex3f( 1.0, -1.0, -1.0)
glTexCoord2f(0.0, 0.0) glVertex3f( 1.0, -1.0, 1.0)
glTexCoord2f(1.0, 0.0) glVertex3f(-1.0, -1.0, 1.0)
// Right face
glTexCoord2f(1.0, 0.0) glVertex3f( 1.0, -1.0, -1.0)
glTexCoord2f(1.0, 1.0) glVertex3f( 1.0, 1.0, -1.0)
glTexCoord2f(0.0, 1.0) glVertex3f( 1.0, 1.0, 1.0)
glTexCoord2f(0.0, 0.0) glVertex3f( 1.0, -1.0, 1.0)
// Left Face
glTexCoord2f(0.0, 0.0) glVertex3f(-1.0, -1.0, -1.0)
glTexCoord2f(1.0, 0.0) glVertex3f(-1.0, -1.0, 1.0)
glTexCoord2f(1.0, 1.0) glVertex3f(-1.0, 1.0, 1.0)
glTexCoord2f(0.0, 1.0) glVertex3f(-1.0, 1.0, -1.0)
glEnd()
class GameBackground
nBackX = 0
nBackY = 0
nBackDiffx = -1
nBackDiffy = -1
nBackMotion = 1
aBackMotionList = [
[ -1, -1 ] , # Down - Right
[ 0 , 1 ] , # Up
[ -1, -1 ] , # Down - Right
[ 0 , 1 ] , # Up
[ 1 , -1 ] , # Down - Left
[ 0 , 1 ] , # Up
[ 1 , -1 ] , # Down - Left
[ 0 , 1 ] # Up
]
bitmap
func Update
draw()
motion()
func draw
al_draw_bitmap(bitmap,nBackX,nBackY,1)
func motion
nBackX += nBackDiffx
nBackY += nBackDiffy
if (nBackY = -350) or (nBackY = 0)
nBackMotion++
if nBackMotion > len(aBackMotionList)
nBackMotion = 1
ok
nBackDiffx = aBackMotionList[nBackMotion][1]
nBackDiffy = aBackMotionList[nBackMotion][2]
ok
func loadResources
bitmap = al_load_bitmap("image/back.jpg")
class GameSound
sample sampleid
func loadresources
sample = al_load_sample( "sound/music1.wav" )
sampleid = al_new_allegro_sample_id()
al_play_sample(sample, 1.0, 0.0,1.0,ALLEGRO_PLAYMODE_LOOP,sampleid)
class GraphicsAppBase
display event_queue ev timeout
timer
redraw = true
FPS = 60
SCREEN_W = 1024
SCREEN_H = 700
KEY_UP = 1
KEY_DOWN = 2
KEY_LEFT = 3
KEY_RIGHT = 4
Key = [false,false,false,false]
Mouse_X = 0
Mouse_Y = 0
TITLE = "Graphics Application"
PRINT_MOUSE_XY = False
func start
SetUp()
loadResources()
eventsLoop()
destroy()
func setup
al_init()
al_init_font_addon()
al_init_ttf_addon()
al_init_image_addon()
al_install_audio()
al_init_acodec_addon()
al_reserve_samples(1)
al_set_new_display_flags(ALLEGRO_OPENGL)
display = al_create_display(SCREEN_W,SCREEN_H)
al_set_window_title(display,TITLE)
al_clear_to_color(al_map_rgb(0,0,0))
event_queue = al_create_event_queue()
al_register_event_source(event_queue,
al_get_display_event_source(display))
ev = al_new_allegro_event()
timeout = al_new_allegro_timeout()
al_init_timeout(timeout, 0.06)
timer = al_create_timer(1.0 / FPS)
al_register_event_source(event_queue,
al_get_timer_event_source(timer))
al_start_timer(timer)
al_install_mouse()
al_register_event_source(event_queue,
al_get_mouse_event_source())
al_install_keyboard()
al_register_event_source(event_queue,
al_get_keyboard_event_source())
func eventsLoop
while true
al_wait_for_event_until(event_queue, ev, timeout)
switch al_get_allegro_event_type(ev)
on ALLEGRO_EVENT_DISPLAY_CLOSE
CloseEvent()
on ALLEGRO_EVENT_TIMER
redraw = true
on ALLEGRO_EVENT_MOUSE_AXES
mouse_x = al_get_allegro_event_mouse_x(ev)
mouse_y = al_get_allegro_event_mouse_y(ev)
if PRINT_MOUSE_XY
see "x = " + mouse_x + nl
see "y = " + mouse_y + nl
ok
on ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY
mouse_x = al_get_allegro_event_mouse_x(ev)
mouse_y = al_get_allegro_event_mouse_y(ev)
on ALLEGRO_EVENT_MOUSE_BUTTON_UP
MouseClickEvent()
on ALLEGRO_EVENT_KEY_DOWN
switch al_get_allegro_event_keyboard_keycode(ev)
on ALLEGRO_KEY_UP
key[KEY_UP] = true
on ALLEGRO_KEY_DOWN
key[KEY_DOWN] = true
on ALLEGRO_KEY_LEFT
key[KEY_LEFT] = true
on ALLEGRO_KEY_RIGHT
key[KEY_RIGHT] = true
off
on ALLEGRO_EVENT_KEY_UP
switch al_get_allegro_event_keyboard_keycode(ev)
on ALLEGRO_KEY_UP
key[KEY_UP] = false
on ALLEGRO_KEY_DOWN
key[KEY_DOWN] = false
on ALLEGRO_KEY_LEFT
key[KEY_LEFT] = false
on ALLEGRO_KEY_RIGHT
key[KEY_RIGHT] = false
on ALLEGRO_KEY_ESCAPE
exit
off
off
if redraw and al_is_event_queue_empty(event_queue)
redraw = false
drawScene()
al_flip_display()
ok
callgc()
end
func destroy
al_destroy_timer(timer)
al_destroy_allegro_event(ev)
al_destroy_allegro_timeout(timeout)
al_destroy_event_queue(event_queue)
al_destroy_display(display)
al_exit()
func loadresources
func drawScene
func MouseClickEvent
exit # Exit from the Events Loop
func CloseEvent
exit # Exit from the Events Loop
</syntaxhighlight>
[https://youtu.be/xvhNKTZKi8U CalmoSoft Fifteen Puzzle Game in 3D]
=={{header|Ruby}}==
Line 11,770 ⟶ 13,171:
=={{header|Rust}}==
{{libheader|rand}}
<syntaxhighlight lang="rust">
extern crate rand;
use clearscreen::clear;
use std::collections::HashMap;
use std::fmt;
use std::io::{self, Write};
use rand::seq::SliceRandom;
Line 11,841 ⟶ 13,244:
let pos = board
.iter()
.position(|&cell|
.unwrap();
Line 11,921 ⟶ 13,321:
for turns in 1.. {
println!("{p15}");
match ask_action(&p15.get_moves(), true) {
Action::Move(direction) => {
p15.play(&direction);
}
Action::Quit => {
println!("Bye
break;
}
Line 11,935 ⟶ 13,335:
if p15.is_complete() {
println!("Well done
break;
}
Line 11,941 ⟶ 13,341:
}
fn ask_action(moves: &HashMap<Direction, Cell>, render_list: bool) -> Action {
use Action::*;
use Direction::*;
if render_list {
println!("Possible moves:");
if let Some(&Cell::Card(value)) = moves.get(&Up) {
println!("\tU) {value}");
}
if let Some(&Cell::Card(value)) = moves.get(&Left) {
println!("\tL) {value}");
}
if let Some(&Cell::Card(value)) = moves.get(&Right) {
println!("\tR) {value}");
}
if let Some(&Cell::Card(value)) = moves.get(&Down) {
println!("\tD) {value}");
}
println!("\tQ) Quit");
print!("Choose your move: ");
io::stdout().flush().unwrap();
} else {
print!("Unknown move, try again: ");
io::stdout().flush().unwrap();
}
let mut action = String::new();
Line 11,973 ⟶ 13,377:
"Q" => Quit,
_ => {
ask_action(moves, true)
} else {
ask_action(moves, false)
}
}
}
}
fn unknown_action() -> bool {
use crossterm::{
cursor::MoveToPreviousLine,
terminal::{Clear, ClearType},
ExecutableCommand,
};
std::io::stdout().execute(MoveToPreviousLine(1)).unwrap();
std::io::stdout()
.execute(Clear(ClearType::CurrentLine))
.unwrap();
false
}
</syntaxhighlight>
=={{header|Scala}}==
Line 14,465 ⟶ 15,887:
{{libheader|Wren-ioutil}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="
import "./dynamic" for Enum
import "./ioutil" for Input
import "./fmt" for Fmt
var Move = Enum.create("Move", ["up", "down", "right", "left"])
|