15 puzzle game: Difference between revisions

111,802 bytes added ,  15 days ago
m
Back to previous version, because of better understanding.
m (Back to previous version, because of better understanding.)
Tag: Manual revert
 
(95 intermediate revisions by 28 users not shown)
Line 23:
:*   [[16 Puzzle Game]]
<br><br>
 
=={{header|11l}}==
{{trans|Python: Original, with output}}
 
<syntaxhighlight lang="11l">T Puzzle
position = 0
[Int = String] items
 
F main_frame()
V& d = .items
print(‘+-----+-----+-----+-----+’)
print(‘|#.|#.|#.|#.|’.format(d[1], d[2], d[3], d[4]))
print(‘+-----+-----+-----+-----+’)
print(‘|#.|#.|#.|#.|’.format(d[5], d[6], d[7], d[8]))
print(‘+-----+-----+-----+-----+’)
print(‘|#.|#.|#.|#.|’.format(d[9], d[10], d[11], d[12]))
print(‘+-----+-----+-----+-----+’)
print(‘|#.|#.|#.|#.|’.format(d[13], d[14], d[15], d[16]))
print(‘+-----+-----+-----+-----+’)
 
F format(=ch)
ch = ch.trim(‘ ’)
I ch.len == 1
R ‘ ’ch‘ ’
E I ch.len == 2
R ‘ ’ch‘ ’
E
assert(ch.empty)
R ‘ ’
 
F change(=to)
V fro = .position
L(a, b) .items
I b == .format(String(to))
to = a
L.break
swap(&.items[fro], &.items[to])
.position = to
 
F build_board(difficulty)
L(i) 1..16
.items[i] = .format(String(i))
V tmp = 0
L(a, b) .items
I b == ‘ 16 ’
.items[a] = ‘ ’
tmp = a
L.break
.position = tmp
Int diff
I difficulty == 0
diff = 10
E I difficulty == 1
diff = 50
E
diff = 100
L 0 .< diff
V lst = .valid_moves()
[Int] lst1
L(j) lst
lst1.append(Int(j.trim(‘ ’)))
.change(lst1[random:(lst1.len)])
 
F valid_moves()
V pos = .position
I pos C [6, 7, 10, 11]
R [.items[pos - 4], .items[pos - 1], .items[pos + 1], .items[pos + 4]]
E I pos C [5, 9]
R [.items[pos - 4], .items[pos + 4], .items[pos + 1]]
E I pos C [8, 12]
R [.items[pos - 4], .items[pos + 4], .items[pos - 1]]
E I pos C [2, 3]
R [.items[pos - 1], .items[pos + 1], .items[pos + 4]]
E I pos C [14, 15]
R [.items[pos - 1], .items[pos + 1], .items[pos - 4]]
E I pos == 1
R [.items[pos + 1], .items[pos + 4]]
E I pos == 4
R [.items[pos - 1], .items[pos + 4]]
E I pos == 13
R [.items[pos + 1], .items[pos - 4]]
E
assert(pos == 16)
R [.items[pos - 1], .items[pos - 4]]
 
F game_over()
V flag = 0B
L(a, b) .items
I b != ‘ ’
I a == Int(b.trim(‘ ’))
flag = 1B
E
flag = 0B
R flag
 
V g = Puzzle()
g.build_board(Int(input("Enter the difficulty : 0 1 2\n2 => highest 0 => lowest\n")))
g.main_frame()
print(‘Enter 0 to exit’)
L
print("Hello user:\nTo change the position just enter the no. near it")
V lst = g.valid_moves()
[Int] lst1
L(i) lst
lst1.append(Int(i.trim(‘ ’)))
print(i.trim(‘ ’)" \t", end' ‘’)
print()
V x = Int(input())
I x == 0
L.break
E I x !C lst1
print(‘Wrong move’)
E
g.change(x)
g.main_frame()
I g.game_over()
print(‘You WON’)
L.break</syntaxhighlight>
 
{{out}}
The same as in Python.
 
=={{header|68000 Assembly}}==
This is an entire Sega Genesis game, tested in the Fusion emulator. Thanks to Keith S. of Chibiakumas for the cartridge header, font routines, and printing logic. I programmed the actual game logic. This code can be copied and pasted into a text file and assembled as-is using vasmm68k_mot_win32.exe, no includes or incbins necessary (even the bitmap font is here too.)
 
<syntaxhighlight lang="68000devpac">;15 PUZZLE GAME
;Ram Variables
Cursor_X equ $00FF0000 ;Ram for Cursor Xpos
Cursor_Y equ $00FF0000+1 ;Ram for Cursor Ypos
joypad1 equ $00FF0002
 
GameRam equ $00FF1000 ;Ram for where the pieces are
GameRam_End equ $00FF100F ;the last valid slot in the array
;Video Ports
VDP_data EQU $C00000 ; VDP data, R/W word or longword access only
VDP_ctrl EQU $C00004 ; VDP control, word or longword writes only
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; VECTOR TABLE
;org $00000000
DC.L $00FFFFFE ;SP register value
DC.L ProgramStart ;Start of Program Code
DC.L IntReturn ; bus err
DC.L IntReturn ; addr err
DC.L IntReturn ; illegal inst
DC.L IntReturn ; divzero
DC.L IntReturn ; CHK
DC.L IntReturn ; TRAPV
DC.L IntReturn ; privilege viol
DC.L IntReturn ; TRACE
DC.L IntReturn ; Line A (1010) emulator
DC.L IntReturn ; Line F (1111) emulator
DC.L IntReturn,IntReturn,IntReturn,IntReturn ; Reserved /Coprocessor/Format err/ Uninit Interrupt
DC.L IntReturn,IntReturn,IntReturn,IntReturn,IntReturn,IntReturn,IntReturn,IntReturn
DC.L IntReturn ; spurious interrupt
DC.L IntReturn ; IRQ level 1
DC.L IntReturn ; IRQ level 2 EXT
DC.L IntReturn ; IRQ level 3
DC.L IntReturn ; IRQ level 4 Hsync
DC.L IntReturn ; IRQ level 5
DC.L IntReturn ; IRQ level 6 Vsync
DC.L IntReturn ; IRQ level 7 (NMI)
;org $00000080
;TRAPS
DC.L IntReturn,IntReturn,IntReturn,IntReturn,IntReturn,IntReturn,IntReturn,IntReturn
DC.L IntReturn,IntReturn,IntReturn,IntReturn,IntReturn,IntReturn,IntReturn,IntReturn
;org $000000C0
;FP/MMU
DC.L IntReturn,IntReturn,IntReturn,IntReturn,IntReturn,IntReturn,IntReturn,IntReturn
DC.L IntReturn,IntReturn,IntReturn,IntReturn,IntReturn,IntReturn,IntReturn,IntReturn
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Header
HEADER:
DC.B "SEGA GENESIS " ;System Name MUST TAKE UP 16 BYTES, USE PADDING IF NECESSARY
DC.B "(C)PDS " ;Copyright MUST TAKE UP 8 BYTES, USE PADDING IF NECESSARY
DC.B "2022.JUN" ;Date MUST TAKE UP 8 BYTES, USE PADDING IF NECESSARY
CARTNAME:
DC.B "15 PUZZLE"
CARTNAME_END:
DS.B 48-(CARTNAME_END-CARTNAME) ;ENSURES PROPER SPACING
CARTNAMEALT:
DC.B "15 PUZZLE"
CARTNAMEALT_END:
DS.B 48-(CARTNAMEALT_END-CARTNAMEALT) ;ENSURES PROPER SPACING
gameID:
DC.B "GM PUPPY001-00" ;TT NNNNNNNN-RR T=Type (GM=Game) N=game Num R=Revision
DC.W $0000 ;16-bit Checksum (Address $000200+)
CTRLDATA:
DC.B "J " ;Control Data (J=3button K=Keyboard 6=6button C=cdrom)
;(MUST TAKE UP 16 BYTES, USE PADDING IF NECESSARY)
ROMSTART:
DC.L $00000000 ;ROM Start
ROMLEN:
DC.L $003FFFFF ;ROM Length
RAMSTART:
DC.L $00FF0000
RAMEND:
DC.L $00FFFFFF ;RAM start/end (fixed)
 
DC.B " " ;External RAM Data (MUST TAKE UP 12 BYTES, USE PADDING IF NECESSARY)
DC.B " " ;Modem Data (MUST TAKE UP 12 BYTES, USE PADDING IF NECESSARY)
MEMO:
DC.B " " ;(MUST TAKE UP 40 BYTES, USE PADDING IF NECESSARY)
REGION:
DC.B "JUE " ;Regions Allowed (MUST TAKE UP 16 BYTES, USE PADDING IF NECESSARY)
even
HEADER_END:
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Generic Interrupt Handler
IntReturn:
rte ;immediately return to game
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Program Start
ProgramStart:
;initialize TMSS (TradeMark Security System)
move.b ($A10001),D0 ;A10001 test the hardware version
and.b #$0F,D0
beq NoTmss ;branch if no TMSS chip
move.l #'SEGA',($A14000);A14000 disable TMSS
NoTmss:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Set Up Graphics
 
lea VDPSettings,A5 ;Initialize Screen Registers
move.l #VDPSettingsEnd-VDPSettings,D1 ;length of Settings
move.w (VDP_ctrl),D0 ;C00004 read VDP status (interrupt acknowledge?)
move.l #$00008000,d5 ;VDP Reg command (%8rvv)
NextInitByte:
move.b (A5)+,D5 ;get next video control byte
move.w D5,(VDP_ctrl) ;C00004 send write register command to VDP
; 8RVV - R=Reg V=Value
add.w #$0100,D5 ;point to next VDP register
dbra D1,NextInitByte ;loop for rest of block
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Set up palette
;Define palette
move.l #$C0000000,d0 ;Color 0 (background)
move.l d0,VDP_Ctrl
; ----BBB-GGG-RRR-
move.w #%0000011000000000,VDP_data
move.l #$C01E0000,d0 ;Color 15 (Font)
move.l d0,VDP_Ctrl
move.w #%0000000011101110,VDP_data
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Set up Font
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
; FONT IS 1BPP, THIS ROUTINE CONVERTS IT TO A 4BPP FORMAT.
lea Font,A1 ;Font Address in ROM
move.l #Font_End-Font,d6 ;Our font contains 96 letters 8 lines each
move.l #$40000000,(VDP_Ctrl);Start writes to VRAM address $0000
NextFont:
move.b (A1)+,d0 ;Get byte from font
moveq.l #7,d5 ;Bit Count (8 bits)
clr.l d1 ;Reset BuildUp Byte
Font_NextBit: ;1 color per nibble = 4 bytes
 
rol.l #3,d1 ;Shift BuildUp 3 bits left
roxl.b #1,d0 ;Shift a Bit from the 1bpp font into the Pattern
roxl.l #1,d1 ;Shift bit into BuildUp
dbra D5,Font_NextBit ;Next Bit from Font
move.l d1,d0 ; Make fontfrom Color 1 to color 15
rol.l #1,d1 ;Bit 1
or.l d0,d1
rol.l #1,d1 ;Bit 2
or.l d0,d1
rol.l #1,d1 ;Bit 3
or.l d0,d1
move.l d1,(VDP_Data);Write next Long of char (one line) to VDP
dbra d6,NextFont ;Loop until done
 
 
clr.b Cursor_X ;Clear Cursor XY
clr.b Cursor_Y
;Turn on screen
move.w #$8144,(VDP_Ctrl);C00004 reg 1 = 0x44 unblank display
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; all of the above was just the prep work to boot the Sega Genesis, and had nothing to do with a 15 Puzzle.
; That's hardware for you!
 
LEA GameRam,A0
;load the initial state of the puzzle. There is no randomization here unfortunately, as creating a sufficient pseudo-RNG
;to make the game "believable" is more difficult than programming the game itself!
;so instead we'll start in such a manner that the player has to do quite a bit of work to win.
MOVE.B #'F',(A0)+
MOVE.B #'E',(A0)+
MOVE.B #'D',(A0)+
MOVE.B #'C',(A0)+
MOVE.B #'B',(A0)+
MOVE.B #'A',(A0)+
MOVE.B #'9',(A0)+
MOVE.B #'8',(A0)+
MOVE.B #'7',(A0)+
MOVE.B #'6',(A0)+
MOVE.B #'5',(A0)+
MOVE.B #'4',(A0)+
MOVE.B #'3',(A0)+
MOVE.B #'2',(A0)+
MOVE.B #'1',(A0)+
MOVE.B #' ',(A0)+
 
;puzzle will look like:
;FEDC
;BA98
;7654
;321
 
main:
JSR Player_ReadControlsDual ;get controller input
move.w d0,(joypad1)
 
 
;adjust the number of these as you see fit.
;this affects the game's overall speed.
JSR waitVBlank
JSR waitVBlank
JSR waitVBlank
JSR waitVBlank
JSR waitVBlank
JSR waitVBlank
JSR waitVBlank
JSR waitVBlank
JSR waitVBlank
JSR waitVBlank
 
;find where the blank space is among GameRAM
LEA GameRAM,a0
MOVE.B #' ',D0
JSR REPNE_SCASB
MOVE.L A0,A1
;;;;;;;;;;;;;;;;;;; check controller presses
JOYPAD_BITFLAG_M equ 2048
JOYPAD_BITFLAG_Z equ 1024
JOYPAD_BITFLAG_Y equ 512
JOYPAD_BITFLAG_X equ 256
JOYPAD_BITFLAG_S equ 128
JOYPAD_BITFLAG_C equ 64
JOYPAD_BITFLAG_B equ 32
JOYPAD_BITFLAG_A equ 16
JOYPAD_BITFLAG_R equ 8
JOYPAD_BITFLAG_L equ 4
JOYPAD_BITFLAG_D equ 2
JOYPAD_BITFLAG_U equ 1
 
JOYPAD_BITNUM_M equ 11
JOYPAD_BITNUM_Z equ 10
JOYPAD_BITNUM_Y equ 9
JOYPAD_BITNUM_X equ 8
JOYPAD_BITNUM_S equ 7
JOYPAD_BITNUM_C equ 6
JOYPAD_BITNUM_B equ 5
JOYPAD_BITNUM_A equ 4
JOYPAD_BITNUM_R equ 3
JOYPAD_BITNUM_L equ 2
JOYPAD_BITNUM_D equ 1
JOYPAD_BITNUM_U equ 0
 
 
 
 
move.w (joypad1),D0
 
BTST #JOYPAD_BITNUM_U,D0
BNE JoyNotUp
MOVEM.L D0/A1,-(SP)
ADDA.L #4,A1
CMPA.L #GameRam_End,A1
BHI .doNothing
;OTHERWISE SWAP THE EMPTY SPACE WITH THE BYTE BELOW IT.
MOVE.B (A1),D7
MOVE.B (A0),(A1)
MOVE.B D7,(A0)
.doNothing
MOVEM.L (SP)+,D0/A1
bra vdraw
JoyNotUp:
BTST #JOYPAD_BITNUM_D,D0
BNE JoyNotDown
MOVEM.L D0/A1,-(SP)
 
SUBA.L #4,A1 ;CHECK ONE ROW ABOVE WHERE WE ARE
CMPA.L #GameRam,A1
BCS .doNothing ;if A1-4 IS BELOW THE START OF GAME RAM, DON'T MOVE
;OTHERWISE SWAP THE EMPTY SPACE WITH THE BYTE ABOVE IT.
MOVE.B (A1),D7
MOVE.B (A0),(A1)
MOVE.B D7,(A0)
.doNothing:
MOVEM.L (SP)+,D0/A1
bra vdraw
JoyNotDown:
BTST #JOYPAD_BITNUM_L,D0
BNE JoyNotLeft
MOVEM.L D0/A1,-(SP)
ADDA.L #1,A1
MOVE.L A1,D4
MOVE.L A0,D3
AND.L #3,D4
AND.L #3,D3
CMP.L D3,D4
BCS .doNothing
;OTHERWISE SWAP THE EMPTY SPACE WITH THE BYTE TO THE LEFT
MOVE.B (A1),D7
MOVE.B (A0),(A1)
MOVE.B D7,(A0)
.doNothing:
MOVEM.L (SP)+,D0/A1
bra vdraw
JoyNotLeft:
BTST #JOYPAD_BITNUM_R,D0
BNE JoyNotRight
MOVEM.L D0/A1,-(SP)
SUBA.L #1,A1
MOVE.L A1,D4
MOVE.L A0,D3
AND.L #3,D4
AND.L #3,D3
CMP.L D3,D4
BHI .doNothing
;OTHERWISE SWAP THE EMPTY SPACE WITH THE BYTE TO THE RIGHT
MOVE.B (A1),D7
MOVE.B (A0),(A1)
MOVE.B D7,(A0)
.doNothing:
MOVEM.L (SP)+,D0/A1
bra vdraw
JoyNotRight:
 
vdraw:
;this actually draws the current state of the puzzle to the screen.
LEA GameRam,A0
CLR.B (Cursor_X) ;reset text cursors to top left of screen
CLR.B (Cursor_Y)
;draw the puzzle
 
;anything insize a REPT N...ENDR block is in-lined N times, back to back.
rept 4
 
MOVE.B (A0)+,D0
JSR PrintChar
 
MOVE.B (A0)+,D0
JSR PrintChar
 
MOVE.B (A0)+,D0
JSR PrintChar
 
MOVE.B (A0)+,D0
JSR PrintChar ;we just finished drawing one row of the puzzle. Now, begin a new line and continue drawing.
 
jsr newline
endr
checkIfWin:
;YES THIS IS MESSY, I TRIED IT WITH A LOOP BUT IT WOULDN'T WORK SO I JUST UNROLLED THE LOOP.
LEA GameRam,a4
MOVE.B (A4)+,D5
CMP.B #'1',D5
BNE .keepGoing
 
MOVE.B (A4)+,D5
CMP.B #'2',D5
BNE .keepGoing
 
MOVE.B (A4)+,D5
CMP.B #'3',D5
BNE .keepGoing
 
MOVE.B (A4)+,D5
CMP.B #'4',D5
BNE .keepGoing
 
MOVE.B (A4)+,D5
CMP.B #'5',D5
BNE .keepGoing
 
MOVE.B (A4)+,D5
CMP.B #'6',D5
BNE .keepGoing
 
MOVE.B (A4)+,D5
CMP.B #'7',D5
BNE .keepGoing
 
MOVE.B (A4)+,D5
CMP.B #'8',D5
BNE .keepGoing
 
MOVE.B (A4)+,D5
CMP.B #'9',D5
BNE .keepGoing
 
MOVE.B (A4)+,D5
CMP.B #'A',D5
BNE .keepGoing
 
MOVE.B (A4)+,D5
CMP.B #'B',D5
BNE .keepGoing
 
MOVE.B (A4)+,D5
CMP.B #'C',D5
BNE .keepGoing
 
MOVE.B (A4)+,D5
CMP.B #'D',D5
BNE .keepGoing
 
MOVE.B (A4)+,D5
CMP.B #'E',D5
BNE .keepGoing
 
MOVE.B (A4)+,D5
CMP.B #'F',D5
BNE .keepGoing
 
MOVE.B (A4)+,D5
CMP.B #' ',D5
BNE .keepGoing
clr.b (Cursor_X)
move.b #7,(Cursor_Y)
LEA victoryMessage,a3
jsr PrintString
jmp * ;game freezes after you win.
 
.keepGoing:
;it's unlikely that the label "main" is in range of here so I didn't bother checking and just assumed it was out of range.
;Otherwise I would have said "BEQ main" instead of BNE .keepGoing
jmp main
 
VictoryMessage:
DC.B "A WINNER IS YOU",255
EVEN
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
REPNE_SCASB:
;INPUT:
;A0 = POINTER TO START OF MEMORY
;D0 = THE BYTE TO SEARCH FOR
;OUTPUT = A0 POINTS TO THE BYTE THAT CONTAINED D0
MOVE.B (A0),D1
CMP.B D0,D1
BEQ .done
ADDA.L #1,A0
BRA REPNE_SCASB
.done:
RTS
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 
 
Player_ReadControlsDual:
move.b #%01000000,($A1000B) ; Set direction IOIIIIII (I=In O=Out)
move.l #$A10003,a0 ;RW port for player 1
 
move.b #$40,(a0) ; TH = 1
nop ;Delay
nop
move.b (a0),d2 ; d0.b = --CBRLDU Store in D2
move.b #$0,(a0) ; TH = 0
nop ;Delay
nop
move.b (a0),d1 ; d1.b = --SA--DU Store in D1
move.b #$40,(a0) ; TH = 1
nop ;Delay
nop
move.b #$0,(a0) ; TH = 0
nop ;Delay
nop
move.b #$40,(a0) ; TH = 1
nop ;Delay
nop
move.b (a0),d3 ; d1.b = --CBXYZM Store in D3
move.b #$0,(a0) ; TH = 0
clr.l d0 ;Clear buildup byte
roxr.b d2
roxr.b d0 ;U
roxr.b d2
roxr.b d0 ;D
roxr.b d2
roxr.b d0 ;L
roxr.b d2
roxr.b d0 ;R
roxr.b #5,d1
roxr.b d0 ;A
roxr.b d2
roxr.b d0 ;B
roxr.b d2
roxr.b d0 ;C
roxr.b d1
roxr.b d0 ;S
move.l d3,d1
roxl.l #7,d1 ;XYZ
and.l #%0000011100000000,d1
or.l d1,d0
move.l d3,d1
roxl.l #8,d1 ;M
roxl.l #3,d1
and.l #%0000100000000000,d1
or.l d1,d0
or.l #$FFFFF000,d0 ;Set unused bits to 1
 
;this returns player 1's buttons into D0 as the following:
;----MZYXSCBARLDU
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
waitVBlank: ;Bit 3 defines if we're in Vblank
MOVE.L d0,-(sp)
.wait:
move.w VDP_ctrl,d0
and.w #%0000000000001000,d0 ;See if vblank is running
bne .wait ;wait until it is
waitVBlank2:
move.w VDP_ctrl,d0
and.w #%0000000000001000,d0 ;See if vblank is running
beq waitVBlank2 ;wait until it isnt
MOVE.L (SP)+,d0
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PrintChar: ;Show D0 to screen
moveM.l d0-d7/a0-a7,-(sp)
and.l #$FF,d0 ;Keep only 1 byte
sub #32,d0 ;No Characters in our font below 32
PrintCharAlt:
Move.L #$40000003,d5 ;top 4=write, bottom $3=Cxxx range
clr.l d4 ;Tilemap at $C000+
 
Move.B (Cursor_Y),D4
rol.L #8,D4 ;move $-FFF to $-FFF----
rol.L #8,D4
rol.L #7,D4 ;2 bytes per tile * 64 tiles per line
add.L D4,D5 ;add $4------3
Move.B (Cursor_X),D4
rol.L #8,D4 ;move $-FFF to $-FFF----
rol.L #8,D4
rol.L #1,D4 ;2 bytes per tile
add.L D4,D5 ;add $4------3
MOVE.L D5,(VDP_ctrl) ; C00004 write next character to VDP
MOVE.W D0,(VDP_data) ; C00000 store next word of name data
 
addq.b #1,(Cursor_X) ;INC Xpos
move.b (Cursor_X),d0
cmp.b #39,d0
bls nextpixel_Xok
jsr NewLine ;If we're at end of line, start newline
nextpixel_Xok:
moveM.l (sp)+,d0-d7/a0-a7
rts
PrintString:
move.b (a3)+,d0 ;Read a character in from A3
cmp.b #255,d0
beq PrintString_Done ;return on 255
jsr PrintChar ;Print the Character
bra PrintString
PrintString_Done:
rts
NewLine:
addq.b #1,(Cursor_Y) ;INC Y
clr.b (Cursor_X) ;Zero X
rts
Font:
;1bpp font - 8x8 96 characters
;looks just like your typical "8-bit" font. You'll just have to take my word for it.
DC.B $00,$00,$00,$00,$00,$00,$00,$00,$18,$3c,$3c,$18,$18,$00,$18,$18
DC.B $36,$36,$12,$24,$00,$00,$00,$00,$00,$12,$7f,$24,$24,$fe,$48,$00
DC.B $00,$04,$1e,$28,$1c,$0a,$3c,$10,$00,$62,$64,$08,$10,$26,$46,$00
DC.B $00,$18,$24,$20,$12,$2c,$44,$3a,$18,$18,$08,$10,$00,$00,$00,$00
DC.B $08,$10,$20,$20,$20,$20,$10,$08,$10,$08,$04,$04,$04,$04,$08,$10
DC.B $00,$10,$38,$10,$28,$00,$00,$00,$00,$00,$10,$10,$7c,$10,$10,$00
DC.B $00,$00,$00,$00,$0c,$0c,$04,$08,$00,$00,$00,$00,$7e,$00,$00,$00
DC.B $00,$00,$00,$00,$00,$18,$18,$00,$01,$02,$04,$08,$10,$20,$40,$00
DC.B $1c,$26,$63,$63,$63,$32,$1c,$00,$0c,$1c,$0c,$0c,$0c,$0c,$3f,$00
DC.B $3e,$63,$07,$1e,$3c,$70,$7f,$00,$3f,$06,$0c,$1e,$03,$63,$3e,$00
DC.B $0e,$1e,$36,$66,$7f,$06,$06,$00,$7e,$60,$7e,$03,$03,$63,$3e,$00
DC.B $1e,$30,$60,$7e,$63,$63,$3e,$00,$7f,$63,$06,$0c,$18,$18,$18,$00
DC.B $3c,$62,$72,$3c,$4f,$43,$3e,$00,$3e,$63,$63,$3f,$03,$06,$3c,$00
DC.B $00,$18,$18,$00,$18,$18,$00,$00,$00,$0c,$0c,$00,$0c,$0c,$04,$08
DC.B $00,$00,$06,$18,$60,$18,$06,$00,$00,$00,$00,$7e,$00,$7e,$00,$00
DC.B $00,$00,$60,$18,$06,$18,$60,$00,$1c,$36,$36,$06,$0c,$00,$0c,$0c
DC.B $3c,$42,$99,$a1,$a1,$99,$42,$3c,$1c,$36,$63,$63,$7f,$63,$63,$00
DC.B $7e,$63,$63,$7e,$63,$63,$7e,$00,$1e,$33,$60,$60,$60,$33,$1e,$00
DC.B $7c,$66,$63,$63,$63,$66,$7c,$00,$3f,$30,$30,$3e,$30,$30,$3f,$00
DC.B $7f,$60,$60,$7e,$60,$60,$60,$00,$1f,$30,$60,$67,$63,$33,$1f,$00
DC.B $63,$63,$63,$7f,$63,$63,$63,$00,$3f,$0c,$0c,$0c,$0c,$0c,$3f,$00
DC.B $03,$03,$03,$03,$03,$63,$3e,$00,$63,$66,$6c,$78,$7c,$6e,$67,$00
DC.B $30,$30,$30,$30,$30,$30,$3f,$00,$63,$77,$7f,$7f,$6b,$63,$63,$00
DC.B $63,$73,$7b,$7f,$6f,$67,$63,$00,$3e,$63,$63,$63,$63,$63,$3e,$00
DC.B $7e,$63,$63,$63,$7e,$60,$60,$00,$3e,$63,$63,$63,$6f,$66,$3d,$00
DC.B $7e,$63,$63,$67,$7c,$6e,$67,$00,$3c,$66,$60,$3e,$03,$63,$3e,$00
DC.B $3f,$0c,$0c,$0c,$0c,$0c,$0c,$00,$63,$63,$63,$63,$63,$63,$3e,$00
DC.B $63,$63,$63,$77,$3e,$1c,$08,$00,$63,$63,$6b,$7f,$7f,$77,$63,$00
DC.B $63,$77,$3e,$1c,$3e,$77,$63,$00,$33,$33,$33,$1e,$0c,$0c,$0c,$00
DC.B $7f,$07,$0e,$1c,$38,$70,$7f,$00,$00,$38,$20,$20,$20,$20,$38,$00
DC.B $80,$40,$20,$10,$08,$04,$02,$00,$00,$1c,$04,$04,$04,$04,$1c,$00
DC.B $10,$28,$44,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$7e,$00
DC.B $00,$20,$10,$00,$00,$00,$00,$00,$00,$18,$04,$1c,$24,$2c,$1c,$00
DC.B $00,$20,$20,$38,$24,$24,$38,$00,$00,$00,$1c,$20,$20,$20,$1c,$00
DC.B $00,$04,$04,$1c,$24,$24,$1c,$00,$00,$00,$1c,$24,$3c,$20,$1c,$00
DC.B $00,$18,$24,$20,$30,$20,$20,$00,$00,$1c,$24,$24,$1c,$04,$3c,$00
DC.B $00,$20,$20,$38,$24,$24,$24,$00,$00,$10,$00,$10,$10,$10,$10,$00
DC.B $08,$00,$08,$08,$08,$08,$28,$10,$20,$20,$24,$28,$30,$28,$24,$00
DC.B $10,$10,$10,$10,$10,$10,$18,$00,$00,$00,$40,$68,$54,$54,$54,$00
DC.B $00,$00,$28,$34,$24,$24,$24,$00,$00,$00,$1c,$22,$22,$22,$1c,$00
DC.B $00,$00,$38,$24,$24,$38,$20,$20,$00,$00,$1c,$24,$24,$1c,$04,$04
DC.B $00,$00,$2c,$30,$20,$20,$20,$00,$00,$00,$1c,$20,$1c,$02,$3c,$00
DC.B $00,$10,$3c,$10,$10,$14,$08,$00,$00,$00,$24,$24,$24,$24,$1a,$00
DC.B $00,$00,$24,$24,$24,$14,$18,$00,$00,$00,$92,$92,$92,$5a,$6c,$00
DC.B $00,$00,$22,$14,$08,$14,$22,$00,$00,$00,$24,$24,$1c,$04,$18,$00
DC.B $00,$00,$3c,$04,$18,$20,$3c,$00,$00,$08,$10,$10,$20,$10,$10,$08
DC.B $18,$18,$18,$18,$18,$18,$18,$18,$00,$10,$08,$08,$04,$08,$08,$10
DC.B $00,$00,$00,$30,$4a,$04,$00,$00,$1c,$7f,$00,$7f,$55,$55,$55,$00
Font_End:
 
VDPSettings:
DC.B $04 ; 0 mode register 1 ---H-1M-
DC.B $04 ; 1 mode register 2 -DVdP---
DC.B $30 ; 2 name table base for scroll A (A=top 3 bits) --AAA--- = $C000
DC.B $3C ; 3 name table base for window (A=top 4 bits / 5 in H40 Mode) --AAAAA- = $F000
DC.B $07 ; 4 name table base for scroll B (A=top 3 bits) -----AAA = $E000
DC.B $6C ; 5 sprite attribute table base (A=top 7 bits / 6 in H40) -AAAAAAA = $D800
DC.B $00 ; 6 unused register --------
DC.B $00 ; 7 background color (P=Palette C=Color) --PPCCCC
DC.B $00 ; 8 unused register --------
DC.B $00 ; 9 unused register --------
DC.B $FF ;10 H interrupt register (L=Number of lines) LLLLLLLL
DC.B $00 ;11 mode register 3 ----IVHL
DC.B $81 ;12 mode register 4 (C bits both1 = H40 Cell) C---SIIC
DC.B $37 ;13 H scroll table base (A=Top 6 bits) --AAAAAA = $FC00
DC.B $00 ;14 unused register --------
DC.B $02 ;15 auto increment (After each Read/Write) NNNNNNNN
DC.B $01 ;16 scroll size (Horiz & Vert size of ScrollA & B) --VV--HH = 64x32 tiles
DC.B $00 ;17 window H position (D=Direction C=Cells) D--CCCCC
DC.B $00 ;18 window V position (D=Direction C=Cells) D--CCCCC
DC.B $FF ;19 DMA length count low LLLLLLLL
DC.B $FF ;20 DMA length count high HHHHHHHH
DC.B $00 ;21 DMA source address low LLLLLLLL
DC.B $00 ;22 DMA source address mid MMMMMMMM
DC.B $80 ;23 DMA source address high (C=CMD) CCHHHHHH
VDPSettingsEnd:
even</syntaxhighlight>
 
{{out}}[https://ibb.co/4MZpL4W Screenshot of emulator]
 
=={{header|AArch64 Assembly}}==
{{works with|as|Raspberry Pi 3B version Buster 64 bits}}
<syntaxhighlight lang="aarch64 assembly">
<lang AArch64 Assembly>
/* ARM assembly AARCH64 Raspberry PI 3B */
/* program puzzle15_64.s */
Line 647 ⟶ 1,431:
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"
</syntaxhighlight>
</lang>
 
=={{header|Action!}}==
<syntaxhighlight lang="action!">DEFINE BOARDSIZE="16"
DEFINE X0="13"
DEFINE Y0="6"
DEFINE ITEMW="3"
DEFINE ITEMH="2"
 
BYTE ARRAY board(BOARDSIZE)
BYTE emptyX,emptyY,solved,first=[1]
 
BYTE FUNC Index(BYTE x,y)
RETURN (x+y*4)
 
PROC UpdateItem(BYTE x,y)
BYTE item
 
Position(X0+x*ITEMW+1,Y0+y*ITEMH+1)
item=board(Index(x,y))
IF item=0 THEN
Print(" ")
ELSEIF item<10 THEN
Put(160) Put(item+176)
ELSE
Put(item/10+176)
Put(item MOD 10+176)
FI
RETURN
 
PROC UpdateBoard()
BYTE x,y
 
FOR y=0 TO 3
DO
FOR x=0 TO 3
DO
UpdateItem(x,y)
OD
OD
RETURN
 
PROC DrawGrid()
CHAR ARRAY
top=[13 17 18 18 23 18 18 23 18 18 23 18 18 5],
row=[13 124 32 32 124 32 32 124 32 32 124 32 32 124],
mid=[13 1 18 18 19 18 18 19 18 18 19 18 18 4],
bot=[13 26 18 18 24 18 18 24 18 18 24 18 18 3]
BYTE y,i
 
y=Y0
Position(X0,y) Print(top) y==+1
Position(X0,y) Print(row) y==+1
FOR i=0 TO 2
DO
Position(X0,y) Print(mid) y==+1
Position(X0,y) Print(row) y==+1
OD
Position(X0,y) Print(bot)
RETURN
 
PROC DrawBoard()
DrawGrid()
UpdateBoard()
RETURN
 
PROC FindEmpty()
BYTE i
 
FOR i=0 TO BOARDSIZE-1
DO
IF board(i)=0 THEN
emptyX=i MOD 4
emptyY=i/4
FI
OD
RETURN
 
PROC Wait(BYTE frames)
BYTE RTCLOK=$14
frames==+RTCLOK
WHILE frames#RTCLOK DO OD
RETURN
 
PROC UpdateStatus()
Position(9,3) Print("Game status: ")
IF solved THEN
Print("SOLVED !")
IF first=0 THEN
Sound(0,100,10,5) Wait(5)
Sound(0,60,10,5) Wait(5)
Sound(0,40,10,5) Wait(5)
Sound(0,0,0,0)
FI
first=0
ELSE
Print("Shuffled")
FI
RETURN
 
PROC InitBoard()
BYTE i
FOR i=1 TO BOARDSIZE
DO
board(i-1)=i MOD 16
OD
FindEmpty()
solved=1
UpdateStatus()
RETURN
 
BYTE FUNC IsSolved()
BYTE i
 
FOR i=1 TO BOARDSIZE
DO
IF board(i-1)#i MOD 16 THEN
RETURN (0)
FI
OD
RETURN (1)
 
PROC CheckStatus()
BYTE tmp
 
tmp=IsSolved()
IF solved#tmp THEN
solved=tmp
UpdateStatus()
FI
RETURN
 
PROC Swap(BYTE x1,y1,x2,y2)
BYTE tmp,i1,i2
 
i1=Index(x1,y1)
i2=Index(x2,y2)
tmp=board(i1)
board(i1)=board(i2)
board(i2)=tmp
UpdateItem(x1,y1)
UpdateItem(x2,y2)
CheckStatus()
RETURN
 
PROC Shuffle()
BYTE i,j,tmp
 
i=BOARDSIZE-1
WHILE i>0
DO
j=Rand(i)
tmp=board(i)
board(i)=board(j)
board(j)=tmp
i==-1
OD
FindEmpty()
UpdateBoard()
CheckStatus()
RETURN
 
PROC MoveLeft()
IF emptyX=0 THEN RETURN FI
Swap(emptyX,emptyY,emptyX-1,emptyY)
emptyX==-1
RETURN
 
PROC MoveRight()
IF emptyX=3 THEN RETURN FI
Swap(emptyX,emptyY,emptyX+1,emptyY)
emptyX==+1
RETURN
 
PROC MoveUp()
IF emptyY=0 THEN RETURN FI
Swap(emptyX,emptyY,emptyX,emptyY-1)
emptyY==-1
RETURN
 
PROC MoveDown()
IF emptyY=3 THEN RETURN FI
Swap(emptyX,emptyY,emptyX,emptyY+1)
emptyY==+1
RETURN
 
PROC Main()
BYTE k,lastStick=[255],currStick,
CH=$02FC, ;Internal hardware value for last key pressed
CRSINH=$02F0 ;Controls visibility of cursor
 
Graphics(0)
SetColor(2,0,2)
CRSINH=1 ;hide cursor
Position(10,18) Print("Joystick - move tiles")
Position(9,19) Print("Space bar - shuffle")
Position(15,20) Print("ESC - exit")
InitBoard()
DrawBoard()
DO
currStick=Stick(0)
IF currStick#lastStick THEN
IF currStick=11 THEN MoveRight()
ELSEIF currStick=7 THEN MoveLeft()
ELSEIF currStick=13 THEN MoveUp()
ELSEIF currStick=14 THEN MoveDown()
FI
FI
lastStick=currStick
k=CH
IF k#$FF THEN CH=$FF FI
IF k=33 THEN Shuffle()
ELSEIF k=28 THEN EXIT
FI
OD
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/15_puzzle_game.png Screenshot from Atari 8-bit computer]
 
=={{header|Ada}}==
Line 653 ⟶ 1,655:
We fist define a generic package Generic_Puzzle. Upon instantiation, it can take any number of rows, any number of columns for a rows*columns-1 game. Instead of plain numbers, the tiles on the board can have arbitrary names (but they should all be of the same length). The package user can request the name for the tile at a certain (row,column)-point, and the set of possible moves. The user can move the empty space up, down, left and right (if possible). If the user makes the attempt to perform an impossible move, a Constraint_Error is raised.
 
<langsyntaxhighlight Adalang="ada">generic
Rows, Cols: Positive;
with function Name(N: Natural) return String; -- with Pre => (N < Rows*Cols);
Line 668 ⟶ 1,670:
procedure Move(The_Move: Moves);
 
end Generic_Puzzle;</langsyntaxhighlight>
 
The package implementation is as follows.
 
<langsyntaxhighlight Adalang="ada">package body Generic_Puzzle is
Field: array(Row_Type, Col_Type) of Natural;
Line 728 ⟶ 1,730:
end loop;
end;
end Generic_Puzzle;</langsyntaxhighlight>
 
The main program reads the level from the command line. A larger level implies a more difficult instance. The default level is 10, which is fairly simple. After randomizing the board, the user can move the tiles.
 
<langsyntaxhighlight Adalang="ada">with Generic_Puzzle, Ada.Text_IO,
Ada.Numerics.Discrete_Random, Ada.Command_Line;
 
Line 803 ⟶ 1,805:
end;
end loop;
end Puzzle_15;</langsyntaxhighlight>
 
{{out}}
Line 845 ⟶ 1,847:
4 moves!</pre>
 
For other puzzles, one must just the single line with the package instantiation. E.g., for an 8-puzzle, we would write the following. <langsyntaxhighlight Adalang="ada"> package Puzzle is new Generic_Puzzle(Rows => 3, Cols => 3, Name => Image);</langsyntaxhighlight>
 
=={{header|Amazing Hopper}}==
<syntaxhighlight lang="Amazing Hopper">
#include <jambo.h>
 
#define FILATABLA 5
#define COLUMNATABLA 10
#define Imprimelamatriz Gosub 'Pone la matriz'
#define Imprimelascasillas Gosub 'Pone las casillas'
#define Imprimeelíndiceen(_X_,_Y_) Set '_X_,_Y_', Gosub 'Pone el índice'
 
Main
Set break
 
Void (casilla, índice, números)
Link gosub( Crea una casilla, Crea el índice, Crea la matriz de números )
Cls
x=4, y=4, Tok sep '""', Gosub 'Imprime escenario'
/* INICIA EL JUEGO */
SW = 1, GANADOR = 0
c=0, cero x=4, cero y=4
Loop
Let ( c:=Getch )
Switch ( c )
Case 'KRIGHT' { #( y < 4 ) do{ ++y }, Exit }
Case 'KDOWN' { #( x < 4 ) do{ ++x }, Exit }
Case 'KLEFT' { #( y > 1 ) do{ --y }, Exit }
Case 'KUP' { #( x > 1 ) do{ --x }, Exit }
Case 'KRETURN' { If ( Gosub 'Chequear si movimiento es válido' )
Gosub 'Mover las casillas'
End If
Exit
}
Case 'KESCAPE' { SW=0 }
End switch
Gosub 'Imprime escenario'
Break if ( Gosub 'Verificar puzzle resuelto' --- Backup to 'GANADOR' )
Back if 'SW' is not zero
 
/* FIN DEL JUEGO */
If ( GANADOR )
Locate (18,15), Printnl("LO RESOLVISTE!")
End If
Locate (19,1), Prnl
End
 
Subrutines
 
/* CHEQUEO DE MOVIMIENTO */
 
Define ( Verificar puzzle resuelto )
ret = 0
Clr all marks
Tnúmeros=números
Redim (Tnúmeros,0), N = 0, Let ( N := Length(Tnúmeros) Minus (1))
i=1
Iterator ( ++i, Less equal ( i, N ) And( Not(ret) ), \
Let ( ret := Bit xor(i, [i] Get 'Tnúmeros') ) )
Clr all marks
Clear 'Tnúmeros'
 
Return 'Not (ret); And( Equals(i, Plus one(N)) ) '
 
Define ( Chequear si movimiento es válido )
Return 'Only one ( Equals (x, cero x), Equals(y, cero y ) )'
 
Define ( Mover las casillas )
If ( Equals (y, cero y) )
If ( Less (x, cero x) ) // mueve hacia abajo
Loop for ( i = cero x, #( i >= x ) , --i )
If ( Greater ( i, 1 ) )
[{i} Minus(1), y] Get 'números', [i,y] Put 'números'
Else
[{i} Plus(1), y] Get 'números', [i,y] Put 'números'
End If
Next
Else // por defecto: mueve hacia arriba
Loop for ( i = cero x, #( i <= x ) , ++i )
If ( Less ( i, 4 ) )
[{i} Plus(1), y] Get 'números', [i,y] Put 'números'
Else
[i,y] Get 'números', [{i} Minus(1),y] Put 'números'
End If
Next
End If
[x,y] Set '0', Put 'números'
Set 'x', Move to 'cero x'
Else // por defecto: está en la misma fila
If ( Less ( y, cero y ) ) // mueve hacia la derecha
Loop for ( i = cero y, #( i >= y ) , --i )
If ( Greater ( i, 1) )
[x, {i} Minus(1)] Get 'números', [x,i] Put 'números'
Else
[x, y] Get 'números', [x, {i} Plus(1)] Put 'números'
End If
Next
Else // por defecto: mueve hacia la izquierda
Loop for ( i = cero y, #( i <= y ) , ++i )
If ( Less ( i, 4 ) )
[x, {i} Plus(1)] Get 'números', [x,i] Put 'números'
Else
[x,i] Get 'números', [x,{i} Minus(1)] Put 'números'
End If
Next
End If
[x,y] Set '0', Put 'números'
Set 'y', Move to 'cero y'
End If
Clr all marks
Return
 
/* DESPLIEGUE DE CUADRITOS Y NUMEROS */
 
Define ( Imprime escenario )
Imprime las casillas
Imprime el índice en 'x,y'
Imprime la matriz
Return
 
Define ( Pone la matriz )
i=4, col = COLUMNA TABLA, celda=""
Clr all marks
py=1
Loop
j=4, fil = FILA TABLA, px=1
Loop
Locate 'Plus one(fil), Plus two (col)'
Printnl( Get if ([px,py] Get 'números' ---Backup to (celda)---, celda, " ") )
fil += 3
--j, ++px
Back if (j) is not zero
col += 6, --i, ++py
Back if (i) is not zero
Return
 
Define ( Pone las casillas )
i=4, col = COLUMNA TABLA
Clr all marks
Loop
j=4, fil = FILA TABLA
Loop
Set 'fil, col', Gosub 'Pone un cuadrito'
fil += 3, --j
Back if (j) is not zero
col += 6, --i
Back if (i) is not zero
Return
 
Define (Pone un cuadrito, fil, col)
Locate 'fil, col', Print table 'casilla'
Return
 
Define ( Pone el índice, fil, col )
/* 5+(fil-1)*3 fila
10+(col-1)*6 col */
Clr all marks
Locate 'Minus one(fil) Mul by (3) Plus (FILA TABLA), Minus one(col) Mulby(6) Plus(COLUMNA TABLA)'
Print table 'índice'
Return
 
/* CONFIGURACION DEL JUEGO */
 
Define ( Crea la matriz de números )
Sequence ( 0, 1, 16, números )
Gosub 'Barajar el array'
Redim ( números, 4,4 )
Return
 
/* algoritmo de Fisher-Yates */
Define ( Barajar el array )
N = 0, Let ( N := Length(números) )
R = 0, aux = 0
Loop
Let (R := Ceil(Rand(N)))
Let (aux := [R] Get 'números' )
[N] Get 'números', [R] Put 'números'
Set 'aux', [N] Put 'números'
--N
Back if 'N' is positive
If ( [16] Get 'números' ---Backup to 'aux'---, Not (Is zero?) )
[aScan(1,0,números)] Set 'aux', Put 'números'
[16] Set '0', Put 'números'
End If
Return
 
Define ( Crea una casilla )
Set 'Utf8(Chr(218)),Utf8(Chr(196)),Utf8(Chr(196)),Utf8(Chr(196)),Utf8(Chr(196)),Utf8(Chr(191))', Apnd row 'casilla'
Set 'Utf8(Chr(179))," "," "," "," ",Utf8(Chr(179))', Apnd row 'casilla'
Set 'Utf8(Chr(192)),Utf8(Chr(196)),Utf8(Chr(196)),Utf8(Chr(196)),Utf8(Chr(196)),Utf8(Chr(217))', Apnd row 'casilla'
Return
 
Define ( Crea el índice )
Set 'Utf8(Chr(220)),Utf8(Chr(220)),Utf8(Chr(220)),Utf8(Chr(220)),Utf8(Chr(220)),Utf8(Chr(220))', Apnd row 'índice'
Set 'Utf8(Chr(219))," "," "," "," ",Utf8(Chr(219))', Apnd row 'índice'
Set 'Utf8(Chr(223)),Utf8(Chr(223)),Utf8(Chr(223)),Utf8(Chr(223)),Utf8(Chr(223)),Utf8(Chr(223))', Apnd row 'índice'
Return
 
</syntaxhighlight>
{{out}}
<pre>
$ hopper jm/puzzle.jambo
┌────┐┌────┐┌────┐┌────┐
│ 14 ││ 5 ││ 3 ││ 12 │
└────┘└────┘└────┘└────┘
┌────┐┌────┐┌────┐┌────┐
│ 13 ││ 9 ││ 6 ││ 11 │
└────┘└────┘└────┘└────┘
┌────┐┌────┐┌────┐┌────┐
│ 15 ││ 10 ││ 8 ││ 2 │
└────┘└────┘└────┘└────┘
┌────┐┌────┐┌────┐▄▄▄▄▄▄
│ 4 ││ 1 ││ 7 │█ █
└────┘└────┘└────┘▀▀▀▀▀▀
..... (muchos click)
┌────┐┌────┐┌────┐┌────┐
│ 7 ││ 10 ││ 14 ││ 12 │
└────┘└────┘└────┘└────┘
┌────┐┌────┐┌────┐┌────┐
│ 15 ││ ││ 4 ││ 2 │
└────┘└────┘└────┘└────┘
┌────┐▄▄▄▄▄▄┌────┐┌────┐
│ 1 │█ 8 █│ 6 ││ 11 │
└────┘▀▀▀▀▀▀└────┘└────┘
┌────┐┌────┐┌────┐┌────┐
│ 3 ││ 13 ││ 5 ││ 9 │
└────┘└────┘└────┘└────┘
....( muy muchos clicks )
┌────┐┌────┐┌────┐┌────┐
│ 1 ││ 2 ││ 3 ││ 4 │
└────┘└────┘└────┘└────┘
┌────┐┌────┐┌────┐┌────┐
│ 5 ││ 6 ││ 7 ││ 8 │
└────┘└────┘└────┘└────┘
┌────┐┌────┐┌────┐┌────┐
│ 9 ││ 10 ││ 11 ││ 12 │
└────┘└────┘└────┘└────┘
┌────┐┌────┐┌────┐▄▄▄▄▄▄
│ 13 ││ 14 ││ 15 │█ █
└────┘└────┘└────┘▀▀▀▀▀▀
 
LO RESOLVISTE!
</pre>
 
=={{header|APL}}==
{{works with|Dyalog APL|16.0}}
<langsyntaxhighlight APLlang="apl">fpg←{⎕IO←0
⍺←4 4
(s∨.<0)∨2≠⍴s←⍺:'invalid shape:'s
Line 873 ⟶ 2,121:
(1↓⍺)∇ n
}z
}</langsyntaxhighlight>
{{out}}
<pre> fpg 10
Line 922 ⟶ 2,170:
=={{header|ARM Assembly}}==
{{works with|as|Raspberry Pi}}
<syntaxhighlight lang="arm assembly">
<lang ARM Assembly>
 
/* ARM assembly Raspberry PI */
Line 1,560 ⟶ 2,808:
bx lr @return
 
</syntaxhighlight>
</lang>
 
=={{header|Arturo}}==
<syntaxhighlight lang="arturo">
;; ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~
;; ===>> ~~ Game's functions ~~ <<===
;; --->> ~~ Init functions ~~ <<---
 
;; This is a solved sample that is used to
;; init and finish the game
solvedTable: @[ " 1 " " 2 " " 3 " " 4 "
" 5 " " 6 " " 7 " " 8 "
" 9 " " 10 " " 11 " " 12 "
" 13 " " 14 " " 15 " " " ]
 
;; Use this once in :game's init, to get a player position
;; Q: Why use it once?
;; A: This algorithm is slower than just get a stored varible
;; yet this searches for a string for every value from :game
getPlayerPosition: $[table :block][
return index table " "
]
 
;; This is the object that represents the game
;; 'table » The sample table to generate the game
define :game [
table :block
][
 
init: [
; checks if 'table has 16 elements
ensure [16 = size this\table]
 
;; The game's table itself
this\table: (shuffle this\table) ; creates a random game
;; The current movement. When less, better is your punctuation
this\movements: 0
;; The current 'playerPosition in table
;; Used to evaluate if certain movement is possible or not
this\playerPosition: getPlayerPosition this\table
;; Defines it the gameLoop still running
this\running?: true
]
 
;; A builtin print function that simplifies the use
print: [
render {
Movements: |this\movements|, Position: |this\playerPosition|
*-----*-----*-----*-----*
|this\table\0| |this\table\1| |this\table\2| |this\table\3|
*-----*-----*-----*-----*
|this\table\4| |this\table\5| |this\table\6| |this\table\7|
*-----*-----*-----*-----*
|this\table\8| |this\table\9| |this\table\10| |this\table\11|
*-----*-----*-----*-----*
|this\table\12| |this\table\13| |this\table\14| |this\table\15|
*-----*-----*-----*-----*
}
]
 
;; Compares the internal's 'table with another :block
compare: [
if this\table = that
-> return true
]
 
]
 
;; These are the commands used internally on game
;; To avoid ambiguity, User's input'll to be translated to this
gameActions: ['up, 'left, 'down, 'right, 'quit]
 
 
;; ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~
;; -->> Print funnctions <<---
 
;; A template for print instructions
printInstructions: [
color #cyan "Type (WASD) to move and (Q) to quit."
]
 
;; A template for print input warning
;; 'input: the wrong input itself that will be printed
printWrongInput: $[inp :string][
print color #red
~"Wrong input: '|inp|'"
]
 
;; A template for print input warning
;; 'action: could be 'up, 'down, 'left or 'right
printWrongMovement: $[action :literal][
print color #red
~"Wrong movement. Can't go |action|"
]
 
 
;; ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~
;; --->> Validators/Checkers functions <<---
 
;; Checks if a 'input is in 'gameActions
;; Valids for: 'up, 'down, 'left, 'right and 'quit
validInput?: $[inp :any][
return (in? inp gameActions)
]
 
;; Checks if the current movement tried is possible
;; 'game » is the current game
;; 'movement » must be in 'gameActions, but can't be 'quit
validMovement?: $[
game :game
movement :literal
][
pos: game\playerPosition
case [movement]
when? [='up]
-> return (not? in? pos [0..3])
when? [='down]
-> return (not? in? pos [12..15])
when? [='left]
-> return (not? in? pos [0 4 8 12])
when? [='right]
-> return (not? in? pos [3 7 11 15])
else
-> return false
]
 
 
;; ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~
;; --->> Action functions <<---
 
;; Gets user input from terminal
;; returning a :literal from 'gameActions
;; Raises: In case of wrong input,
;; will be returned the same input as a :string
parseInput: $[inp :string][
lowerInp: lower inp
case [lowerInp]
when? [="w"] -> return 'up
when? [="a"] -> return 'left
when? [="s"] -> return 'down
when? [="d"] -> return 'right
when? [="q"] -> return 'quit
else -> return inp
]
 
;; Moves the player in Game's Table
;; Note that this's a unsafe function,
;; use 'validMovement? to check a 'movement given a game,
;; and then use this
movePlayer: $[
game :game
movement :literal
][
 
position: game\playerPosition
 
updateGame: $[
game :game
playerPosition :integer
relativePosition :integer
][
try [
 
; 'otherPosition is the real index of the 'relativePosition
otherPosition: + playerPosition relativePosition
 
; -- Updates the table, swaping the positions
temp: game\table\[playerPosition]
game\table\[playerPosition]: game\table\[otherPosition]
game\table\[otherPosition]: temp
 
; -- Updates player's status
game\playerPosition: otherPosition
game\movements: inc game\movements
] else -> panic "'movement didn't checked."
]
 
case [movement]
when? [='up]
-> (updateGame game position (neg 4))
when? [='down]
-> (updateGame game position (4))
when? [='left]
-> (updateGame game position (neg 1))
when? [='right]
-> (updateGame game position (1))
else -> panic "'movement didn't checked."
 
]
 
endGame: $[
message :string
][
print message
exit
]
 
 
;; ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~
;; --->> Run function <<---
 
;; Inits ans runs the game
;; 'sampleTable must be already solved
runGame: $[sampleTable :block][
game: to :game [sampleTable]
 
while [game\running?] [
print game
print printInstructions
command: parseInput input ">> "
 
if command = 'quit
-> endGame "Exiting game..."
 
validInp: validInput? command
if? validInp [
validMov: validMovement? game command
(validMov)?
-> movePlayer game command
-> printWrongMovement command
] else
-> printWrongInput command
 
if sampleTable = game
-> endGame "Congratulations! You won!"
print ""
]
]
 
 
runGame solvedTable</syntaxhighlight>
 
=={{header|Astro}}==
<langsyntaxhighlight lang="python">type Puzzle(var items: {}, var position: -1)
 
fun mainframe(puz):
Line 1,677 ⟶ 3,155:
print 'You WON'
break
</syntaxhighlight>
</lang>
 
=={{header|AutoHotkey}}==
<langsyntaxhighlight AutoHotkeylang="autohotkey">Size := 20
Grid := [], Deltas := ["-1,0","1,0","0,-1","0,1"], Width := Size * 2.5
Gui, font, S%Size%
Line 1,756 ⟶ 3,234:
if (Trim(gridCont, ",") = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16")
MsgBox, 262208, 15 Puzzle, You solved 15 Puzzle
}</langsyntaxhighlight>
 
=={{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}}===
<langsyntaxhighlight lang="basic">10 REM 15-PUZZLE GAME
20 REM COMMODORE BASIC 2.0
30 REM ********************************
Line 1,875 ⟶ 3,451:
1130 FOR T=0 TO 400
1140 NEXT
1150 RETURN</langsyntaxhighlight>
 
=={{header|BBC BASIC}}==
{{works with|BBC BASIC for Windows}}{{works with|ARM BBC BASIC}}{{works with|Brandy BASIC|Matrix Brandy}}
<langsyntaxhighlight lang="bbcbasic"> IF INKEY(-256)=77 OR (INKEY(-256) AND &F0)=&A0 THEN MODE 1: COLOUR 0: COLOUR 143: *FX4,1
 
SIZE=4 : DIFFICULTY=3
Line 1,923 ⟶ 3,499:
COLOUR 0 : COLOUR 143
PRINT
ENDPROC</langsyntaxhighlight>
 
=={{header|BQN}}==
{{trans|APL}}
<syntaxhighlight lang="bqn">_while_ ← {𝔽⍟𝔾∘𝔽_𝕣_𝔾∘𝔽⍟𝔾𝕩}
FPG←{
𝕊𝕩: 4‿4𝕊𝕩;
(∧´𝕨<0)∨2≠≠𝕨 ? •Out "Invalid shape: "∾•Fmt 𝕨;
0≠=𝕩 ? •Out "Invalid shuffle count: "∾•Fmt 𝕩;
s𝕊𝕩:
d←⟨1‿0⋄¯1‿0⋄0‿1⋄0‿¯1⟩ # Directions
w←𝕨⥊1⌽↕×´𝕨 # Solved grid
b←w # Board
z←⊑{
z‿p←𝕩
p↩(⊢≡s⊸|)¨⊸/(<z)+d(¬∘∊/⊣)p # filter out invalid
n←(•rand.Range ≠p)⊑p
b⌽⌾(z‿n⊸⊑)↩ # switch places
-`n‿z
}⍟𝕩 ⟨𝕨-1,⟨0⟩⟩
{
𝕊:
b≡w ? •Show b, •Out "You win", 0;
•Show b
inp←⊑{
Check 𝕩:
•Out "Enter move: "
x←•GetLine@
i←⊑"↑↓←→q"⊐x
{
i=4 ? i; # quit
i>4 ? •Out "Invalid direction: "∾x, Check x;
(⊢≢s⊸|)z+i⊑d ? •Out "Out of bounds: "∾x, Check x;
i
}
} @
{
𝕩=4 ? •Out "Quitting", 0;
mv←z+𝕩⊑d
b⌽⌾(mv‿z⊸⊑)↩
z↩mv
1
} inp
} _while_ ⊢ 1
@
}</syntaxhighlight>
<syntaxhighlight lang="bqn"> )ex 15_puzzle.bqn
FPG 10
┌─
╵ 1 2 0 3
5 6 7 4
9 10 11 8
13 14 15 12
Enter move:
a
Invalid direction: a
Enter move:
┌─
╵ 1 2 7 3
5 6 0 4
9 10 11 8
13 14 15 12
Enter move:
┌─
╵ 1 2 0 3
5 6 7 4
9 10 11 8
13 14 15 12
Enter move:
Out of bounds: ↓
...</syntaxhighlight>
 
=={{header|C}}==
===C89, 22 lines version===
The task, as you can see, can be resolved in 22 lines of no more than 80 characters. Of course, the source code in C is not very readable. The second example works exactly the same way, but it was written in much more human readable way. The program also works correctly for non-standard number of rows and/or columns.
<langsyntaxhighlight Clang="c">/* RosettaCode: Fifteen puzle game, C89, plain vanillia TTY, MVC, § 22 */
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
Line 1,949 ⟶ 3,601:
RIGHT;}}}void pause(void){getchar();}int main(void){srand((unsigned)time(NULL));
do setup();while(isEnd());show();while(!isEnd()){update(get());show();}disp(
"You win"); pause();return 0;}</langsyntaxhighlight>
 
===C89, short version, TTY mode===
<syntaxhighlight lang="c">/*
<lang C>/*
* RosettaCode: Fifteen puzle game, C89, plain vanillia TTY, MVC
*/
Line 2,075 ⟶ 3,727:
}
 
</syntaxhighlight>
</lang>
{{Out}}
<pre>
Line 2,107 ⟶ 3,759:
 
===C89, long version, TTY/Winapi/ncurses modes===
<langsyntaxhighlight Clang="c">/**
* RosettaCode: Fifteen puzle game, C89, MS Windows Console API, MVC
*
Line 2,417 ⟶ 4,069:
return EXIT_SUCCESS;
}
</syntaxhighlight>
</lang>
 
=={{header|C sharp|C#}}==
{{libheader|System.Windows.Forms}}
{{libheader|System.Drawing}}
{{works with|C sharp|63+}}
<langsyntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
 
public class FifteenPuzzle
{
const int gridSizeGridSize = 4; //Standard 15 puzzle is 4x4
const boolint evenSizedBlockCount = gridSize % 2 == 016;
const int blockCount = gridSize * gridSize;
const int last = blockCount - 1;
const int buttonSize = 50;
const int buttonMargin = 3; //default = 3
const int formEdge = 9;
static readonly Random rnd = new Random();
static readonly Font buttonFont = new Font("Arial", 15.75F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));
readonly Button[] buttons = new Button[blockCount];
readonly int[] grid = new int[blockCount];
readonly int[] positionOf = new int[blockCount];
int moves = 0;
DateTime start;
 
public static voidreadonly Main(string[]Random argsR = new Random();
 
private List<Button> Puzzles = new List<Button>();
private int Moves = 0;
private DateTime Start;
 
public class Puzzle
{
FifteenPuzzleprivate pint = new FifteenPuzzle()mOrderedNumer;
 
Form f = p.BuildForm();
Application.Run(f)public int CurrentNumber;
 
public int X;
public int Y;
 
public int InvX
{
get { return (GridSize - 1) - X; }
}
public int InvY
{
get { return (GridSize - 1) - Y; }
}
 
public Puzzle(int OrderedNumer)
{
mOrderedNumer = OrderedNumer;
 
CurrentNumber = OrderedNumer;
 
X = OrderedNumer % GridSize;
Y = OrderedNumer / GridSize;
}
public Puzzle(int OrderedNumer, int CurrentNumber)
: this(OrderedNumer)
{
this.CurrentNumber = CurrentNumber;
}
 
public bool IsEmptyPuzzle
{
get { return CurrentNumber >= (BlockCount - 1); }
}
public bool IsTruePlace
{
get { return (CurrentNumber == mOrderedNumer); }
}
public bool NearestWith(Puzzle OtherPz)
{
int dx = (X - OtherPz.X);
int dy = (Y - OtherPz.Y);
 
if ((dx == 0) && (dy <= 1) && (dy >= -1)) return true;
if ((dy == 0) && (dx <= 1) && (dx >= -1)) return true;
 
return false;
}
 
public override string ToString()
{
return (CurrentNumber + 1).ToString();
}
}
 
public FifteenPuzzlestatic void Main(string[] args)
{
forFifteenPuzzle (int iGame = 0;new i < blockCountFifteenPuzzle(); i++) {
grid[i] = iApplication.Run(Game.CreateForm());
positionOf[i] = i;
}
}
 
private Form BuildFormCreateForm()
{
Buttonint startButtonButtonSize = new Button {50;
int ButtonMargin = 3;
Font = new Font("Arial", 9.75F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0))),
int SizeFormEdge = new Size(86, 23),9;
Location = new Point(formEdge,
(buttonSize + buttonMargin * 2) * gridSize + buttonMargin + formEdge),
Text = "New Game",
UseVisualStyleBackColor = true
};
startButton.Click += (sender, e) => Shuffle();
 
Font ButtonFont = new Font("Arial", 15.75F, FontStyle.Regular);
int size = buttonSize * gridSize + buttonMargin * gridSize * 2 + formEdge * 2;
 
Form form = new Form {
Button StartButton = new Text = "Fifteen",Button();
ClientSizeStartButton.Location = new SizePoint(width: sizeFormEdge, height:(GridSize size* (ButtonMargin + buttonMargin * 2ButtonSize)) + startButton.HeightFormEdge);
}StartButton.Size = new Size(86, 23);
StartButton.Font = new Font("Arial", 9.75F, FontStyle.Regular);
form.SuspendLayout();
for (int indexStartButton.Text = 0;"New index < blockCountGame"; index++) {
StartButton.UseVisualStyleBackColor = true;
Button button = new Button {
FontStartButton.TabStop = buttonFont,false;
 
Size = new Size(buttonSize, buttonSize),
StartButton.Click //Margin += new PaddingEventHandler(buttonMarginNewGame),;
 
Text = (index + 1).ToString(),
int FormWidth = (GridSize * ButtonSize) + ((GridSize - 1) * ButtonMargin) + (FormEdge * 2);
UseVisualStyleBackColor = true
int FormHeigth = FormWidth }+ StartButton.Height;
 
SetLocation(button, index);
Form Form = new form.Controls.AddForm(button);
buttons[index]Form.Text = button"Fifteen";
Form.ClientSize = new Size(FormWidth, int i = indexFormHeigth);
Form.FormBorderStyle = FormBorderStyle.FixedSingle;
button.Click += (sender, e) => ButtonClick(i);
Form.MaximizeBox = false;
Form.SuspendLayout();
 
for (int i = 0; i < BlockCount; i++)
{
Button Bt = new Button();
Puzzle Pz = new Puzzle(i);
 
int PosX = FormEdge + (Pz.X) * (ButtonSize + ButtonMargin);
int PosY = FormEdge + (Pz.Y) * (ButtonSize + ButtonMargin);
Bt.Location = new Point(PosX, PosY);
 
Bt.Size = new Size(ButtonSize, ButtonSize);
Bt.Font = ButtonFont;
 
Bt.Text = Pz.ToString();
Bt.Tag = Pz;
Bt.UseVisualStyleBackColor = true;
Bt.TabStop = false;
 
Bt.Enabled = false;
if (Pz.IsEmptyPuzzle) Bt.Visible = false;
 
Bt.Click += new EventHandler(MovePuzzle);
 
Puzzles.Add(Bt);
Form.Controls.Add(Bt);
}
 
form.Controls.Add(startButton);
formForm.ResumeLayoutControls.Add(StartButton);
return formForm.ResumeLayout();
 
return Form;
}
 
private void ButtonClickNewGame(intobject Sender, EventArgs iE)
{
do
if (buttons[last].Visible) return;
int target = positionOf[i];{
if for (positionOf[int i] /= gridSize0; ==i positionOf[last]< /Puzzles.Count; gridSizei++) {
while (positionOf[last] < target) {
SwapButton Bt1 = Puzzles[R.Next(lasti, grid[positionOf[lastPuzzles.Count)] + 1]);
moves++Button Bt2 = Puzzles[i];
} Swap(Bt1, Bt2);
while (positionOf[last] > target) {
Swap(last, grid[positionOf[last] - 1]);
moves++;
}
} else if (positionOf[i] % gridSize == positionOf[last] % gridSize) {
while (positionOf[last] < target) {
Swap(last, grid[positionOf[last] + gridSize]);
moves++;
}
while (positionOf[last] > target) {
Swap(last, grid[positionOf[last] - gridSize]);
moves++;
}
}
ifwhile (Solved!IsSolvable()) {;
 
TimeSpan elapsed = DateTime.Now - start;
for (int i = 0; i < Puzzles.Count; i++)
elapsed = TimeSpan.FromSeconds(Math.Round(elapsed.TotalSeconds, 0));
{
buttons[last].Visible = true;
MessageBoxPuzzles[i].Show($"SolvedEnabled in= {moves} moves. Time: {elapsed}")true;
}
}
 
Moves = 0;
bool Solved() => Enumerable.Range(0, blockCount - 1).All(i => positionOf[i] == i);
Start = DateTime.Now;
 
static void SetLocation(Button button, int index)
{
int row = index / gridSize, column = index % gridSize;
button.Location = new Point(
(buttonSize + buttonMargin * 2) * column + buttonMargin + formEdge,
(buttonSize + buttonMargin * 2) * row + buttonMargin + formEdge);
}
 
private void MovePuzzle(object Sender, EventArgs E)
void Shuffle()
{
forButton (int iBt1 = 0(Button)Sender; i < blockCount; i++) {
Puzzle int rPz1 = rnd.Next(i, blockCountPuzzle)Bt1.Tag;
 
int g = grid[r];
Button Bt2 = grid[r]Puzzles.Find(Bt => grid[i]((Puzzle)Bt.Tag).IsEmptyPuzzle);
Puzzle grid[i]Pz2 = g(Puzzle)Bt2.Tag;
 
}
forif (int i = 0; i < blockCount; i++Pz1.NearestWith(Pz2)) {
positionOf[grid[i]] = i;{
SetLocationSwap(buttons[grid[i]]Bt1, iBt2);
Moves++;
}
if (!Solvable()) Swap(0, 1); //Swap any 2 blocks
 
buttons[last].Visible = falseCheckWin();
moves = 0;
start = DateTime.Now;
}
 
boolprivate Solvablevoid CheckWin()
{
Button WrongPuzzle = Puzzles.Find(Bt => !((Puzzle)Bt.Tag).IsTruePlace);
bool parity = true;
forbool (int iUWin = 0;(WrongPuzzle i== < blockCount - 2null); i++) {
 
for (int j = i + 1; j < blockCount - 1; j++) {
if (UWin)
if (positionOf[j] < positionOf[i]) parity = !parity;
{
for (int i = 0; i < Puzzles.Count; i++)
{
Puzzles[i].Enabled = false;
}
 
TimeSpan Elapsed = DateTime.Now - Start;
Elapsed = TimeSpan.FromSeconds(Math.Round(Elapsed.TotalSeconds, 0));
MessageBox.Show(String.Format("Solved in {0} moves. Time: {1}", Moves, Elapsed));
}
if (evenSized && positionOf[last] / gridSize % 2 == 0) parity = !parity;
return parity;
}
 
private void Swap(intButton aBt1, intButton bBt2)
{
Pointif location(Bt1 == Bt2) buttons[a].Locationreturn;
buttons[a].Location = buttons[b].Location;
buttons[b].Location = location;
 
intPuzzle pPz1 = positionOf[a](Puzzle)Bt1.Tag;
positionOf[a]Puzzle Pz2 = positionOf[b](Puzzle)Bt2.Tag;
positionOf[b] = p;
 
grid[positionOf[a]]int g = aPz1.CurrentNumber;
grid[positionOf[b]]Pz1.CurrentNumber = bPz2.CurrentNumber;
Pz2.CurrentNumber = g;
 
Bt1.Visible = true;
Bt1.Text = Pz1.ToString();
if (Pz1.IsEmptyPuzzle) Bt1.Visible = false;
 
Bt2.Visible = true;
Bt2.Text = Pz2.ToString();
if (Pz2.IsEmptyPuzzle) Bt2.Visible = false;
}
 
private bool IsSolvable()
{
// WARNING: size of puzzle board MUST be even(like 4)!
// For explain see: https://www.geeksforgeeks.org/check-instance-15-puzzle-solvable/
 
int InvCount = 0;
for (int i = 0; i < Puzzles.Count - 1; i++)
{
for (int j = i + 1; j < Puzzles.Count; j++)
{
Puzzle Pz1 = (Puzzle)Puzzles[i].Tag;
if (Pz1.IsEmptyPuzzle) continue;
 
Puzzle Pz2 = (Puzzle)Puzzles[j].Tag;
if (Pz2.IsEmptyPuzzle) continue;
 
if (Pz1.CurrentNumber > Pz2.CurrentNumber) InvCount++;
}
}
 
Button EmptyBt = Puzzles.Find(Bt => ((Puzzle)Bt.Tag).IsEmptyPuzzle);
Puzzle EmptyPz = (Puzzle)EmptyBt.Tag;
 
bool Result = false;
if ((EmptyPz.InvY + 1) % 2 == 0) // is even
{
// is odd
if (InvCount % 2 != 0) Result = true;
}
else // is odd
{
// is even
if (InvCount % 2 == 0) Result = true;
}
return Result;
}
}</langsyntaxhighlight>
 
=={{header|C++}}==
<langsyntaxhighlight lang="cpp">
#include <time.h>
#include <stdlib.h>
Line 2,680 ⟶ 4,426:
p15 p; p.play(); return 0;
}
</syntaxhighlight>
</lang>
<pre>
+----+----+----+----+
Line 2,698 ⟶ 4,444:
Tested with GnuCOBOL
 
<langsyntaxhighlight lang="cobol"> >>SOURCE FORMAT FREE
*> This code is dedicated to the public domain
*> This is GNUCOBOL 2.0
Line 2,848 ⟶ 4,594:
end-evaluate
.
end program fifteen.</langsyntaxhighlight>
 
{{out}}
Line 2,867 ⟶ 4,613:
Credit to this post for help with the inversions-counting function: [http://www.lispforum.com/viewtopic.php?f=2&t=3422]
 
Run it (after loading the file) with <syntaxhighlight lang ="lisp">|15|::main</langsyntaxhighlight>.
 
<langsyntaxhighlight lang="lisp">(defpackage :15
(:use :common-lisp))
(in-package :15)
Line 2,967 ⟶ 4,713:
(rotatef (aref *board* (first pos) (second pos))
(aref *board* (first zpos) (second zpos))))))
(format t "You win!~%"))</langsyntaxhighlight>
 
=={{header|Craft Basic}}==
[[File:15 puzzle craft basic.png|thumb]]
<syntaxhighlight lang="basic">rem 15 Puzzle example game
rem written in Craft Basic
rem by Gemino Smothers 2023
rem www.lucidapogee.com
 
define size = 16, correct = 0, moves = 0
define click = 0, start = 0
 
dim list[size]
 
gosub setup
gosub game
 
end
 
sub setup
 
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
 
let x = 0
let y = y + 25
 
endif
 
let x = x + 28
 
formid i + 1
formtext ""
buttonform x, y, 25, 20
 
next i
 
formid 17
formtext "
staticform 40, 130, 100, 20
bgcolor 0, 128, 0
fgcolor 255, 255, 0
colorform
 
formid 18
formtext ""
staticform 40, 150, 100, 20
bgcolor 0, 128, 0
fgcolor 255, 255, 0
colorform
 
formid 19
formtext "New"
buttonform 1, 1, 50, 20
 
formid 20
formtext "Help"
buttonform 55, 1, 50, 20
 
formid 21
formtext "About"
buttonform 110, 1, 50, 20
 
formid 22
formtext "Welcome."
staticform 40, 170, 120, 20
bgcolor 0, 128, 0
fgcolor 255, 255, 0
colorform
 
return
 
sub shuffle
 
let start = 1
 
formid 22
formtext "shuffling..."
updateform
 
for i = 0 to size - 1
 
formid i + 1
formtext ""
updateform
 
let list[i] = 0
 
next i
 
let t = 0
let i = 0
 
do
 
if i = 14 then
 
let n = 120 - t
 
formid i + 1
formtext n
updateform
 
let list[i] = n
 
break
 
endif
 
for f = 0 to size - 1
 
let n = int(rnd * 15) + 1
let s = 0
 
for c = 0 to i - 1
 
if n = list[c] then
 
let s = 1
break c
 
endif
 
next c
 
if s = 0 and list[i] = 0 then
 
formid i + 1
formtext n
updateform
 
let list[i] = n
let t = t + n
let i = i + 1
 
endif
 
wait
 
next f
 
loop i < size - 1
 
formid 22
formtext ""
updateform
 
return
 
sub game
 
do
 
let click = forms
 
if click > 0 and click < 17 and start = 1 then
 
let moves = moves + 1
 
formid 17
formtext "Moves: ", moves
updateform
 
gosub checkspaces
gosub checkorder
 
endif
 
if click = 19 then
 
gosub shuffle
 
let moves = 0
let correct = 0
 
formid 17
formtext "Moves:"
updateform
 
formid 18
formtext "Correct:"
updateform
 
endif
 
if click = 20 then
 
alert "Click the numbers to move them in the correct order."
 
endif
 
if click = 21 then
 
alert "15 Puzzle", newline, "by Gemino Smothers 2023 ", newline, " www.lucidapogee.com"
 
endif
 
button k, 27
 
wait
 
loop k = 0
 
return
 
sub checkspaces
 
let click = click - 1
let top = click - 4
let right = click + 1
let bottom = click + 4
let left = click - 1
 
if top >= 0 then
 
if list[top] = 0 then
 
let n = top
gosub swap
 
endif
 
endif
 
if right <= size - 1 then
 
if list[right] = 0 then
 
let n = right
gosub swap
 
endif
 
endif
 
if bottom <= size - 1 then
 
if list[bottom] = 0 then
 
let n = bottom
gosub swap
 
endif
 
endif
 
if left >= 0 then
 
if list[left] = 0 then
 
let n = left
gosub swap
 
endif
 
endif
 
return
 
sub swap
 
let t = list[click]
let list[n] = list[click]
let list[click] = 0
 
let click = click + 1
formid click
formtext ""
updateform
 
let n = n + 1
formid n
formtext t
updateform
 
return
 
sub checkorder
 
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
 
endif
 
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.onlinedev/apps/15-puzzle.html?v1 Run it]
 
<syntaxhighlight>
<lang>set_background 432
sys topleft
set_textsize 13
background 432
textsize 13
len f[] 16
funcproc draw . .
clear
clear_screen
for i range= 1 to 16
h = f[i]
if h < 16
x = (i - 1) mod 4 * 24 + 3
y = (i - 1) div 4 * 24 + 3
set_color color 210
move_pen move x y
draw_rect rect 22 22
move_pen move x + 4 y + 56
if h < 10
move_pen move x + 6 y + 56
.
color 885
text h
.
.
set_color 885
draw_text h
.
.
.
global done .
funcproc initsmiley . .
done s = 03.5
for ix range= 1686
f[i]y = i + 186
move x y
.
# shufflecolor 983
for icircle =2.8 14* downto 1s
color 000
r = random (i + 1)
move swapx f[r]- f[i]s y - s
circle s / 3
.
move x + 3.5 y - 3.5
# make it solvable
inv =circle 0s / 3
linewidth s / 3
for i range 15
curve [ x - s y + s x y + 2 * s x + s y + s ]
for j range i
.
if f[j] > f[i]
proc init . .
inv += 1
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
.
if inv mod 2 <>swap 0f[1] f[2]
.
swap f[0] f[1]
textsize 12
.
draw
set_textsize 12
call draw
.
funcproc move_tile . .
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]
.
call draw
done for i = 1 to 15
if f[i] > f[i + 1]
for i range 15
if f[i] > f[i + 1]return
done = 0.
.
done = 1
.
if donetimer = 10.5
clear_screen
move_pen 10 30
draw_text "Well done!"
.
.
on mouse_down
if done = 10
call init move_tile
elif done = 3
else
call move_tile init
.
.
on timer
if done = 1
smiley
done = 2
timer 2
else
done = 3
.
.
call init</lang>
</syntaxhighlight>
 
=={{header|F_Sharp|F#}}==
<langsyntaxhighlight lang="fsharp">
// 15 Puzzle Game. Nigel Galloway: August 9th., 2020
let Nr,Nc,RA,rnd=[|3;0;0;0;0;1;1;1;1;2;2;2;2;3;3;3|],[|3;0;1;2;3;0;1;2;3;0;1;2;3;0;1;2|],[|for n in [1..16]->n%16|],System.Random()
Line 3,073 ⟶ 5,319:
[<EntryPoint>]
let main n = fL(match n with [|n|]->let g=[|let g=uint64 n in for n in 60..-4..0->int((g>>>n)&&&15UL)|] in (Array.findIndex((=)0)g,g) |_->fE()) 0
</syntaxhighlight>
</lang>
3 uses:
15 game with no parameters will generate a random game which may be solved.
Line 3,107 ⟶ 5,353:
</pre>
=={{header|Factor}}==
<langsyntaxhighlight lang="factor">USING: accessors combinators combinators.extras
combinators.short-circuit grouping io kernel literals math
math.matrices math.order math.parser math.vectors prettyprint qw
Line 3,183 ⟶ 5,429:
drop ;
 
MAIN: main</langsyntaxhighlight>
{{out}}
<pre>
Line 3,218 ⟶ 5,464:
See [[15_puzzle_solver#Forth]] for a solver based on the same code.
 
<langsyntaxhighlight lang="forth">#! /usr/bin/gforth
 
cell 8 <> [if] s" 64-bit system required" exception throw [then]
Line 3,287 ⟶ 5,533:
 
solution 1000 shuffle play
</syntaxhighlight>
</lang>
 
=={{header|Fortran}}==
Line 3,300 ⟶ 5,546:
The game plan is to start with an ordered array so that each cell definitely has a unique code, then jumble them via "random" swaps. Possible arrangements turn out to have either odd or even parity based on the number of out-of-sequence squares, and as the allowed transformations do not change the parity and the solution state has even parity, odd parity starting states should not be presented except by those following Franz Kafka. The calculation is simplified by always having the blank square in the last position, thus in the last row. Once an even-parity starting state is floundered upon, the blank square is re-positioned using allowable moves so that the parity is not altered thereby. Then the game begins: single-square moves only are considered, though in practice groups of squares could be moved horizontally or vertically rather than one-step-at-a-time - a possible extension.
 
The source style uses F90 for its array arithmetic abilities, especially the functions ALL, ANY and COUNT. A statement <langsyntaxhighlight Fortranlang="fortran">LOCZ = MINLOC(BOARD) !Find the zero. 0 = BOARD(LOCZ(1),LOCZ(2)) == BOARD(ZC,ZR)</langsyntaxhighlight> could be used but is unnecessary thanks to tricks with EQUIVALENCE. For earlier Fortran, various explicit DO-loops would have to be used. This would at least make clear whether or not the equivalents of ANY and ALL terminated on the first failure or doggedly scanned the entire array no matter what. <langsyntaxhighlight Fortranlang="fortran"> SUBROUTINE SWAP(I,J) !Alas, furrytran does not provide this.
INTEGER I,J,T !So, we're stuck with supplying the obvious.
T = I !And, only for one type at a go.
Line 3,416 ⟶ 5,662:
IF (ANY(BORED(1:N - 2) + 1 .NE. BORED(2:N - 1))) GO TO 20 !Are we there yet?
WRITE (MSG,*) TRY,"Steps to success!" !Yes!
END !That was fun.</langsyntaxhighlight>
 
Output: Not so good. As ever, the character cell sizes are not square so a square game board comes out as a rectangle. Similarly, underlining is unavailable (no overprints!) so the layout is not pleasing. There are special "box-drawing" glyphs available, but they are not standardised and there is still no overprinting so that a flabby waste of space results. Further, there is no ability to re-write the display, even though one could easily regard the output to the screen as a random-access file: <code>WRITE (MSG,REC = 6) STUFF</code> would rewrite the sixth line of the display. Instead, output relentlessly rolls forwards, starting as follows:
Line 3,450 ⟶ 5,696:
 
=={{header|FreeBASIC}}==
<langsyntaxhighlight lang="freebasic">sub drawboard( B() as ubyte )
dim as string outstr = ""
for i as ubyte = 0 to 15
Line 3,523 ⟶ 5,769:
print "Congratulations! You win!"
print
drawboard B()</langsyntaxhighlight>
 
 
 
=={{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}}==
<langsyntaxhighlight lang="gambas">'Charlie Ogier (C) 15PuzzleGame 24/04/2017 V0.1.0 Licenced under MIT
'Inspiration came from: -
''http://rosettacode.org/wiki/15_Puzzle_Game
Line 3,824 ⟶ 6,168:
 
End
</syntaxhighlight>
</lang>
 
[http://www.cogier.com/gambas/Copuzzle.png Click here for image of game in play]
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 3,982 ⟶ 6,326:
return
}
}</langsyntaxhighlight>
 
=={{header|Harbour}}==
<syntaxhighlight lang="harbour">
<lang Harbour>
 
#include "inkey.ch"
Line 4,170 ⟶ 6,514:
SetColor(" W/N, BG+/B")
RETURN fim
</syntaxhighlight>
</lang>
 
=={{header|Haskell}}==
<langsyntaxhighlight lang="haskell">import Data.Array
import System.Random
 
Line 4,245 ⟶ 6,589:
randomIndex <- randomRIO (0, length moves - 1)
let move = moves !! randomIndex
shufflePuzzle (numOfShuffels - 1) (applyMove move puzzle)</langsyntaxhighlight>
Output:
<pre>Please enter the difficulty level: 0, 1 or 2
Line 4,275 ⟶ 6,619:
Implementation:
 
<langsyntaxhighlight Jlang="j">require'general/misc/prompt'
 
genboard=:3 :0
Line 4,339 ⟶ 6,683:
showboard board
echo 'You win.'
)</langsyntaxhighlight>
 
Most of this is user interface code. We initially shuffle the numbers randomly, then check their parity and swap the first and last squares if needed. Then, for each move, we allow the user to pick one of the taxicab neighbors of the empty square.
Line 4,345 ⟶ 6,689:
A full game would be too big to be worth showing here, so for the purpose of giving a glimpse of what this looks like in action we replace the random number generator with a constant:
 
<langsyntaxhighlight Jlang="j"> game''
15 puzzle
h for help, q to quit
Line 4,382 ⟶ 6,726:
│13│14│15│ │
└──┴──┴──┴──┘
You win.</langsyntaxhighlight>
 
=={{header|Java}}==
{{works with|Java|8}}
<langsyntaxhighlight lang="java">package fifteenpuzzle;
 
import java.awt.*;
Line 4,599 ⟶ 6,943:
});
}
}</langsyntaxhighlight>
 
=={{header|Javascript}}==
Play it [http://paulo-jorente.de/webgames/15p/ here]
<langsyntaxhighlight lang="javascript">
var board, zx, zy, clicks, possibles, clickCounter, oldzx = -1, oldzy = -1;
function getPossibles() {
Line 4,722 ⟶ 7,066:
restart();
}
</syntaxhighlight>
</lang>
Html to test
<pre>
Line 4,741 ⟶ 7,085:
 
=={{header|Julia}}==
<langsyntaxhighlight lang="julia">
using Random
 
Line 4,849 ⟶ 7,193:
 
puzzle15play()
</langsyntaxhighlight>{{output}}<pre>
This puzzle is solvable.
+----+----+----+----+
Line 4,866 ⟶ 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}}==
{{trans|Java}}
<langsyntaxhighlight lang="scala">// version 1.1.3
 
import java.awt.BorderLayout
Line 5,017 ⟶ 7,467:
}
}
}</langsyntaxhighlight>
 
=={{header|Liberty BASIC}}==
{{trans|Commodore BASIC}}
{{works with|Just BASIC}}
<syntaxhighlight lang="lb">
<lang lb>
' 15-PUZZLE GAME
' ********************************
Line 5,156 ⟶ 7,606:
isPuzzleComplete = pc
end function
</syntaxhighlight>
</lang>
 
=={{header|LiveCode}}==
<syntaxhighlight lang="livecode">
<lang liveCode>
#Please note that all this code can be performed in livecode with just few mouse clicks
#This is just a pure script exampe
Line 5,221 ⟶ 7,671:
end if
end checkDistance
</syntaxhighlight>
</lang>
Screenshot:
[https://s24.postimg.org/uc6fx7kph/Livecode15_Puzzle_Game.png]
 
=={{header|Lua}}==
<langsyntaxhighlight lang="lua">
math.randomseed( os.time() )
local puz = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0 }
Line 5,323 ⟶ 7,773:
-- [ entry point ] --
beginGame()
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 5,355 ⟶ 7,805:
Also the code is not the best, because we can move from 4 position to 5 (we can't do that with real puzzle)
 
<syntaxhighlight lang="m2000 interpreter">
<lang M2000 Interpreter>
Module Puzzle15 {
Line 5,468 ⟶ 7,918:
}
Puzzle15
</syntaxhighlight>
</lang>
 
=={{header|Mathematica}} / {{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">grid = MapThread[{#1,#2} &, {Range @ 16, Range @ 16}]
 
Move[x_] := (empty = Select[grid, #[[1]]==16 &][[1,2]];
If[(empty == x+4) || (empty == x-4) ||
(Mod[empty,4] != 0 && empty == x-1) ||
(Mod[empty,4] != 1 && empty == x+1),
oldEmpty = grid[[empty]][[1]];
grid[[empty]][[1]] = grid[[x]][[1]];
grid[[x]][[1]] = oldEmpty])
 
CButton[{x_,loc_}] := If[x==16, Null, Button[x,Move @ loc]]
 
Dynamic @ Grid @ Partition[CButton /@ grid,4]</syntaxhighlight>
 
=={{header|Mercury}}==
Line 5,474 ⟶ 7,939:
The ideal in Mercury is to have a declarative module that encodes the game logic, and then separate modules to implement a human player with text commands (here), or keyed commands, or some kind of AI player, and so on. fifteen.print/3 is a arguably a smudge on fifteen's interface:
<langsyntaxhighlight Mercurylang="mercury">:- module fifteen.
:- interface.
:- use_module random, io.
Line 5,575 ⟶ 8,040:
move(I, right, !B) :-
not (I = 3 ; I = 7 ; I = 11 ; I = 15),
swap(I, I + 1, !B).</langsyntaxhighlight>
 
As used:
 
<langsyntaxhighlight Mercurylang="mercury">:- module play_fifteen.
:- interface.
:- import_module io.
Line 5,659 ⟶ 8,124:
"
Seed = time(NULL);
").</langsyntaxhighlight>
 
=={{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 5,708 ⟶ 8,515:
 
=={{header|Nim}}==
<langsyntaxhighlight lang="nim">import random, terminal
 
type
Line 5,850 ⟶ 8,657:
 
draw board
echo "You win!"</langsyntaxhighlight>
{{out}}
<pre>┌──┬──┬──┬──┐
Line 5,864 ⟶ 8,671:
 
=={{header|OCaml}}==
<langsyntaxhighlight lang="ocaml">module Puzzle =
struct
type t = int array
Line 5,902 ⟶ 8,709:
print_string " > ";
Puzzle.move p (read_line () |> int_of_string)
done</langsyntaxhighlight>
 
To move, input the number to slide into the blank. If you accidentally make an impossible move you can undo it by repeating the last input. A nice self-checked puzzle, the same as if you were physically moving the pieces around.
Line 5,952 ⟶ 8,759:
=={{header|Pascal}}==
This is Free Pascal(version >= 3.0.4) text mode implementation. To make a move, the user needs to enter the number of the selected tile.
<syntaxhighlight lang="pascal">
<lang Pascal>
program fifteen;
{$mode objfpc}
Line 6,242 ⟶ 9,049:
Run;
end.
</syntaxhighlight>
</lang>
 
=={{header|Perl}}==
Line 6,251 ⟶ 9,058:
On verbosity shows how the solvability is calculated. The program has some extra feature like font size and color scheme but also the possibility to set the intial board disposition.
This program was originally posted by me at [http://www.perlmonks.org/?node_id=1192660 perlmonks]
<langsyntaxhighlight lang="perl">
 
use strict;
Line 6,502 ⟶ 9,309:
 
 
</syntaxhighlight>
</lang>
 
===console version===
This short console program just poses solvable puzzles: it achieves this shuffling a solved board n times, where n defaults to 1000 but can be passed as first argument of the program in the command line. It was originally posted by me at [http://www.perlmonks.org/?node_id=1192865 perlmonks] but here a little modification was inserted to prevent wrong numbers to make the board messy.
<langsyntaxhighlight lang="perl">
use strict;
use warnings;
Line 6,538 ⟶ 9,345:
[$$e[0]-1,$$e[1]],[$$e[0]+1,$$e[1]],[$$e[0],$$e[1]-1],[$$e[0],$$e[1]+1]
}
</syntaxhighlight>
</lang>
 
=={{header|Phix}}==
=== console only ===
Kept simple. Obviously, increase the 5 random moves for more of a challenge.
<!--<lang Phix>(phixonline)-->
<syntaxhighlight lang="phix">
<span style="color: #008080;">constant</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;">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 style="color: #0000FF;">,</span> <span style="color: #000000;">DOWN<span style="color: #0000FF;">=<span style="color: #000000;">336</span>
constant ESC=27, UP=328, LEFT=331, RIGHT=333, DOWN=336
<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;">15<span style="color: #0000FF;">)<span style="color: #0000FF;">&<span style="color: #000000;">0<span style="color: #0000FF;">,</span> <span style="color: #000000;">solve</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">board</span>
sequence board = tagset(15)&0, solve = board
<span style="color: #004080;">integer</span> <span style="color: #000000;">pos</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">16</span>
integer pos = 16
<span style="color: #008080;">procedure</span> <span style="color: #000000;">print_board<span style="color: #0000FF;">(<span style="color: #0000FF;">)</span>
procedure print_board()
<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: #7060A8;">length<span style="color: #0000FF;">(<span style="color: #000000;">board<span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
for i=1 to length(board) do
<span style="color: #7060A8;">puts<span style="color: #0000FF;">(<span style="color: #000000;">1<span style="color: #0000FF;">,<span style="color: #008080;">iff<span style="color: #0000FF;">(<span style="color: #000000;">i<span style="color: #0000FF;">=<span style="color: #000000;">pos<span style="color: #0000FF;">?<span style="color: #008000;">" "<span style="color: #0000FF;">:<span style="color: #7060A8;">sprintf<span style="color: #0000FF;">(<span style="color: #008000;">"%3d"<span style="color: #0000FF;">,<span style="color: #0000FF;">{<span style="color: #000000;">board<span style="color: #0000FF;">[<span style="color: #000000;">i<span style="color: #0000FF;">]<span style="color: #0000FF;">}<span style="color: #0000FF;">)<span style="color: #0000FF;">)<span style="color: #0000FF;">)</span>
puts(1,iff(i=pos?" ":sprintf("%3d",{board[i]})))
<span style="color: #008080;">if</span> <span style="color: #7060A8;">mod<span style="color: #0000FF;">(<span style="color: #000000;">i<span style="color: #0000FF;">,<span style="color: #000000;">4<span style="color: #0000FF;">)<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"<span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
if mod(i,4)=0 then puts(1,"\n") end if
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end for
<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>
puts(1,"\n")
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
end procedure
<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>
procedure move(integer d)
<span style="color: #004080;">integer</span> <span style="color: #000000;">new_pos</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">pos<span style="color: #0000FF;">+<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;">1<span style="color: #0000FF;">,<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;">d<span style="color: #0000FF;">]</span>
integer new_pos = pos+{+4,+1,-1,-4}[d]
<span style="color: #008080;">if</span> <span style="color: #000000;">new_pos<span style="color: #0000FF;">>=<span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #000000;">new_pos<span style="color: #0000FF;"><=<span style="color: #000000;">16</span>
if new_pos>=1 and new_pos<=16
<span style="color: #008080;">and</span> <span style="color: #0000FF;">(<span style="color: #7060A8;">mod<span style="color: #0000FF;">(<span style="color: #000000;">pos<span style="color: #0000FF;">,<span style="color: #000000;">4<span style="color: #0000FF;">)<span style="color: #0000FF;">=<span style="color: #7060A8;">mod<span style="color: #0000FF;">(<span style="color: #000000;">new_pos<span style="color: #0000FF;">,<span style="color: #000000;">4<span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- same col, or row:</span>
and (mod(pos,4)=mod(new_pos,4) -- same col, or row:
<span style="color: #008080;">or</span> <span style="color: #7060A8;">floor<span style="color: #0000FF;">(<span style="color: #0000FF;">(<span style="color: #000000;">pos<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: #7060A8;">floor<span style="color: #0000FF;">(<span style="color: #0000FF;">(<span style="color: #000000;">new_pos<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> <span style="color: #008080;">then</span>
or floor((pos-1)/4)=floor((new_pos-1)/4)) then
<span style="color: #0000FF;">{<span style="color: #000000;">board<span style="color: #0000FF;">[<span style="color: #000000;">pos<span style="color: #0000FF;">]<span style="color: #0000FF;">,<span style="color: #000000;">board<span style="color: #0000FF;">[<span style="color: #000000;">new_pos<span style="color: #0000FF;">]<span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{<span style="color: #000000;">board<span style="color: #0000FF;">[<span style="color: #000000;">new_pos<span style="color: #0000FF;">]<span style="color: #0000FF;">,<span style="color: #000000;">0<span style="color: #0000FF;">}</span>
{board[pos],board[new_pos]} = {board[new_pos],0}
<span style="color: #000000;">pos</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">new_pos</span>
pos = new_pos
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
end procedure
<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;">5</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> <span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
for i=1 to 5 do move(rand(4)) end for
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
while 1 do
<span style="color: #000000;">print_board<span style="color: #0000FF;">(<span style="color: #0000FF;">)</span>
print_board()
<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: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
if board=solve then exit end if
<span style="color: #004080;">integer</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find<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: #000000;">UP<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: #000000;">DOWN<span style="color: #0000FF;">}<span style="color: #0000FF;">)<span style="color: #0000FF;">-<span style="color: #000000;">1</span>
integer c = find(wait_key(),{ESC,UP,LEFT,RIGHT,DOWN})-1
<span style="color: #008080;">if</span> <span style="color: #000000;">c<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>
if c=0 then exit end if
<span style="color: #000000;">move<span style="color: #0000FF;">(<span style="color: #000000;">c<span style="color: #0000FF;">)</span>
move(c)
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
end while
<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;">)
puts(1,"solved!\n")
<!--</lang>-->
</syntaxhighlight>
{{out}}
<pre>
Line 6,604 ⟶ 9,413:
solved!
</pre>
 
=== GUI version ===
{{libheader|Phix/pGUI}}
{{libheader|Phix/online}}
You can run this online [http://phix.x10.mx/p2js/15game.htm here].
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">--
-- demo\rosetta\15_puzzle_game.exw
-- ===============================
--</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">title</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"15 puzzle"</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">help_text</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"""
Put the tiles back into order 1..15 and the hole last.
Rightarrow moves the tile to the left of the hole (rightwards) into it.
Leftarrow moves the tile to the right of the hole (leftwards) into it.
Uparrow moves the tile below the hole (upwards) into it.
Downarrow moves the tile above the hole (downwards) into it.
Press 'N' to start a new game.
"""</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">show_help</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupMessage</span><span style="color: #0000FF;">(</span><span style="color: #000000;">title</span><span style="color: #0000FF;">,</span><span style="color: #000000;">help_text</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bWrap</span><span style="color: #0000FF;">:=</span><span style="color: #004600;">false</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_IGNORE</span> <span style="color: #000080;font-style:italic;">-- (don't open browser help!)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">dialog</span>
<span style="color: #004080;">cdCanvas</span> <span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">solved</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #000000;">15</span><span style="color: #0000FF;">)&</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">board</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">pos</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">move</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">d</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">d</span><span style="color: #0000FF;">=</span><span style="color: #000000;">5</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- new game</span>
<span style="color: #000000;">board</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">solved</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">pos</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">16</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1000</span> <span style="color: #008080;">do</span> <span style="color: #000000;">move</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">4</span><span style="color: #0000FF;">))</span> <span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">d</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">new_pos</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">pos</span><span style="color: #0000FF;">+{+</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">4</span><span style="color: #0000FF;">}[</span><span style="color: #000000;">d</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">new_pos</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #000000;">new_pos</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">16</span>
<span style="color: #008080;">and</span> <span style="color: #0000FF;">(</span><span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pos</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">)=</span><span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">new_pos</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- same col, or row:</span>
<span style="color: #008080;">or</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #000000;">pos</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">4</span><span style="color: #0000FF;">)=</span><span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #000000;">new_pos</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">4</span><span style="color: #0000FF;">))</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">pos</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">new_pos</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">new_pos</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #000000;">pos</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">new_pos</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #000000;">move</span><span style="color: #0000FF;">(</span><span style="color: #000000;">5</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- new game</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">redraw_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">dw</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dh</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetIntInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DRAWSIZE"</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">ox</span><span style="color: #0000FF;">,</span><span style="color: #000000;">oy</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- top right coords</span>
<span style="color: #000000;">os</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ts</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- overall and tile size</span>
<span style="color: #000000;">ht</span> <span style="color: #000080;font-style:italic;">-- half tile, for number positioning</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">dw</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">dh</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">ox</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #000000;">dw</span><span style="color: #0000FF;">-</span><span style="color: #000000;">dh</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">oy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #000000;">os</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dh</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">ox</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #000000;">oy</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #000000;">dh</span><span style="color: #0000FF;">-</span><span style="color: #000000;">dw</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">os</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dw</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">ts</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #000000;">os</span><span style="color: #0000FF;">-</span><span style="color: #000000;">10</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">4</span><span style="color: #0000FF;">-</span><span style="color: #000000;">7</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">ht</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ts</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">+</span><span style="color: #000000;">5</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">10</span>
<span style="color: #7060A8;">cdCanvasActivate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasSetBackground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">#FAF8EF</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasClear</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasSetForeground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">#BBADA0</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasRoundedBox</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ox</span><span style="color: #0000FF;">+</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ox</span><span style="color: #0000FF;">+</span><span style="color: #000000;">os</span><span style="color: #0000FF;">-</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">oy</span><span style="color: #0000FF;">+</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">oy</span><span style="color: #0000FF;">+</span><span style="color: #000000;">os</span><span style="color: #0000FF;">-</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">tx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ox</span><span style="color: #0000FF;">+</span><span style="color: #000000;">15</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ty</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">oy</span><span style="color: #0000FF;">+</span><span style="color: #000000;">15</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">bxy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">board</span><span style="color: #0000FF;">[(</span><span style="color: #000000;">4</span><span style="color: #0000FF;">-</span><span style="color: #000000;">x</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">4</span><span style="color: #0000FF;">+</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span>
<span style="color: #7060A8;">cdCanvasSetForeground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">#EEE4DA</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasRoundedBox</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tx</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">ts</span><span style="color: #0000FF;">-</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ty</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ty</span><span style="color: #0000FF;">+</span><span style="color: #000000;">ts</span><span style="color: #0000FF;">-</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">bxy</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">cdCanvasSetForeground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">#776E65</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasFont</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"Calibri"</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_BOLD</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">32</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasText</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">ht</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ty</span><span style="color: #0000FF;">+</span><span style="color: #000000;">ht</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">sprint</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bxy</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">ty</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">ts</span><span style="color: #0000FF;">+</span><span style="color: #000000;">5</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">tx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">ts</span><span style="color: #0000FF;">+</span><span style="color: #000000;">5</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">cdCanvasFlush</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">fmt</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">==</span><span style="color: #000000;">solved</span><span style="color: #0000FF;">?</span><span style="color: #008000;">"%s - solved"</span><span style="color: #0000FF;">:</span><span style="color: #008000;">"%s"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetStrAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dialog</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"TITLE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fmt</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">title</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">map_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">cdcanvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_IUP</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">cddbuffer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_DBUFFER</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasSetTextAlignment</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_CENTER</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">key_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_ESC</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CLOSE</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- (standard practice for me)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_F5</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- (let browser reload work)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_F1</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">show_help</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">move</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">upper</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">),{</span><span style="color: #004600;">K_UP</span><span style="color: #0000FF;">,</span><span style="color: #004600;">K_LEFT</span><span style="color: #0000FF;">,</span><span style="color: #004600;">K_RIGHT</span><span style="color: #0000FF;">,</span><span style="color: #004600;">K_DOWN</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'N'</span><span style="color: #0000FF;">}))</span>
<span style="color: #7060A8;">IupUpdate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_IGNORE</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">canvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupCanvas</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"RASTERSIZE=520x540"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetCallbacks</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"MAP_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"map_cb"</span><span style="color: #0000FF;">),</span>
<span style="color: #008000;">"ACTION"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"redraw_cb"</span><span style="color: #0000FF;">)})</span>
<span style="color: #000000;">dialog</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`TITLE="%s",MINSIZE=440x450`</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">title</span><span style="color: #0000FF;">})</span>
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dialog</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"KEY_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"key_cb"</span><span style="color: #0000FF;">));</span>
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dialog</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"RASTERSIZE"</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">NULL</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetAttributeHandle</span><span style="color: #0000FF;">(</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"PARENTDIALOG"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dialog</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<!--</syntaxhighlight>-->
 
=={{header|PHP}}==
OOP and MVC design pattern has been used to facilitate any improvements, e.g. tiles with graphics instead of just numbers.
<langsyntaxhighlight PHPlang="php"><?php
// Puzzle 15 Game - Rosseta Code - PHP 7 as the server-side script language.
 
Line 6,777 ⟶ 9,717:
else
echo "<span class='puzzle'></span>";
}
echo "<br>";
}
Line 6,832 ⟶ 9,772:
?></p>
</body>
</html></langsyntaxhighlight>
 
=={{header|Picat}}==
<syntaxhighlight lang="picat">
import util.
 
main =>
Board = {{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}},
Goal = copy_term(Board),
shuffle(Board),
play(Board,Goal).
 
shuffle(Board) =>
foreach (_ in 1..1000)
R1 = random() mod 4 + 1,
C1 = random() mod 4 + 1,
R2 = random() mod 4 + 1,
C2 = random() mod 4 + 1,
T := Board[R1,C1],
Board[R1,C1] := Board[R2,C2],
Board[R2,C2] := T
end.
 
play(Board,Goal) =>
while (Board != Goal)
print_board(Board),
possible_moves(Board,R0,C0,Moves),
printf("Possible moves are: %w, 0 to exit. Your move? => ", Moves),
S = read_line().strip(),
if S == "0" || S == "" then
halt
else
move_hole(Board,R0,C0,to_int(S))
end
end,
print_board(Board),
println("Puzzle solved.").
 
print_board(Board) =>
N = len(Board),
print("+----+----+----+----+\n"),
foreach (R in 1..N)
print("|"),
foreach (C in 1..N)
printf("%4d|", Board[R,C])
end,
nl
end,
println("+----+----+----+----+").
 
possible_moves(Board,R0,C0,Moves) =>
N = len(Board),
between(1,N,R0),
between(1,N,C0),
Board[R0,C0] == 0, !,
NeibsOfHole = [(R1,C1) : (R1,C1) in [(R0-1,C0), (R0+1,C0), (R0,C0-1), (R0,C0+1)], R1 >= 1, R1 =< N, C1 >= 1, C1 =< N],
Moves = sort([Board[R,C] : (R,C) in NeibsOfHole]).
 
move_hole(Board,R0,C0,S) =>
N = len(Board),
between(1,N,R),
between(1,N,C),
Board[R,C] == S, !,
Board[R0,C0] := S,
Board[R,C] := 0.
</syntaxhighlight>
 
=={{header|Powershell}}==
Line 6,839 ⟶ 9,847:
Board is always scrambled from a solved board so it's always solvable.
Written in ISE with ISESteroids. I'm sure the code could be improved on.
<syntaxhighlight lang="powershell">
<lang Powershell>
#15 Puzzle Game
$Script:Neighbours = @{
Line 7,099 ⟶ 10,107:
# Show Window
$result = Show-WPFWindow -Window $window
</syntaxhighlight>
</lang>
 
=={{header|Processing}}==
<langsyntaxhighlight lang="java">
int number_of_grid_cells = 16; // Set the number of cells of the board here 9, 16, 25 etc
color piece_color = color(255, 175, 0);
Line 7,216 ⟶ 10,224:
}
}
}</langsyntaxhighlight>
 
'''It can be played on line''' :<BR> [https://www.openprocessing.org/sketch/863055/ here.]
Line 7,222 ⟶ 10,230:
==={{header|Processing Python mode}}===
{{trans|Processing}}
<langsyntaxhighlight Pythonlang="python"># Set the number of cells of the board here 9, 16, 25 etc
num_grid_cells = 16
piece_color = color(255, 175, 0)
Line 7,332 ⟶ 10,340:
# Upper bright
line(self.x + 2, self.y + 1, self.x +
piece_side_length - 1, self.y + 1)</langsyntaxhighlight>
 
 
=={{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 7,338 ⟶ 10,456:
Numbers are displayed in Hexadecimal (ie 1 to F)
Default controls are u,d,l,r
<syntaxhighlight lang="purebasic">
<lang PureBasic>
#difficulty=10 ;higher is harder
#up="u"
Line 7,408 ⟶ 10,526:
Print("Won !")
CloseConsole()
</syntaxhighlight>
</lang>
<pre>
1234
Line 7,422 ⟶ 10,540:
{{works with|Python|3.X}}
'''unoptimized'''
<langsyntaxhighlight lang="python">
''' Structural Game for 15 - Puzzle with different difficulty levels'''
from random import randint
Line 7,547 ⟶ 10,665:
print('You WON')
break
</syntaxhighlight>
</lang>
<pre>
Enter the difficulty : 0 1 2
Line 7,581 ⟶ 10,699:
 
===Python: using tkinter===
<langsyntaxhighlight lang="python">
''' Python 3.6.5 code using Tkinter graphical user interface.'''
 
Line 7,831 ⟶ 10,949:
g = Game(root)
root.mainloop()
</syntaxhighlight>
</lang>
 
=={{header|QB64}}==
<syntaxhighlight lang="qb64">
<lang QB64>
_TITLE "GUI Sliding Blocks Game "
RANDOMIZE TIMER
Line 7,918 ⟶ 11,036:
END IF
LOOP
</syntaxhighlight>
</lang>
 
=={{header|Quackery}}==
The inputs are w,s,a,d and they refer to the direction in which the empty place "moves". After every prompt you can input a string of characters and submit them by pressing enter. Any characters other than w,s,a,d will be ignored, and moves will be performed according to the correct commands. Commands that would "move" the empty space off the edge of the puzzle are also ignored. For example, on a solved puzzle "asgw" would move 15 to the right, ignore 's' and 'g' and move 11 down.
<syntaxhighlight lang="quackery">
( moves: 0 - up, 1 - down, 2 - left, 3 - right )
 
[ stack ] is 15.solver ( --> [ )
 
[ 0 swap find ] is find-empty ( board --> n )
 
[ over + dup -1 >
over 4 < and iff
[ nip true ] else
[ drop false ] ] is try-nudge ( coord delta --> coord ? )
 
[ dip [ dup find-empty 4 /mod ]
2 /mod 2 * 1 -
swap iff try-nudge else
[ dip swap
try-nudge
dip swap ]
dip [ swap 4 * + ] ] is try-move-target ( board move --> board target ? )
 
[ 2dup peek dip
[ -1 unrot poke
0 over find ]
unrot poke
0 swap -1 over find poke ] is move-to ( board target --> board )
 
[ try-move-target
iff [ move-to true ]
else [ drop false ] ] is try-move ( board move --> board ? )
 
[ [] 15 times
[ i^ 1+ join ]
0 join ] constant is <board> ( --> board )
 
[ <board>
410 times ( 2 * the upper bound on the maximum moves required to solve )
[ 4 random
try-move drop ] ] is <random-board> ( --> board )
 
[ peek dup iff
[ number$
dup size 1 =
if [ space swap join ] ]
else [ drop $ ' ' ]
echo$ ] is echo-cell ( board n --> )
 
[ 4 * 4 times
[ say '| '
2dup i^ +
echo-cell
say ' ' ]
say '|'
2drop ] is echo-row ( board n --> )
 
[ 4 times
[ say '+----+----+----+----+' cr
dup i^ echo-row cr ]
say '+----+----+----+----+' cr
drop ] is echo-board ( board --> )
 
[ <board> = ] is solved? ( board --> ? )
 
[ $ 'Moves: ' input ] is input-moves ( --> $ )
 
[ dup char w = iff
[ drop 0 true ] done
dup char s = iff
[ drop 1 true ] done
dup char a = iff
[ drop 2 true ] done
dup char d = iff
[ drop 3 true ] done
false ] is char-to-move ( c --> move true | c false )
 
[ input-moves witheach
[ char-to-move
if try-move
drop ] ] is player-move ( board --> board )
 
[ ]'[ 15.solver put
[ cr dup echo-board
dup solved? not while
15.solver share do
again ]
15.solver release drop ] is 15-solve-with ( board 'solver --> board )
 
[ <random-board>
15-solve-with player-move ] is 15-puzzle ( --> )
 
15-puzzle
</syntaxhighlight>
 
=={{header|R}}==
The inputs are w,a,s,d and they refer to the direction in which the adjacent piece moves into the empty space. For example, on a solved puzzle, "d" would move the 15 to the right.
<syntaxhighlight lang="r">
<lang R>
puz15<-function(scramble.length=100){
m=matrix(c(1:15,0),byrow=T,ncol=4)
Line 8,011 ⟶ 11,223:
}
}
</syntaxhighlight>
</lang>
 
Sample output:
Line 8,058 ⟶ 11,270:
It uses the <code>2htdp/universe</code> package.
 
<langsyntaxhighlight lang="racket">#lang racket/base
(require 2htdp/universe 2htdp/image racket/list racket/match)
 
Line 8,106 ⟶ 11,318:
(to-draw (fifteen->pict))
(stop-when solved-world? (fifteen->pict #t))
(on-key key-move-space))</langsyntaxhighlight>
 
=={{header|Raku}}==
Line 8,112 ⟶ 11,324:
{{works with|Rakudo|2018.06}}
Most of this is interface code. Reused substantial portions from the [[2048#Raku|2048]] task. Use the arrow keys to slide tiles, press 'q' to quit or 'n' for a new puzzle. Requires a POSIX termios aware terminal. Ensures that the puzzle is solvable by shuffling the board with an even number of swaps, then checking for even taxicab parity for the empty space.
<syntaxhighlight lang="raku" perl6line>use Term::termios;
 
constant $saved = Term::termios.new(fd => 1).getattr;
Line 8,160 ⟶ 11,372:
for (^16).pick(*) -> $y, $x {
my ($yd, $ym, $xd, $xm) = ($y div n, $y mod n, $x div n, $x mod n);
my @(@c[$temp ym;$yd],@c[$xm;$xd]) = @(@c[$xm;$xd],@c[$ym;$yd]);
@c[$ym;$yd] = @c[$xm;$xd];
@c[$xm;$xd] = $temp;
}
@c;
Line 8,228 ⟶ 11,438:
last if $key eq 'q'; # (q)uit
new() if $key eq 'n';
}</langsyntaxhighlight>
Sample screen shot:
<pre>
Line 8,247 ⟶ 11,457:
 
=={{header|Rebol}}==
<langsyntaxhighlight Rebollang="rebol">rebol [] random/seed now g: [style t box red [
if not find [0x108 108x0 0x-108 -108x0] face/offset - e/offset [exit]
x: face/offset face/offset: e/offset e/offset: x] across
] x: random repeat i 15 [append x:[] i] repeat i 15 [
repend g ['t mold x/:i random white] if find [4 8 12] i [append g 'return]
] append g [e: box] view layout g</langsyntaxhighlight>
 
=={{header|Red}}==
<syntaxhighlight lang="red">
<lang Red>
Red [Needs: 'view]
system/view/screens/1/pane/-1/visible?: false ;; suppress console window
Line 8,321 ⟶ 11,531:
view lay
 
</syntaxhighlight>
</lang>
 
=={{header|REXX}}==
This REXX version allows the user to specify the size of the puzzle &nbsp; ('''N''', &nbsp; where &nbsp; '''NxN''' &nbsp; is the size of the puzzle).
 
With some more complexity, &nbsp; the REXX computer program could be changed to allow multiple-tilemultiple─tile moves &nbsp; (so that, for instance, three tiles could be slid to the right).
<br>for instance, &nbsp; three tiles could be slid to the right).
 
Over half of the REXX program has to do with input validation and presentation of the puzzle (grid).
<langsyntaxhighlight lang="rexx">/*REXX pgm implements the 15─puzzle (AKA: Gem Puzzle, Boss Puzzle, Mystic Square, 14─15)*/
parse arg N seed . /*obtain optional arguments from the CL*/
if N=='' | N=="," then N=4 /*Not specified? Then use the default.*/
Line 8,353 ⟶ 11,564:
 
call showGrid 1; say; say sep 'Congratulations! The' nn"-puzzle is solved."
exit 0 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
getmv: x= 0; sep= copies('─', 8); pad= left('', 1 + length(sep) ) /*pad=9 blanks*/
prompt= sep 'Please enter a tile number or numbers ' sep " (or Quit)."
if queued()==0 then do; say; call showGrid 1; say; say prompt
Line 8,392 ⟶ 11,603:
rm=holeRow-1; rp=holeRow+1; cm=holeCol-1; cp=holeCol+1 /*possible moves.*/
!=!.rm.holeCol !.rp.holeCol !.holeRow.cm !.holeRow.cp /* legal moves.*/
if show then say pad bot; return</langsyntaxhighlight>
{{out|output|text=&nbsp; when using the default input:}}
<pre>
Line 8,438 ⟶ 11,649:
=={{header|Ring}}==
 
<langsyntaxhighlight lang="ring">
# Project : CalmoSoft Fifteen Puzzle Game
/* ------------------------------------------------------------------------------------------------------
# Date : 2018/12/01
# Author : Gal Zsolt (CalmoSoft), Bert Mariani
# Email : calmosoft@gmail.com
 
load "guilib.ring"
Copyright (c) 2004 - Gal Zsolt (CalmoSoft)
 
app1 = new qapp {
------------------------------------------------------------------------------------------------------ */
 
stylefusionblack()
implement playDialog
empty = 16
open core, vpiDomains, vpiOldDomains, resourceIdentifiers
nr_moves = 0
nr_sleep = 1
button_size = 4
current_button = 4
temp = 0
flag_init = 0
flag_save = 0
flag_move = 0
button = list(52)
size_button = list(7)
table1 = []
table2 = []
table3 = []
n_degree = 0
nr_degree = [0,90,180,270 ,-90,-180,-270]
n_degreeRight = 0
n_degreeLeft = 0
btn_degree = newlist(52,2)
counter_man = 0
t1 = 0
 
win1 = new qwidget() {
facts
move(0,0)
thisWin : vpiDomains::windowHandle := erroneous.
resize(380,760)
setwindowtitle("CalmoSoft Fifteen Puzzle Game")
 
for n=1 to 52
clauses
show(Parent):- for m=1 to 2
btn_degree[n][m] = 0
_ = vpi::winCreateDynDialog(Parent, controlList, eventHandler, gui_api::lNull).
next
next
 
for n = 4 to 7
/* ------------------------------------------------------------------------------------------------------ */
size_button[n] = new qpushbutton(win1)
{
col = n%4
setgeometry(100+col*40,60,40,40)
settext(string(n) + "x" + string(n))
setclickevent("newsize(" + string(n) + ")")
}
next
 
btnMoves = new qpushbutton(win1)
predicates
eventHandler : vpiDomains::ehandler. {
setgeometry(100,260,80,40)
clauses
settext("0")
eventHandler(Win, Event) = Result :-
Result = generatedEventHandler(Win, Event show().
}
 
scramblebtn = new qpushbutton(win1)
/* ------------------------------------------------------------------------------------------------------ */
{
setgeometry(100,300,160,40)
settext("Scramble")
setclickevent("scramble()")
}
 
resetbtn = new qpushbutton(win1)
{
setgeometry(100,340,160,40)
settext("Reset")
setclickevent("resettiles()")
}
 
savebtn = new qpushbutton(win1)
predicates
{
onDestroy : vpiOldDomains::destroyHandler.
setgeometry(100,380,160,40)
clauses
settext("Save Game")
onDestroy() = vpiOldDomains::defaultHandling() :-
thisWin := erroneous. setclickevent("pSave()")
}
 
playbtn = new qpushbutton(win1)
/* ------------------------------------------------------------------------------------------------------ */
{
setgeometry(100,420,160,40)
settext("Resume Game")
setclickevent("pPlay()")
}
 
sleepbtn = new qpushbutton(win1)
predicates
{
onControlCancel : vpiOldDomains::controlHandler.
setgeometry(100,460,160,40)
clauses
settext("Sleep Time: ")
onControlCancel(_Ctrl, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull) :-
file::save("game.dba",gameDB),
retractall(table(_,_)),
retractall(gameplay(_,_)),
retractall(empty_cell(_)),
retractall(cell(_,_)),
retractall(cellnr(_,_)),
retractall(good(_,_,_)),
vpi::winDestroy(thisWin).
 
}
/* ------------------------------------------------------------------------------------------------------ */
 
decbtn = new qpushbutton(win1)
predicates
onUpdate : vpiOldDomains::updateHandler. {
setgeometry(220,460,40,40)
clauses
settext("<-")
onUpdate(Rectangle) = vpiOldDomains::defaultHandling():-
setclickevent("pDecSleep()")
vpi::winClear( thisWin,Rectangle,0x808040),
!. }
 
incbtn = new qpushbutton(win1)
/* ------------------------------------------------------------------------------------------------------ */
{
setgeometry(260,460,40,40)
settext("->")
setclickevent("pIncSleep()")
}
 
rightbtn = new qpushbutton(win1)
class facts - gameDB
table:(integer,string). {
setgeometry(100,500,160,40)
gameplay:(integer,integer).
settext("In the Right Place : ")
empty_cell:(integer).
}
 
timebtn = new qpushbutton(win1)
class facts
{
cell:(integer,vpiDomains::windowHandle).
setgeometry(100,540,160,40)
cellnr:(integer,integer).
settext("Elapsed Time : ")
}
 
TimerMan = new qtimer(win1)
/* ------------------------------------------------------------------------------------------------------ */
{
setinterval(500)
settimeoutevent("pTime()")
stop()
}
newsize(4)
show()
}
exec()
}
 
Func newlist x, y
class facts
if isstring(x) step_nr:integer:x=0.+x ok
if isstring(y) y=0+y ok
alist = list(x)
for t in alist
t = list(y)
next
return alist
 
func scramble
predicates
for n= 1 to 1000
onCreate : vpiOldDomains::createHandler.
current_button=random(button_size*button_size-1)+1
clauses
up = (empty = (current_button - button_size))
onCreate(_CreationData) = vpiOldDomains::defaultHandling():-
retractalldown = (tableempty = (_,_current_button + button_size)),
left = ((empty = (current_button - 1)) and ((current_button % button_size) != 1))
retractall(gameplay(_,_)),
right = ((empty = (current_button + 1)) and ((current_button % button_size) != 0))
retractall(empty_cell(_)),
retractall(cell(_,_)),move = up or down or left or right
retractall(cellnr(_,_)),if move = 1
retractall button[current_button] { temp2 = text(good(_,_,_)), }
col = empty%button_size
if col = 0 col = button_size ok
row = ceil(empty/button_size)
button[empty] {
setgeometry(60+col*40,60+row*40,40,40)
rnd = random(6)+1
n_degree = nr_degree[rnd]
button[empty].setbuttoncolor("yellow")
button[empty].settext(temp2)
button[empty].setClickEvent("movetile(" + string(empty) +")")
btn_degree[empty] [1] = temp2
btn_degree[empty] [2] = n_degree
}
button[current_button].setbuttoncolor("yellow")
btn_degree[current_button][2] = 0
button[current_button]{settext("")}
empty = current_button
ok
next
button[button_size*button_size+2]{settext("Here")}
for n=1 to button_size*button_size
button[n].setbuttoncolor("yellow")
next
table1 = []
table2 = []
table3 = []
for n = 1 to button_size*button_size
add(table1, button[n].text())
add(table2, button[n].text())
add(table3, string(btn_degree[n][2]))
next
add(table1, string(empty))
add(table2, string(empty))
add(table3, string(empty))
add(table1, "OK")
add(table2, "OK")
add(table3, "OK")
flag_save = 0
flag_move = 0
nr_moves = 0
btnMoves.settext(string(nr_moves))
timebtn.settext("Elapsed Time : ")
t1 = clock()
rightPlace()
return
 
func movetile current_button2
scrollbars_init(),
if (current_button2 = button_size*button_size-1 and button[current_button2].text() = "In")
cellhandle_init(),
empty:=16,pBack()
good_cell(0),else
see table_savechar(7),
up = (empty = (current_button2 - button_size))
step_nr:=0,
down fail.= (empty = (current_button2 + button_size))
left = ((empty = (current_button2- 1)) and ((current_button2 % button_size) != 1))
onCreate(_CreationData) = vpiOldDomains::defaultHandling().
right = ((empty = (current_button2 + 1)) and ((current_button2 % button_size) != 0))
move = up or down or left or right
if move = 1
temp2 = button[current_button2].text()
btn_degree[empty][1] = temp2
add(table1, temp2)
add(table2, string(current_button2))
col = empty%button_size
if col = 0 col = button_size ok
row = ceil(empty/button_size)
button[empty] {
setgeometry(60+col*40,60+row*40,40,40)
n_degree = btn_degree[current_button2][2]
btn_degree[empty][2] = n_degree
button[empty].setbuttoncolor("orange")
button[empty].settext(temp2)
}
add(table3, string(n_degree))
button[current_button2].setbuttoncolor("cyan")
button[current_button2]{settext("")}
empty = current_button2
nr_moves = nr_moves + 1
btnMoves.settext(string(nr_moves))
isGameOver()
ok
ok
flag_move = 1
pElapsedTime()
rightPlace()
return
 
func resettiles
/* ------------------------------------------------------------------------------------------------------ */
n_degree = 0
empty = button_size*button_size
for empty = 1 to button_size*button_size-1
btn_degree[empty][2] = 0
n_degree = 0
btn_degree[empty][1] = string(empty)
button[empty].setstylesheet("background-color:yellow")
button[empty] {settext(string(empty))}
next
button[button_size*button_size].setstylesheet("background-color:yellow")
button[button_size*button_size] {settext("")}
table1 = []
table2 = []
table3 = []
for n = 1 to button_size*button_size
add(table1, button[n].text())
add(table2, button[n].text())
add(table3, string(btn_degree[n][2]))
next
add(table1, string(empty))
add(table2, string(empty))
add(table3, string(empty))
add(table1, "OK")
add(table2, "OK")
add(table3, "OK")
flag_save = 0
flag_move = 0
nr_moves = 0
btnMoves.settext(string(nr_moves))
timebtn.settext("Elapsed Time : ")
t1 = clock()
rightPlace()
return
 
func pHere
facts
if button[button_size*button_size-1].text() != "" and button[button_size*button_size+2].text() = "Here"
vsbarr : vpiDomains::windowHandle := erroneous.
button[button_size*button_size-1] { temp = text() }
vsbarl : vpiDomains::windowHandle := erroneous.
button[button_size*button_size+2].close()
hsbart : vpiDomains::windowHandle := erroneous.
button[button_size*button_size+2] = new ButtonWithRotatedText(win1)
hsbarb : vpiDomains::windowHandle := erroneous.
button[button_size*button_size+2] {
setgeometry(60+(button_size-1)*40,60+(button_size+1)*40,40,40)
setstylesheet("background-color:yellow")
btn_degree[button_size*button_size+2][2] = btn_degree[button_size*button_size-1][2]
n_degree = btn_degree[button_size*button_size+2][2]
emptysave = empty
empty = button_size*button_size+2
btn_degree[empty][1] = temp
settext(temp)
}
n_degree = 0
empty = button_size*button_size-1
btn_degree[empty][1] = "In"
button[button_size*button_size-1]{settext("In")}
for n = 1 to button_size*button_size
button[n].setenabled(false)
next
button[button_size*button_size-1].setenabled(true)
scramblebtn.setenabled(false)
resetbtn.setenabled(false)
savebtn.setenabled(false)
playbtn.setenabled(false)
empty = emptysave
ok
 
func pBack
predicates
button[button_size*button_size+2] { temp = text() }
scrollbars_init:().
n_degree = btn_degree[button_size*button_size+2][2]
clauses
btn_degree[button_size*button_size-1][2] = btn_degree[button_size*button_size+2][2]
scrollbars_init():-
emptysave = empty
vsbarr := vpi::winGetCtlHandle(thisWin,idc_sbvr),
empty = button_size*button_size-1
vsbarl := vpi::winGetCtlHandle(thisWin,idc_sbvl),
btn_degree[empty][1] = temp
hsbart := vpi::winGetCtlHandle(thisWin,idc_sbht),
button[button_size*button_size-1] {settext(temp)}
hsbarb := vpi::winGetCtlHandle(thisWin,idc_sbhb),
button[button_size*button_size+2].close()
button[button_size*button_size+2] = new qpushbutton(win1)
{
setgeometry(60+(button_size-1)*40,60+(button_size+1)*40,40,40)
settext("Here")
setclickevent("pHere()")
show()
}
for n = 1 to button_size*button_size
button[n].setenabled(true)
next
scramblebtn.setenabled(true)
resetbtn.setenabled(true)
savebtn.setenabled(true)
playbtn.setenabled(true)
empty = emptysave
isGameOver()
 
func rotateleft
if button[button_size*button_size+2].text() != "Here"
button[button_size*button_size+2].close()
button[button_size*button_size+2] = new ButtonWithRotatedText(win1)
button[button_size*button_size+2] {
setgeometry(60+(button_size-1)*40,60+(button_size+1)*40,40,40)
setstylesheet("background-color:yellow")
n_degreeLeft = (n_degreeLeft-90)%360
n_degree = n_degreeLeft
btn_degree[button_size*button_size+2][2] = n_degree
emptysave = empty
empty = button_size*button_size+2
btn_degree[empty][1] = temp
button[button_size*button_size+2]{settext(temp)}
}
empty = emptysave
ok
 
func rotateright
vpi::winSetScrollRange(vsbarr,sb_Ctl,1,4),
if button[button_size*button_size+2].text() != "Here"
vpi::winSetScrollProportion(vsbarr,sb_Ctl,1),
button[button_size*button_size+2].close()
vpi::winSetScrollPos(vsbarr,sb_Ctl,4),
button[button_size*button_size+2] = new ButtonWithRotatedText(win1)
button[button_size*button_size+2] {
setgeometry(60+(button_size-1)*40,60+(button_size+1)*40,40,40)
setstylesheet("background-color:yellow")
n_degreeRight = (n_degreeRight+90)%360
n_degree = n_degreeRight
btn_degree[button_size*button_size+2][2] = n_degree
emptysave = empty
empty = button_size*button_size+2
btn_degree[empty][1] = temp
button[button_size*button_size+2]{settext(temp)}
}
empty = emptysave
ok
 
func newsize current_button
vpi::winSetScrollRange(vsbarl,sb_Ctl,1,4),
win1{
vpi::winSetScrollProportion(vsbarl,sb_Ctl,1),
vpi::winSetScrollPos(vsbarl,sb_Ctl, sizenew = current_button%4),
win1.resize(360+sizenew*40,640+sizenew*40)
if flag_init != 0
for nb = 1 to button_size*button_size+3
button[nb] {close()}
next
btnMoves.close()
ok
scramblebtn.close()
resetbtn.close()
savebtn.close()
playbtn.close()
btnMoves.close()
sleepbtn.close()
decbtn.close()
incbtn.close()
rightbtn.close()
timebtn.close()
 
for n = 1 to current_button*current_button
vpi::winSetScrollRange(hsbart,sb_Ctl,1,4),
vpi::winSetScrollProportion(hsbart,sb_Ctl,1), col = n%current_button
vpi::winSetScrollPos(hsbart,sb_Ctl,4), if col = 0 col = current_button ok
row = ceil(n/current_button)
button[n] = new ButtonWithRotatedText(win1)
button[n] {
setgeometry(60+col*40,60+row*40,40,40)
button[n].setbuttoncolor("yellow")
n_degree = 0
if n < current_button*current_button
button[n].settext(string(n))
but n = current_button*current_button
button[n].settext("")
ok
setClickEvent("movetile(" + string(n) +")")
}
next
 
vpi::winSetScrollRange btnMoves = new qpushbutton(hsbarb,sb_Ctl,1,4win1),
vpi::winSetScrollProportion(hsbarb,sb_Ctl,1), {
setgeometry(100,60+(current_button+1)*40,(current_button-3)*40,40)
vpi::winSetScrollPos(hsbarb,sb_Ctl,4).
setStyleSheet("text-align:center")
settext("0")
show()
}
 
button[current_button*current_button+1] = new qpushbutton(win1)
/* ------------------------------------------------------------------------------------------------------ */
{
setgeometry(60+(current_button-2)*40,60+(current_button+1)*40,40,40)
settext("<-")
setclickevent("rotateLeft()")
show()
}
 
button[current_button*current_button+2] = new qpushbutton(win1)
class facts
cell1 : vpiDomains::windowHandle := erroneous. {
setgeometry(60+(current_button-1)*40,60+(current_button+1)*40,40,40)
cell2 : vpiDomains::windowHandle := erroneous.
settext("Here")
cell3 : vpiDomains::windowHandle := erroneous.
setclickevent("pHere()")
cell4 : vpiDomains::windowHandle := erroneous.
show()
cell5 : vpiDomains::windowHandle := erroneous.
cell6 : vpiDomains::windowHandle := erroneous. }
cell7 : vpiDomains::windowHandle := erroneous.
cell8 : vpiDomains::windowHandle := erroneous.
cell9 : vpiDomains::windowHandle := erroneous.
cell10 : vpiDomains::windowHandle := erroneous.
cell11 : vpiDomains::windowHandle := erroneous.
cell12 : vpiDomains::windowHandle := erroneous.
cell13 : vpiDomains::windowHandle := erroneous.
cell14 : vpiDomains::windowHandle := erroneous.
cell15 : vpiDomains::windowHandle := erroneous.
cell16 : vpiDomains::windowHandle := erroneous.
 
button[current_button*current_button+3] = new qpushbutton(win1)
predicates
cell_handle:(). {
setgeometry(60+current_button*40,60+(current_button+1)*40,40,40)
clauses
settext("->")
cell_handle():-
setclickevent("rotateRight()")
cell1:=vpi::winGetCtlHandle(thisWin,idc_cell1),
cell2:=vpi::winGetCtlHandle show(thisWin,idc_cell2),
cell3:=vpi::winGetCtlHandle(thisWin,idc_cell3), }
cell4:=vpi::winGetCtlHandle(thisWin,idc_cell4),
cell5:=vpi::winGetCtlHandle(thisWin,idc_cell5),
cell6:=vpi::winGetCtlHandle(thisWin,idc_cell6),
cell7:=vpi::winGetCtlHandle(thisWin,idc_cell7),
cell8:=vpi::winGetCtlHandle(thisWin,idc_cell8),
cell9:=vpi::winGetCtlHandle(thisWin,idc_cell9),
cell10:=vpi::winGetCtlHandle(thisWin,idc_cell10),
cell11:=vpi::winGetCtlHandle(thisWin,idc_cell11),
cell12:=vpi::winGetCtlHandle(thisWin,idc_cell12),
cell13:=vpi::winGetCtlHandle(thisWin,idc_cell13),
cell14:=vpi::winGetCtlHandle(thisWin,idc_cell14),
cell15:=vpi::winGetCtlHandle(thisWin,idc_cell15),
cell16:=vpi::winGetCtlHandle(thisWin,idc_cell16).
 
scramblebtn = new qpushbutton(win1)
/* ------------------------------------------------------------------------------------------------------ */
{
setgeometry(100,100+(current_button+1)*40,current_button*40,40)
settext("Scramble")
setclickevent("scramble()")
show()
}
 
resetbtn = new qpushbutton(win1)
predicates
cellhandle_init:(). {
setgeometry(100,100+(current_button+2)*40,current_button*40,40)
clauses
settext("Reset")
cellhandle_init():-
retractall setclickevent(cell"resettiles(_,_)"),
cell_handle show(),
}
 
assert savebtn = new qpushbutton(cell(1,cell1)win1),
assert(cell(2,cell2)), {
setgeometry(100,100+(current_button+3)*40,current_button*40,40)
assert(cell(3,cell3)),
assert settext(cell(4,cell4)"Save Game"),
assert setclickevent(cell"pSave(5,cell5)"),
assert show(cell(6,cell6)),
assert(cell(7,cell7)), }
assert(cell(8,cell8)),
assert(cell(9,cell9)),
assert(cell(10,cell10)),
assert(cell(11,cell11)),
assert(cell(12,cell12)),
assert(cell(13,cell13)),
assert(cell(14,cell14)),
assert(cell(15,cell15)),
assert(cell(16,cell16)).
 
playbtn = new qpushbutton(win1)
/* ------------------------------------------------------------------------------------------------------ */
{
setgeometry(100,100+(current_button+4)*40,current_button*40,40)
settext("Resume Game")
setclickevent("pPlay()")
show()
}
 
sleepbtn = new qpushbutton(win1)
class facts
good_nr:integer:=0. {
setgeometry(100,100+(current_button+5)*40,(current_button-2)*40,40)
good:(integer,integer,integer) nondeterm.
settext("Sleep Time: " + string(nr_sleep) + " s")
empty:integer:=16.
show()
}
 
decbtn = new qpushbutton(win1)
predicates
good_cell:(integer) multi. {
setgeometry(100+(current_button-2)*40,100+(current_button+5)*40,40,40)
clauses
good_cell settext(16):"<-!.")
setclickevent("pDecSleep()")
good_cell(Number):-
NumberNew = Number+1, show()
good_nr:=0, }
good_above(NumberNew), % movable cells above empty cell
good_before(NumberNew), % movable cells before empty cell
good_after(NumberNew), % movable cells after empty cell
good_under(NumberNew), % movable cells under empty cell
assert(cellnr(NumberNew,good_nr)), % number of movable cells around the empty cell
good_cell(NumberNew).
 
incbtn = new qpushbutton(win1)
/* ------------------------------------------------------------------------------------------------------ */
{
setgeometry(100+(current_button-1)*40,100+(current_button+5)*40,40,40)
settext("->")
setclickevent("pIncSleep()")
show()
}
 
rightbtn = new qpushbutton(win1)
predicates
good_above:(integer). {
setgeometry(100,100+(current_button+6)*40,current_button*40,40)
clauses
settext("In the Right Place : ")
good_above(Number):-
Number > 4, % movable cells above empty cellshow()
good_nr:= good_nr+1, }
assert(good(Number,good_nr,Number-4)),
fail.
good_above(_).
 
timebtn = new qpushbutton(win1)
/* ------------------------------------------------------------------------------------------------------ */
{
setgeometry(100,100+(current_button+7)*40,current_button*40,40)
settext("Elapsed Time : ")
show()
}
 
table1 = []
predicates
good_before:(integer). table2 = []
table3 = []
clauses
for n = 1 to button_size*button_size
good_before(Number):-
(Number mod 4) <> 1, add(table1, % movable cells before empty cellbutton[n].text())
good_nr:= good_nr+1 add(table2, button[n].text())
assert add(goodtable3, string(Number,good_nr,Number-10)),
fail. next
good_before add(_table1, string(empty)).
add(table2, string(empty))
add(table3, string(empty))
add(table1, "OK")
add(table2, "OK")
add(table3, "OK")
empty = current_button*current_button
button_size = current_button
flag_init = 1
flag_save = 0
flag_move = 0
nr_moves = 0
timebtn.settext("Elapsed Time : ")
t1 = clock()
scramble()
}
 
func pSave
/* ------------------------------------------------------------------------------------------------------ */
textedit1 = list2str(table1)
textedit2 = list2str(table2)
textedit3 = list2str(table3)
chdir(currentdir())
cName1 = "CalmoSoftPuzzle1.txt"
cName2 = "CalmoSoftPuzzle2.txt"
cName3 = "CalmoSoftPuzzle3.txt"
write(cName1,textedit1)
write(cName2,textedit2)
write(cName3,textedit3)
flag_save = 1
timebtn.settext("Elapsed Time : ")
t1 = clock()
return
 
func pPlay
predicates
if flag_save = 0 or flag_move = 0
good_after:(integer).
warning()
clauses
good_after(Number):-else
chdir(currentdir())
(Number mod 4) > 0, % movable cells after empty cell
cName1 good_nr:= good_nr+1,"CalmoSoftPuzzle1.txt"
textedit1 assert= read(good(Number,good_nr,Number+1)cName1),
table1 fail.= str2list(textedit1)
good_after(_) cName2 = "CalmoSoftPuzzle2.txt"
textedit2 = read(cName2)
table2 = str2list(textedit2)
cName3 = "CalmoSoftPuzzle3.txt"
textedit3 = read(cName3)
table3 = str2list(textedit3)
for empty = 1 to button_size*button_size
button[empty].setbuttoncolor("yellow")
n_degree = number(table3[empty])
btn_degree[empty][1] = table1[empty]
button[empty] {settext(table1[empty])}
next
empty = number(table1[button_size*button_size + 1])
counter_man = button_size*button_size+2
nr_moves = 0
t1 = clock()
TimerMan.start()
ok
 
func pTime()
/* ------------------------------------------------------------------------------------------------------ */
if flag_save = 0 or flag_move = 0
warning()
else
counter_man++
pPlaySleep()
sleep(nr_sleep*1000)
pElapsedTime()
if counter_man = len(table1)
TimerMan.stop()
ok
ok
 
func pPlaySleep
predicates
good_under:see char(integer7).
value = table1[counter_man]
clauses
good_under(Number):-place = table2[counter_man]
n_degree = number(table3[counter_man])
Number < 13, % movable cells under empty cell
btn_degree[empty][1] good_nr:= good_nr+1,value
button[empty].setbuttoncolor("orange")
assert(good(Number,good_nr,Number+4)),
button[empty] fail.{settext(value)}
good_under(_).n_degree = 0
button[number(place)].setbuttoncolor("cyan")
button[number(place)] {settext("")}
empty = number(place)
nr_moves = nr_moves + 1
btnMoves.settext(string(nr_moves))
 
func pIncSleep
/* ------------------------------------------------------------------------------------------------------ */
nr_sleep = nr_sleep + 1
sleepbtn.settext("Sleep Time: " + string(nr_sleep) + " s")
 
func pDecSleep
predicates
cell_click:(integer).if nr_sleep > 1
nr_sleep = nr_sleep - 1
sleepbtn.settext("Sleep Time: " + string(nr_sleep) + " s")
ok
 
func sleep(x)
clauses
cell_click(NrCell):-nTime = x
oTest = new good(empty,_,NrCell),qTest
celloTest.qsleep(empty,EmptyHandlenTime),
cell(NrCell,NrCellHandle),return
EmptyNr = vpi::winGetText(NrCellHandle),
vpi::winSetText(EmptyHandle,EmptyNr),
vpi::winSetText(NrCellHandle,""),
empty:=NrCell,
step_nr := step_nr + 1,
Bingo = vpi::winGetCtlHandle(thisWin,idc_bingo),
vpi::winSetText( Bingo, ""),
vpi::winSetState(Bingo,[wsf_Invisible]),
bingo(),
 
func isGameOver
% VerVal = uncheckedConvert(integer, math::floor((empty-1)/4)+1),
flagend = 1
% HorVal = uncheckedConvert(integer, math::floor((empty-1) mod 4)+1),
for n=1 to button_size*button_size-1
if button[n].text() != n or btn_degree[n][2] != 0
flagend = 0
exit
ok
next
if flagend = 1
new qmessagebox(win1) {
setwindowtitle("Game Over")
settext("Congratulations!")
show()
}
ok
 
func rightPlace
VerVal = math::floor((empty-1)/4)+1,
HorValcount = math::floor((empty-1) mod 4)+1,0
for n=1 to button_size*button_size
if button[n].text() = n and btn_degree[n][2] = 0
count = count + 1
ok
next
rightbtn.settext("In the Right Place : " + count)
 
func warning
vpi::winSetScrollPos(vsbarr,sb_Ctl,VerVal),
new qmessagebox(win1) {
vpi::winSetScrollPos(vsbarl,sb_Ctl,VerVal),
vpi::winSetScrollPos setwindowtitle(hsbart,sb_Ctl,HorVal"Warning!"),
settext("First you must play and save the game.")
vpi::winSetScrollPos(hsbarb,sb_Ctl,HorVal),
show()
}
 
func pElapsedTime
Step = vpi::winGetCtlHandle(thisWin,idc_step),
t2 = vpi::winSetText(Step,toStringclock(step_nr) - t1),/1000
timebtn.settext("Elapsed Time : " + t2 + " s")
 
Class ButtonWithRotatedText
assert(gameplay(step_nr,NrCell)),
 
oButton oLabel cText="We are here" n_degree = 30 nTransX = 50 nTransY = 0
fail.
cell_click(_).
 
func init( oParent)
/* ------------------------------------------------------------------------------------------------------ */
oButton = new qPushButton(oParent)
oLabel = new qLabel(oParent)
oLabel.setAttribute(Qt_WA_TransparentForMouseEvents,True)
oLabel.setAttribute(Qt_WA_DeleteOnClose, True)
oButton.setAttribute(Qt_WA_DeleteOnClose, True)
oButton.Show()
return
func close()
oLabel.close()
oButton.close()
return
 
func setstylesheet(x)
predicates
cell_click_play:oButton.setstylesheet(integerx).
 
func setgeometry( x,y,width,height)
clauses
cell_click_playoButton.setgeometry(NrCellx,y,width,height):-
oLabel.setgeometry( good(emptyx,_y,NrCellwidth,height),
cell(empty,EmptyHandle),
func setText( cValue)
cell(NrCell,NrCellHandle),
EmptyNrcText = vpi::winGetText(NrCellHandle),cValue
return
vpi::winSetText(EmptyHandle,EmptyNr),
vpi::winSetText(NrCellHandle,""),
func Text()
empty:=NrCell,
return cText
Bingo = vpi::winGetCtlHandle(thisWin,idc_bingo),
vpi::winSetText(Bingo, ""),
vpi::winSetState(Bingo,[wsf_Invisible]),
bingo(),
 
func setTranslate( x,y )
% VerVal = uncheckedConvert(integer,math::floor((empty-1)/4)+1),
nTransX = x
% HorVal = uncheckedConvert(integer,math::floor((empty-1) mod 4)+1),
nTransY = y
return
 
func TranslateOffsetX()
VerVal = math::floor((empty-1)/4)+1,
return nTransX
HorVal = math::floor((empty-1) mod 4)+1,
 
func TranslateOffsetY()
vpi::winSetScrollPos(vsbarr,sb_Ctl,VerVal),
return nTransY
vpi::winSetScrollPos(vsbarl,sb_Ctl,VerVal),
vpi::winSetScrollPos(hsbart,sb_Ctl,HorVal),
func setRotation_degree( nValue)
vpi::winSetScrollPos(hsbarb,sb_Ctl,HorVal),
n_degree = nValue
return
func Rotation_degree()
return n_degree
 
func setClickEvent( cEvent)
programControl::sleep(1000),
oButton.setClickEvent(cEvent)
return
func braceend()
draw()
return
 
func setEnabled(value) fail.
cell_click_playoButton.setenabled(_value).
return
 
func setButtonColor(color)
/* ------------------------------------------------------------------------------------------------------ */
colorIt = "background-color:" + color
oButton.setstylesheet(colorIt)
return
func draw()
picture = new qpicture()
color = new qcolor() { setrgb(0,0,255,255) }
pen = new qpen() { setcolor(color) setwidth(10) }
painter = new qpainter()
{
begin(picture)
setpen(pen)
oFont = new qfont("Courier New",12,75,0)
oFont.setpointsize(20)
setfont(oFont)
if n_degree = 0
if btn_degree[empty] [1]="In" p1 = -8 p2=0
translate(p1,p2) ok ok
if n_degree = 0
if btn_degree[empty] [1]<10 p1 = 10 p2=10 else p1=5 p2=10 ok
translate(p1,p2)
but n_degree = 90
if btn_degree[empty] [1]<10 p=-10 else p=-15 ok
translate(10,p)
but n_degree = 180
if btn_degree[empty] [1]<10 p1= 30 p2=-10 else p1=35 p2=-10 ok
translate(p1,p2)
but n_degree = 270
if btn_degree[empty] [1]<10 p=10 else p=15 ok
translate(30,p)
but n_degree = -90
if btn_degree[empty] [1]<10 p=10 else p=15 ok
translate(30,p)
but n_degree = -180
if btn_degree[empty] [1]<10 p1=30 p2=-10 else p1=35 p2=-10 ok
translate(p1,p2)
but n_degree = -270
if btn_degree[empty] [1]<10 p1=10 p2=-10 else p1=10 p2=-15 ok
translate(p1,p2)
ok
rotate(n_degree)
drawtext(0,0,this.Text())
endpaint()
}
oLabel {
setpicture(picture)
show()
}
return
 
</syntaxhighlight>
predicates
onControlmix : vpiOldDomains::controlHandler.
clauses
onControlmix(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
step_nr:=0,
cell_reset(),
mix_cells(0),
Play = vpi::winGetCtlHandle(thisWin,idc_play),
vpi::winSetState(Play,[wsf_Disabled]),
Bingo = vpi::winGetCtlHandle(thisWin,idc_bingo),
vpi::winSetText(Bingo, ""),
vpi::winSetState(Bingo,[wsf_Invisible]),
step_nr:=0,
Step = vpi::winGetCtlHandle(thisWin,idc_step),
vpi::winSetText(Step,toString(step_nr)),
table_save(),
retractall(gameplay(_,_)),
fail.
 
'''Output:'''
onControlmix(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull).
 
[https://youtu.be/IZqpYctv8Zs CalmoSoft Fifteen Puzzle Game in Ring - video]
/* ------------------------------------------------------------------------------------------------------ */
 
=== newer version ===
class facts
This was added, out of place, 3rd November 2023, but dated a year earlier than the one last updated 29th September 2021...
rand_nr:integer:=0.
<syntaxhighlight lang="ring">
mix_nr:integer:=300.
/*
**
** Game : CalmoSoft Fifteen Puzzle Game 3D
** Date : 2017/09/01
** Author : CalmoSoft <calmosoft@gmail.com>, Mahmoud Fayed
**
*/
 
# Load Libraries
predicates
load "gamelib.ring" # RingAllegro Library
mix_cells:(integer) multi.
load "opengl21lib.ring" # RingOpenGL Library
 
butSize = 3
clauses
texture = list(9)
mix_cells(mix_nr):-!.
cube = list(9)
mix_cells(Number):-
rnd = list(9)
NumberNew = Number+1,
rndok = 0
cellnr(empty,CellNr),
RandomNr = (math::random(1315) mod CellNr) + 1,
rand_nr := RandomNr,
good(empty,rand_nr, I),
cell_click(I),
mix_cells(NumberNew).
mix_cells(_).
 
for n=1 to 9
/* ------------------------------------------------------------------------------------------------------ */
rnd[n] = 0
next
 
for n=1 to 9
predicates
while table_save:().true
rndok = 0
clauses
table_save ran = random(8):- + 1
retractall(table(_,_)), for nr=1 to 9
retractall(empty_cell(_)), if rnd[nr] = ran
assert(empty_cell(empty)), rndok = 1
ok
next
if rndok = 0
rnd[n] = ran
exit
ok
end
next
 
for n=1 to 9
assert(table(1,vpi::winGetText(cell1))),
if rnd[n] = 9
assert(table(2,vpi::winGetText(cell2))),
empty = n
assert(table(3,vpi::winGetText(cell3))),
ok
assert(table(4,vpi::winGetText(cell4))),
next
assert(table(5,vpi::winGetText(cell5))),
assert(table(6,vpi::winGetText(cell6))),
assert(table(7,vpi::winGetText(cell7))),
assert(table(8,vpi::winGetText(cell8))),
assert(table(9,vpi::winGetText(cell9))),
assert(table(10,vpi::winGetText(cell10))),
assert(table(11,vpi::winGetText(cell11))),
assert(table(12,vpi::winGetText(cell12))),
assert(table(13,vpi::winGetText(cell13))),
assert(table(14,vpi::winGetText(cell14))),
assert(table(15,vpi::winGetText(cell15))),
assert(table(16,vpi::winGetText(cell16))).
 
#==============================================================
/* ------------------------------------------------------------------------------------------------------ */
# 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
predicates
new TicTacToe3D {
onControlreset : vpiOldDomains::controlHandler.
start()
clauses
}
onControlreset(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
cell_reset().
 
class TicTacToe3D from GameLogic
/* ------------------------------------------------------------------------------------------------------ */
predicates
cell_reset:().
clauses
cell_reset():-
vpi::winSetText(cell1,"1"),
vpi::winSetText(cell2,"2"),
vpi::winSetText(cell3,"3"),
vpi::winSetText(cell4,"4"),
vpi::winSetText(cell5,"5"),
vpi::winSetText(cell6,"6"),
vpi::winSetText(cell7,"7"),
vpi::winSetText(cell8,"8"),
vpi::winSetText(cell9,"9"),
vpi::winSetText(cell10,"10"),
vpi::winSetText(cell11,"11"),
vpi::winSetText(cell12,"12"),
vpi::winSetText(cell13,"13"),
vpi::winSetText(cell14,"14"),
vpi::winSetText(cell15,"15"),
vpi::winSetText(cell16,""),
 
FPS = 60
vpi::winSetScrollPos(vsbarr,sb_Ctl,4),
TITLE = "CalmoSoft Fifteen Puzzle Game 3D"
vpi::winSetScrollPos(vsbarl,sb_Ctl,4),
vpi::winSetScrollPos(hsbart,sb_Ctl,4),
vpi::winSetScrollPos(hsbarb,sb_Ctl,4),
 
oBackground = new GameBackground
empty:=16,
oGameSound = new GameSound
step_nr:=0,
oGameCube = new GameCube
Step = vpi::winGetCtlHandle(thisWin,idc_step),
oGameInterface = new GameInterface
vpi::winSetText(Step,toString(step_nr)),
Bingo = vpi::winGetCtlHandle(thisWin,idc_bingo),
vpi::winSetText(Bingo, ""),
vpi::winSetState(Bingo,[wsf_Invisible]),
Play = vpi::winGetCtlHandle(thisWin,idc_play),
vpi::winSetState(Play,[wsf_Disabled]),
retractall(gameplay(_,_)),
table_save().
 
func loadresources
/* ------------------------------------------------------------------------------------------------------ */
oGameSound.loadresources()
oBackGround.loadresources()
oGameCube.loadresources()
 
func drawScene
predicates
oBackground.update()
bingo:().
oGameInterface.update(self)
 
func MouseClickEvent
clauses
oGameInterface.MouseClickEvent(self)
bingo():-
toString(1) = vpi::winGetText(cell1),
toString(2) = vpi::winGetText(cell2),
toString(3) = vpi::winGetText(cell3),
toString(4) = vpi::winGetText(cell4),
toString(5) = vpi::winGetText(cell5),
toString(6) = vpi::winGetText(cell6),
toString(7) = vpi::winGetText(cell7),
toString(8) = vpi::winGetText(cell8),
toString(9) = vpi::winGetText(cell9),
toString(10) = vpi::winGetText(cell10),
toString(11) = vpi::winGetText(cell11),
toString(12) = vpi::winGetText(cell12),
toString(13) = vpi::winGetText(cell13),
toString(14) = vpi::winGetText(cell14),
toString(15) = vpi::winGetText(cell15),
"" = vpi::winGetText(cell16),
 
class GameInterface
Bingo = vpi::winGetCtlHandle(thisWin,idc_bingo),
vpi::winSetState(Bingo,[wsf_Visible]),
vpi::winSetText(Bingo, "BINGO !"),
 
func Update oGame
Step = vpi::winGetCtlHandle(thisWin,idc_step),
prepare()
vpi::winSetText(Step,toString(step_nr)),
cubes(oGame)
 
func Prepare
fail.
w = 1024 h = 768
bingo().
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
facts
oGame {
fileName:string:="".
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
predicates
onControlsave : vpiOldDomains::controlHandler.
clauses
onControlsave(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
try
FileName = vpiCommonDialogs::getFileName(fileName, ["All files", "*.game"], "Save game as", [dlgfn_Save], "", _)
catch _ do
fail
end try,
!,
file::save(FileName,gameDB).
 
aGameMap = [
onControlsave(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo)= vpiOldDomains::handled(gui_api::rNull).
[ :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
predicates
onControlopen : vpiOldDomains::controlHandler.
clauses
onControlopen(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
try
FileName = vpiCommonDialogs::getFileName("game_", ["All files", "*.game"], "Open game file", [], "", _)
catch _ do
fail
end try,
!,
retractall(table(_,_)),
retractall(gameplay(_,_)),
retractall(empty_cell(_)),
file::consult(FileName,gameDB),
play_display(),
Play = vpi::winGetCtlHandle(thisWin,idc_play),
vpi::winSetState(Play,[wsf_Enabled]),
Bingo = vpi::winGetCtlHandle(thisWin,idc_bingo),
vpi::winSetState(Bingo,[wsf_Invisible]),
vpi::winSetText(Bingo, ""),
step_nr:=0,
Step = vpi::winGetCtlHandle(thisWin,idc_step),
vpi::winSetText(Step,toString(step_nr)).
 
func point2button x,y
onControlopen(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull).
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
predicates
textureX textureO textureN
play_display:().
clauses
play_display():-
 
xrot = 0.0
table(1,Cell1),
yrot = 0.0
table(2,Cell2),
zrot = 0.0
table(3,Cell3),
table(4,Cell4),
table(5,Cell5),
table(6,Cell6),
table(7,Cell7),
table(8,Cell8),
table(9,Cell9),
table(10,Cell10),
table(11,Cell11),
table(12,Cell12),
table(13,Cell13),
table(14,Cell14),
table(15,Cell15),
table(16,Cell16),
 
func loadresources
vpi::winSetText(cell1,Cell1),
bitmp1 = al_load_bitmap("image/n1.jpg")
vpi::winSetText(cell2,Cell2),
texture[1] = al_get_opengl_texture(bitmp1)
vpi::winSetText(cell3,Cell3),
bitmp2 = al_load_bitmap("image/n2.jpg")
vpi::winSetText(cell4,Cell4),
texture[2] = al_get_opengl_texture(bitmp2)
vpi::winSetText(cell5,Cell5),
bitmp3 = al_load_bitmap("image/n3.jpg")
vpi::winSetText(cell6,Cell6),
texture[3] = al_get_opengl_texture(bitmp3)
vpi::winSetText(cell7,Cell7),
bitmp4 = al_load_bitmap("image/n4.jpg")
vpi::winSetText(cell8,Cell8),
texture[4] = al_get_opengl_texture(bitmp4)
vpi::winSetText(cell9,Cell9),
bitmp5 = al_load_bitmap("image/n5.jpg")
vpi::winSetText(cell10,Cell10),
texture[5] = al_get_opengl_texture(bitmp5)
vpi::winSetText(cell11,Cell11),
bitmp6 = al_load_bitmap("image/n6.jpg")
vpi::winSetText(cell12,Cell12),
texture[6] = al_get_opengl_texture(bitmp6)
vpi::winSetText(cell13,Cell13),
bitmp7 = al_load_bitmap("image/n7.jpg")
vpi::winSetText(cell14,Cell14),
texture[7] = al_get_opengl_texture(bitmp7)
vpi::winSetText(cell15,Cell15),
bitmp8 = al_load_bitmap("image/n8.jpg")
vpi::winSetText(cell16,Cell16),
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)
empty_cell(Empty_Cell),
glLoadIdentity()
empty:=Empty_Cell,
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
fail.
glBindTexture(GL_TEXTURE_2D, cTexture)
play_display().
 
func Rotate
/* ------------------------------------------------------------------------------------------------------ */
xrot += 0.3 * 5
yrot += 0.2 * 5
zrot += 0.4 * 5
 
func drawcube
predicates
glBegin(GL_QUADS)
onControlplay : vpiOldDomains::controlHandler.
// Front Face
clauses
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()
 
onControlplay(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
Play = vpi::winGetCtlHandle(thisWin,idc_play),
vpi::winSetState(Play,[wsf_Disabled]),
gameplay(Nr,Nr_cell),
cell_click_play(Nr_cell),
Step = vpi::winGetCtlHandle(thisWin,idc_step),
vpi::winSetText(Step,toString(Nr)),
fail.
 
class GameBackground
onControlplay(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull).
 
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
predicates
onControlsbvr : vpiOldDomains::controlHandler. % Sets the right vertical scrollbar
clauses
onControlsbvr(_CtrlID, _CtrlType, _CtrlWin,scroll(sc_LineDown,_)) = vpiOldDomains::handled(gui_api::rNull):-
Sbarvalr = vpi::winGetScrollPos(vsbarr,sb_Ctl)+1,
Sbarvalr < 5,
cell_click(empty+4),
vpi::winSetScrollPos(vsbarr,sb_Ctl, Sbarvalr),
vpi::winSetScrollPos(vsbarl,sb_Ctl, Sbarvalr),
fail.
 
func Update
onControlsbvr(_CtrlID, _CtrlType, _CtrlWin,scroll(sc_LineUp,_)) = vpiOldDomains::handled(gui_api::rNull):-
draw()
Sbarvalr = vpi::winGetScrollPos(vsbarr,sb_Ctl)-1,
motion()
Sbarvalr > 0,
cell_click(empty-4),
vpi::winSetScrollPos(vsbarr,sb_Ctl, Sbarvalr),
vpi::winSetScrollPos(vsbarl,sb_Ctl, Sbarvalr),
fail.
 
func draw
onControlsbvr(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull).
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
predicates
onControlsbvl : vpiOldDomains::controlHandler. % Sets the left vertical scrollbar
clauses
onControlsbvl(_CtrlID, _CtrlType, _CtrlWin,scroll(sc_LineDown,_)) = vpiOldDomains::handled(gui_api::rNull):-
Sbarvall = vpi::winGetScrollPos(vsbarl,sb_Ctl)+1,
Sbarvall < 5,
cell_click(empty+4),
vpi::winSetScrollPos(vsbarl,sb_Ctl, Sbarvall),
vpi::winSetScrollPos(vsbarr,sb_Ctl, Sbarvall),
fail.
 
sample sampleid
onControlsbvl(_CtrlID, _CtrlType, _CtrlWin,scroll(sc_LineUp,_)) = vpiOldDomains::handled(gui_api::rNull):-
Sbarvall = vpi::winGetScrollPos(vsbarl,sb_Ctl)-1,
Sbarvall > 0,
cell_click(empty-4),
vpi::winSetScrollPos(vsbarl,sb_Ctl, Sbarvall),
vpi::winSetScrollPos(vsbarr,sb_Ctl, Sbarvall),
fail.
 
func loadresources
onControlsbvl(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull).
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
predicates
timer
onControlsbht : vpiOldDomains::controlHandler. % Sets the top horizontal scrollbar
redraw = true
clauses
FPS = 60
onControlsbht(_CtrlID, _CtrlType, _CtrlWin,scroll(sc_LineDown,_)) = vpiOldDomains::handled(gui_api::rNull):-
SCREEN_W = 1024
Sbarvalt = vpi::winGetScrollPos(hsbart,sb_Ctl)+1,
SCREEN_H = 700
Sbarvalt < 5,
KEY_UP = 1
cell_click(empty+1),
KEY_DOWN = 2
vpi::winSetScrollPos(hsbart,sb_Ctl, Sbarvalt),
KEY_LEFT = 3
vpi::winSetScrollPos(hsbarb,sb_Ctl, Sbarvalt),
KEY_RIGHT = 4
fail.
Key = [false,false,false,false]
Mouse_X = 0
Mouse_Y = 0
TITLE = "Graphics Application"
PRINT_MOUSE_XY = False
 
func start
onControlsbht(_CtrlID, _CtrlType, _CtrlWin,scroll(sc_LineUp,_)) = vpiOldDomains::handled(gui_api::rNull):-
SetUp()
Sbarvalt = vpi::winGetScrollPos(hsbart,sb_Ctl)-1,
loadResources()
Sbarvalt > 0,
eventsLoop()
cell_click(empty-1),
destroy()
vpi::winSetScrollPos(hsbart,sb_Ctl, Sbarvalt),
vpi::winSetScrollPos(hsbarb,sb_Ctl, Sbarvalt),
fail.
 
func setup
onControlsbht(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull).
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
predicates
al_destroy_timer(timer)
onControlsbhb : vpiOldDomains::controlHandler. % Sets the bottom horizontal scrollbar
al_destroy_allegro_event(ev)
clauses
al_destroy_allegro_timeout(timeout)
onControlsbhb(_CtrlID, _CtrlType, _CtrlWin,scroll(sc_LineDown,_)) = vpiOldDomains::handled(gui_api::rNull):-
al_destroy_event_queue(event_queue)
Sbarvalb = vpi::winGetScrollPos(hsbarb,sb_Ctl)+1,
al_destroy_display(display)
Sbarvalb < 5,
al_exit()
cell_click(empty+1),
vpi::winSetScrollPos(hsbarb,sb_Ctl, Sbarvalb),
vpi::winSetScrollPos(hsbart,sb_Ctl, Sbarvalb),
fail.
 
func loadresources
onControlsbhb(_CtrlID, _CtrlType, _CtrlWin,scroll(sc_LineUp,_)) = vpiOldDomains::handled(gui_api::rNull):-
Sbarvalb = vpi::winGetScrollPos(hsbarb,sb_Ctl)-1,
Sbarvalb > 0,
cell_click(empty-1),
vpi::winSetScrollPos(hsbarb,sb_Ctl, Sbarvalb),
vpi::winSetScrollPos(hsbart,sb_Ctl, Sbarvalb),
fail.
 
func drawScene
onControlsbhb(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull).
 
func MouseClickEvent
/* ------------------------------------------------------------------------------------------------------ */
exit # Exit from the Events Loop
 
func CloseEvent
predicates
exit # Exit from the Events Loop
onControlcell1 : vpiOldDomains::controlHandler.
clauses
onControlcell1(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
cell_click(1).
 
/* ------------------------------------------------------------------------------------------------------ */
 
 
predicates
onControlcell2 : vpiOldDomains::controlHandler.
clauses
onControlcell2(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
cell_click(2).
 
/* ------------------------------------------------------------------------------------------------------ */
 
predicates
onControlcell3 : vpiOldDomains::controlHandler.
clauses
onControlcell3(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
cell_click(3).
 
/* ------------------------------------------------------------------------------------------------------ */
 
predicates
onControlcell4 : vpiOldDomains::controlHandler.
clauses
onControlcell4(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
cell_click(4).
 
/* ------------------------------------------------------------------------------------------------------ */
 
predicates
onControlcell5 : vpiOldDomains::controlHandler.
clauses
onControlcell5(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
cell_click(5).
 
/* ------------------------------------------------------------------------------------------------------ */
 
predicates
onControlcell6 : vpiOldDomains::controlHandler.
clauses
onControlcell6(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
cell_click(6).
 
/* ------------------------------------------------------------------------------------------------------ */
 
predicates
onControlcell7 : vpiOldDomains::controlHandler.
clauses
onControlcell7(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
cell_click(7).
 
/* ------------------------------------------------------------------------------------------------------ */
 
predicates
onControlcell8 : vpiOldDomains::controlHandler.
clauses
onControlcell8(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
cell_click(8).
 
/* ------------------------------------------------------------------------------------------------------ */
 
predicates
onControlcell9 : vpiOldDomains::controlHandler.
clauses
onControlcell9(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
cell_click(9).
 
/* ------------------------------------------------------------------------------------------------------ */
 
predicates
onControlcell10 : vpiOldDomains::controlHandler.
clauses
onControlcell10(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
cell_click(10).
 
/* ------------------------------------------------------------------------------------------------------ */
 
predicates
onControlcell11 : vpiOldDomains::controlHandler.
clauses
onControlcell11(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
cell_click(11).
 
/* ------------------------------------------------------------------------------------------------------ */
 
predicates
onControlcell12 : vpiOldDomains::controlHandler.
clauses
onControlcell12(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
cell_click(12).
 
/* ------------------------------------------------------------------------------------------------------ */
 
predicates
onControlcell13 : vpiOldDomains::controlHandler.
clauses
onControlcell13(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
cell_click(13).
 
/* ------------------------------------------------------------------------------------------------------ */
 
predicates
onControlcell14 : vpiOldDomains::controlHandler.
clauses
onControlcell14(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
cell_click(14).
 
/* ------------------------------------------------------------------------------------------------------ */
 
predicates
onControlcell15 : vpiOldDomains::controlHandler.
clauses
onControlcell15(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
cell_click(15).
 
/* ------------------------------------------------------------------------------------------------------ */
 
predicates
onControlcell16 : vpiOldDomains::controlHandler.
clauses
onControlcell16(_CtrlID, _CtrlType, _CtrlWin, _CtrlInfo) = vpiOldDomains::handled(gui_api::rNull):-
cell_click(16).
 
/* ------------------------------------------------------------------------------------------------------ */
 
% This code is maintained by the VDE do not update it manually, 22:12:35-14.3.2004
constants
dialogType : vpiDomains::wintype = wd_Modal.
title : string = "playDialog".
rectangle : vpiDomains::rct = rct(200,40,359,263).
dialogFlags : vpiDomains::wsflags = [wsf_Close,wsf_TitleBar].
dialogFont = "MS Sans Serif".
dialogFontSize = 8.
 
constants
controlList : vpiDomains::windef_list =
[
dlgFont(wdef(dialogType, rectangle, title, u_DlgBase),
dialogFont, dialogFontSize, dialogFlags),
ctl(wdef(wc_PushButton,rct(40,166,67,178),"&Mix",u_DlgBase),idc_mix,[wsf_Group,wsf_TabStop]),
ctl(wdef(wc_PushButton,rct(67,166,94,178),"&Reset",u_DlgBase),idc_reset,[wsf_Group,wsf_TabStop]),
ctl(wdef(wc_PushButton,rct(40,178,67,190),"&Save",u_DlgBase),idc_save,[wsf_Group,wsf_TabStop]),
ctl(wdef(wc_PushButton,rct(94,178,121,190),"&Open",u_DlgBase),idc_open,[wsf_Group,wsf_TabStop]),
ctl(wdef(wc_PushButton,rct(40,190,121,202),"&Play",u_DlgBase),idc_play,[wsf_Group,wsf_TabStop,wsf_Disabled]),
ctl(wdef(wc_PushButton,rct(94,166,121,178),"&Exit",u_DlgBase),idc_cancel,[wsf_Group,wsf_TabStop]),
ctl(wdef(wc_PushButton,rct(40,40,60,60),"1",u_DlgBase),idc_cell1,[wsf_Group]),
ctl(wdef(wc_PushButton,rct(60,40,80,60),"2",u_DlgBase),idc_cell2,[wsf_Group]),
ctl(wdef(wc_PushButton,rct(80,40,100,60),"3",u_DlgBase),idc_cell3,[wsf_Group]),
ctl(wdef(wc_PushButton,rct(100,40,120,60),"4",u_DlgBase),idc_cell4,[wsf_Group]),
ctl(wdef(wc_PushButton,rct(40,60,60,80),"5",u_DlgBase),idc_cell5,[wsf_Group]),
ctl(wdef(wc_PushButton,rct(60,60,80,80),"6",u_DlgBase),idc_cell6,[wsf_Group]),
ctl(wdef(wc_PushButton,rct(80,60,100,80),"7",u_DlgBase),idc_cell7,[wsf_Group]),
ctl(wdef(wc_PushButton,rct(100,60,120,80),"8",u_DlgBase),idc_cell8,[wsf_Group]),
ctl(wdef(wc_PushButton,rct(40,80,60,100),"9",u_DlgBase),idc_cell9,[wsf_Group]),
ctl(wdef(wc_PushButton,rct(60,80,80,100),"10",u_DlgBase),idc_cell10,[wsf_Group]),
ctl(wdef(wc_PushButton,rct(80,80,100,100),"11",u_DlgBase),idc_cell11,[wsf_Group]),
ctl(wdef(wc_PushButton,rct(100,80,120,100),"12",u_DlgBase),idc_cell12,[wsf_Group]),
ctl(wdef(wc_PushButton,rct(40,100,60,120),"13",u_DlgBase),idc_cell13,[wsf_Group]),
ctl(wdef(wc_PushButton,rct(60,100,80,120),"14",u_DlgBase),idc_cell14,[wsf_Group]),
ctl(wdef(wc_PushButton,rct(80,100,100,120),"15",u_DlgBase),idc_cell15,[wsf_Group]),
ctl(wdef(wc_PushButton,rct(100,100,120,120),"",u_DlgBase),idc_cell16,[wsf_Group]),
ctl(wdef(wc_HScroll,rct(30,18,130,30),"",u_DlgBase),idc_sbht,[]),
ctl(wdef(wc_VScroll,rct(130,30,142,130),"",u_DlgBase),idc_sbvr,[]),
ctl(wdef(wc_HScroll,rct(30,130,130,142),"",u_DlgBase),idc_sbhb,[]),
ctl(wdef(wc_VScroll,rct(18,30,30,130),"",u_DlgBase),idc_sbvl,[]),
ctl(wdef(wc_PushButton,rct(67,178,94,190),"",u_DlgBase),idc_step,[wsf_Group]),
ctl(wdef(wc_PushButton,rct(40,154,121,166),"",u_DlgBase),idc_bingo,[wsf_Group,wsf_Invisible])
].
 
predicates
generatedEventHandler : vpiDomains::ehandler.
clauses
generatedEventHandler(Win, e_create(_)) = _ :-
thisWin := Win,
fail.
generatedEventHandler(_Win, e_Create(CreationData)) = Result :-
handled(Result) = onCreate(CreationData).
generatedEventHandler(_Win, e_Update(Rectangle)) = Result :-
handled(Result) = onUpdate(Rectangle).
generatedEventHandler(_Win, e_Control(idc_cancel, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlCancel(idc_cancel, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_mix, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlmix(idc_mix, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_reset, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlreset(idc_reset, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_sbvr, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlsbvr(idc_sbvr, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_sbvl, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlsbvl(idc_sbvl, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_sbhb, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlsbhb(idc_sbhb, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_sbht, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlsbht(idc_sbht, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_save, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlsave(idc_save, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_open, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlopen(idc_open, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_play, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlplay(idc_play, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_cell1, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlcell1(idc_cell1, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_cell10, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlcell10(idc_cell10, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_cell11, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlcell11(idc_cell11, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_cell12, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlcell12(idc_cell12, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_cell13, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlcell13(idc_cell13, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_cell14, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlcell14(idc_cell14, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_cell15, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlcell15(idc_cell15, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_cell16, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlcell16(idc_cell16, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_cell2, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlcell2(idc_cell2, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_cell3, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlcell3(idc_cell3, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_cell4, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlcell4(idc_cell4, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_cell5, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlcell5(idc_cell5, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_cell6, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlcell6(idc_cell6, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_cell7, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlcell7(idc_cell7, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_cell8, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlcell8(idc_cell8, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Control(idc_cell9, CtrlType, CtrlWin, CtlInfo)) = Result :-
handled(Result) = onControlcell9(idc_cell9, CtrlType, CtrlWin, CtlInfo).
generatedEventHandler(_Win, e_Destroy()) = Result :-
handled(Result) = onDestroy().
% end of automatic code
end implement playDialog
</lang>
 
'''Output:'''
 
</syntaxhighlight>
[https://www.youtube.com/watch?v=rWy3AX5HjXM CalmoSoft Fifteen Puzzle Game in Visual Prolog - video]
[https://youtu.be/xvhNKTZKi8U CalmoSoft Fifteen Puzzle Game in 3D]
 
=={{header|Ruby}}==
<langsyntaxhighlight lang="ruby">require 'io/console'
 
class Board
Line 9,469 ⟶ 12,971:
end
 
Board.new</langsyntaxhighlight>
 
{{out}}
Line 9,489 ⟶ 12,991:
{{libheader|JRubyArt}}
Gui Version:-
<langsyntaxhighlight lang="ruby">DIM = 100
SOLUTION = %w[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0].freeze
 
Line 9,592 ⟶ 13,094:
end
 
</syntaxhighlight>
</lang>
 
=={{header|Run BASIC}}==
<langsyntaxhighlight lang="runbasic">call SetCSS
' ---- fill 15 squares with 1 to 15
dim sq(16)
Line 9,663 ⟶ 13,165:
Text-Align:Center;Font-Size:24pt;Font-Weight:Bold;Font-Family:Arial;
}"
END SUB</langsyntaxhighlight>
Output:
[[File:KokengeGame15.jpg]]
Line 9,669 ⟶ 13,171:
=={{header|Rust}}==
{{libheader|rand}}
<syntaxhighlight lang ="rust">extern crate rand;
extern crate rand;
use clearscreen::clear;
use std::collections::HashMap;
use std::fmt;
use std::io::{self, Write};
 
use rand::seq::SliceRandom;
use rand::Rng;
 
use rand::seq::SliceRandom;
#[derive(Copy, Clone, PartialEq, Debug)]
enum Cell {
Line 9,682 ⟶ 13,186:
Empty,
}
 
#[derive(Eq, PartialEq, Hash, Debug)]
enum Direction {
Line 9,690 ⟶ 13,194:
Right,
}
 
enum Action {
Move(Direction),
Quit,
}
 
type Board = [Cell; 16];
const EMPTY: Board = [Cell::Empty; 16];
 
struct P15 {
board: Board,
}
 
impl P15 {
fn new() -> Self {
Line 9,709 ⟶ 13,213:
*cell = Cell::Card(i);
}
 
let mut rng = rand::thread_rng();
 
board.shuffle(&mut rng);
if !Self::is_valid(board) {
// random swap
let i = rng.gen_range(0, ..16);
let mut j = rng.gen_range(0, ..16);
while j == i {
j = rng.gen_range(0, ..16);
}
board.swap(i, j);
}
 
Self { board }
}
 
fn is_valid(mut board: Board) -> bool {
// TODO: optimize
let mut permutations = 0;
 
let pos = board.iter().position(|&cell| cell == Cell::Empty).unwrap();
 
if pos != 15 {
board.swap(pos, 15);
permutations += 1;
}
 
for i in 1..16 {
let pos = board
.iter()
.position(|&cell| match matches!(cell, Cell::Card(value) if value == {i))
Cell::Card(value) if value == i => true,
_ => false,
})
.unwrap();
 
if pos + 1 != i {
board.swap(pos, i - 1);
Line 9,751 ⟶ 13,252:
}
}
 
permutations % 2 == 0
}
 
fn get_empty_position(&self) -> usize {
self.board.iter().position(|&c| c == Cell::Empty).unwrap()
}
 
fn get_moves(&self) -> HashMap<Direction, Cell> {
let mut moves = HashMap::new();
let i = self.get_empty_position();
 
if i > 3 {
moves.insert(Direction::Up, self.board[i - 4]);
Line 9,777 ⟶ 13,278:
moves
}
 
fn play(&mut self, direction: &Direction) {
let i = self.get_empty_position();
Line 9,788 ⟶ 13,289:
};
}
 
fn is_complete(&self) -> bool {
self.board.iter().enumerate().all(|(i, &cell)| match cell {
Line 9,796 ⟶ 13,297:
}
}
 
impl fmt::Display for P15 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
r#try!(writewriteln!(f, "+----+----+----+----+\n"))?;
for (i, &cell) in self.board.iter().enumerate() {
match cell {
Cell::Card(value) => r#try!(write!(f, "| {value:2} ", value))?,
Cell::Empty => r#try!(write!(f, "| "))?,
}
 
if i % 4 == 3 {
r#try!(writewriteln!(f, "|\n"))?;
r#try!(writewriteln!(f, "+----+----+----+----+\n"))?;
}
}
Line 9,814 ⟶ 13,315:
}
}
 
fn main() {
let mut p15 = P15::new();
 
for turns in 1.. {
println!("{p15}", p15);
match ask_action(&p15.get_moves(), true) {
Action::Move(direction) => {
p15.play(&direction);
clear().expect("failed to clear screen");
}
Action::Quit => {
println!clear().expect("Byefailed to clear !screen");
 
println!("Bye!");
break;
}
}
 
if p15.is_complete() {
println!("Well done ! You won in {turns} turns", turns);
break;
}
}
}
 
fn ask_action(moves: &HashMap<Direction, Cell>, render_list: bool) -> Action {
use std::io::{self, Write};
use Action::*;
use Direction::*;
 
if render_list {
println!("Possible moves:");
println!("Possible moves:");
 
if let Some(&Cell::Card(value)) = moves.get(&Up) {
println!if let Some("\tU&Cell::Card(value)) {}",= valuemoves.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();
}
 
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();
let mut action = String::new();
io::stdin().read_line(&mut action).expect("read error");
Line 9,869 ⟶ 13,377:
"Q" => Quit,
_ => {
println!if unknown_action("Unknown action:) {}", action);
ask_action(moves, true)
} else {
ask_action(moves, false)
}
}
}
}
}</lang>
 
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}}==
<langsyntaxhighlight lang="scala">import java.util.Random
 
import jline.console._
Line 9,952 ⟶ 13,478:
.foldLeft(Board.solveState) { case (state, mv) => state.move(mv) }
}
}</langsyntaxhighlight>
 
=={{header|Scheme}}==
 
<langsyntaxhighlight lang="scheme">
(import (scheme base)
(scheme read)
Line 10,042 ⟶ 13,568:
 
(play-game)
</syntaxhighlight>
</lang>
 
{{out}}
Line 10,076 ⟶ 13,602:
=={{header|Scilab}}==
 
<syntaxhighlight lang="text">tiles=[1:15,0];
solution=[tiles(1:4);...
tiles(5:8);...
Line 10,159 ⟶ 13,685:
end
 
disp("Solved in "+string(n_moves)+" moves.");</langsyntaxhighlight>
 
{{out}}
Line 10,230 ⟶ 13,756:
 
=={{header|Simula}}==
<langsyntaxhighlight lang="simula">
BEGIN
CLASS FIFTEENPUZZLE(NUMTILES, SIDE, WIDTH, SEED);
Line 10,443 ⟶ 13,969:
P.REQUEST;
P.PRINTBOARD;
END.</langsyntaxhighlight>
{{out}}
<pre>INPUT RANDOM SEED:
Line 10,485 ⟶ 14,011:
{{works with|SML/NJ}}
{{works with|Moscow ML}}
<langsyntaxhighlight lang="sml">
(* Load required Modules for Moscow ML *)
load "Int";
Line 10,736 ⟶ 14,262:
 
val () = Console.start()
</syntaxhighlight>
</lang>
 
<b>Note:</b>
Line 10,753 ⟶ 14,279:
The window-title is used to show messages.
 
<langsyntaxhighlight lang="tcl"> # 15puzzle_21.tcl - HaJo Gurt - 2016-02-16
# http://wiki.tcl.tk/14403
 
Line 10,890 ⟶ 14,416:
 
# For some more versions, see: http://wiki.tcl.tk/15067 : Classic 15 Puzzle and http://wiki.tcl.tk/15085 : N-Puzzle
</syntaxhighlight>
</lang>
 
=={{header|UNIX Shell}}==
{{works with|Bourne Again SHell|4+}}
This plays the game in an ANSI-compliant terminal using vi/nethack movement keys to slide the tiles.
 
<syntaxhighlight lang="bash">#!/usr/bin/env bash
main() {
local puzzle=({1..15} " ") blank moves_kv i key count total last
printf '\n'
show_puzzle "${puzzle[@]}"
printf '\nPress return to scramble.'
read _
IFS= readarray -t puzzle < <(scramble "${puzzle[@]}")
printf '\r\e[A\e[A\e[A\e[A\e[A\e[A'
show_puzzle "${puzzle[@]}"
printf '\nUse hjkl to slide tiles. '
printf '\r\e[A\e[A\e[A\e[A\e[A'
total=0
while ! solved "${puzzle[@]}"; do
show_puzzle "${puzzle[@]}"
{ read blank; readarray -t moves_kv; } < <(find_moves "${puzzle[@]}")
local count=${#moves_kv[@]}/2
local -A moves
for (( i=0; i<count; i++ )); do
moves[${moves_kv[i]}]=${moves_kv[i+count]}
done
read -r -n 1 key
printf '\r '
if [[ "$key" = u ]]; then
(( total -= 2 ))
case "$last" in
h) key=l;;
j) key=k;;
k) key=j;;
l) key=h;;
esac
fi
if [[ -n "${moves[$key]}" ]]; then
last=$key
(( total++ ))
i=${moves[$key]}
puzzle[$blank]=${puzzle[i]}
puzzle[i]=' '
fi
printf '\r\e[A\e[A\e[A\e[A'
done
show_puzzle "${puzzle[@]}"
printf '\nSolved in %d moves. \n' "$total"
}
 
 
solved() {
local solved=({1..15} ' ')
[[ "${puzzle[*]}" == "${solved[*]}" ]]
}
 
show_puzzle() {
printf '%2s %2s %2s %2s\n' "$@"
}
 
find_moves() {
local puzzle=("$@")
local i j blank
for (( i=0; i<${#puzzle[@]}; ++i )); do
if [[ "${puzzle[i]}" == " " ]]; then
blank=$i
break
fi
done
local -A moves=()
if (( blank%4 )); then
# swapping blank with tile to its left
# is sliding that tile right, which is the l key
moves['l']=$(( blank-1 ))
fi
if (( blank%4 != 3 )); then
moves['h']=$(( blank+1 )) # left
fi
if (( blank >= 4 )); then
moves['j']=$(( blank-4 )) # down
fi
if (( blank < 12 )); then
moves['k']=$(( blank+4 )) # up
fi
printf '%s\n' "$blank" "${!moves[@]}" "${moves[@]}"
}
 
scramble() {
local puzzle=("$@") i j
for (( i=0; i<256; ++i )); do
local blank moves
{ read blank; readarray -t moves; } < <(find_moves "${puzzle[@]}")
moves=(${moves[@]:${#moves[@]}/2})
local dir=$(( RANDOM % ${#moves[@]} ))
j=${moves[dir]}
puzzle[blank]=${puzzle[j]}
puzzle[j]=' '
done
printf '%s\n' "${puzzle[@]}"
}
 
main "$@"</syntaxhighlight>
 
{{Out}}
<pre> 1 2 3 4
5 6 7 8
9 10 11 12
13 14 15
 
Press return to scramble.
</pre>
 
=={{header|VBA}}==
Line 10,899 ⟶ 14,536:
The last move is displayed on the input box, or an error message if an invalid move is attempted. When the puzzle is solved, the move count is displayed.
 
<syntaxhighlight lang="vb">
<lang vb>
Public iSide As Integer
Public iSize As Integer
Line 11,080 ⟶ 14,717:
ShowGrid = s
End Function
</syntaxhighlight>
</lang>
 
Sample output:
Line 11,095 ⟶ 14,732:
 
=={{header|Visual Basic .NET}}==
<langsyntaxhighlight lang="vbnet">Public Class Board
Inherits System.Windows.Forms.Form
 
Line 11,190 ⟶ 14,827:
End Function
 
End Class</langsyntaxhighlight>
 
=={{header|Visual Prolog}}==
'''Output:'''
<lang Visual Prolog>
 
[https://youtu.be/rWy3AX5HjXM 15 Puzzle in Visual Prolog - video]
 
<syntaxhighlight lang="visual prolog">
/* ------------------------------------------------------------------------------------------------------
 
Line 12,128 ⟶ 15,769:
% end of automatic code
end implement playDialog
</syntaxhighlight>
</lang>
'''Output:'''
<br>
[https://youtu.be/rWy3AX5HjXM 15 Puzzle in Visual Prolog - video]
 
=={{header|Wolfram LanguageVBScript}}==
<syntaxhighlight lang="vb">
<lang mathematica>
'----------------15 game-------------------------------------
grid = MapThread[{#1,#2} &, {Range @ 16, Range @ 16}]
'WARNING: this script uses ANSI escape codes to position items on console so
'it won't work in Windows from XP to 8.1 where Microsoft removed ANSI support...
'Windows 10, 11 or 98 are ok!!!
 
option explicit
Move[x_] := (empty = Select[grid, #[[1]]==16 &][[1,2]];
const maxshuffle=100 'level
If[(empty == x+4) || (empty == x-4) ||
(Mod[empty,4] != 0 && empty == x-1) ||
(Mod[empty,4] != 1 && empty == x+1),
oldEmpty = grid[[empty]][[1]];
grid[[empty]][[1]] = grid[[x]][[1]];
grid[[x]][[1]] = oldEmpty])
 
dim ans0:ans0=chr(27)&"["
CButton[{x_,loc_}] := If[x==16, Null, Button[x,Move @ loc]]
dim anscls:anscls=ans0 & "2J"
 
dim dirs:dirs=array(6,-1,-6,1)
Dynamic @ Grid @ Partition[CButton /@ grid,4]
dim a:a=array(-1,-1,-1,-1,-1,-1,_
</lang>
-1, 1, 2, 3, 4,-1,_
-1, 5, 6, 7, 8,-1,_
-1, 9,10,11,12,-1,_
-1,13,14,15, 0,-1,_
-1,-1,-1,-1,-1,-1)
dim b(35)
dim pos0
dim s:s=Array("W+Enter: up Z+Enter: down A+Enter: left S+Enter right ",_
"Bad move!! ",_
"You did it! Another game? [y/n]+Enter ",_
"Bye! ")
 
 
do
shuffle
draw
toxy 10,1,s(0)
do
if usr(wait()) then
draw
toxy 10,1,s(0)
else
toxy 10,1,s(1)
end if
loop until checkend
toxy 10,1,s(2)
loop until wait()="n"
toxy 10,1,s(3)
 
function wait():
toxy 11,1,"":
wait=left(lcase(wscript.stdin.readline),1):
end function
 
sub toxy(x,y,s)
wscript.StdOut.Write ans0 & x & ";" & y & "H"& " "& s
end sub
 
sub draw
dim i,j
wscript.stdout.write anscls
for i=0 to 3 'row
for j=0 to 3 'col
toxy (j*2)+2,(i*3)+3,iif(b(j*6+i+7)<>0,b(j*6+i+7)," ")
next
next
toxy 10,1,""
end sub
 
 
function checkend
dim i
for i=0 to ubound(a)
if (b(i)<>a(i)) then checkend=false : exit function
next
checkend=true
end function
 
function move(d)
dim p1
p1=pos0+d
if b(p1) <>-1 then
b(pos0)=b(p1):
b(p1)=0:
pos0=p1:
move=true
else
move=false
end if
end function
 
sub shuffle
dim cnt,r,i
randomize timer
for i=0 to ubound(a):b(i)=a(i):next
pos0=28
cnt=0
do
r=int(rnd*4)
if move(dirs(r))=true then cnt=cnt+1
loop until cnt=maxshuffle
end sub
 
function iif(a,b,c): if a then iif=b else iif=c end if:end function
 
function usr(a)
dim d
select case lcase(a)
case "w" :d=-6
case "z" :d=6
case "a" :d=-1
case "s" :d=1
end select
usr= move(d)
end function
</syntaxhighlight>
=={{header|Wren}}==
{{trans|Go}}
{{libheader|Wren-dynamic}}
{{libheader|Wren-ioutil}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="wren">import "random" for Random
import "./dynamic" for Enum
import "./ioutil" for Input
import "./fmt" for Fmt
 
var Move = Enum.create("Move", ["up", "down", "right", "left"])
 
var Rand = Random.new()
var RandMove = Fn.new { Rand.int(4) }
 
var SolvedBoard = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0]
 
var AreEqual = Fn.new { |l1, l2|
if (l1.count != l2.count) return false
for (i in 0...l1.count) {
if (l1[i] != l2[i]) return false
}
return true
}
 
class Puzzle {
construct new() {
_board = SolvedBoard.toList
_empty = 15 // _board[empty] == 0
_moves = 0
_quit = false
// Could make this configurable, 10 == easy, 50 == normal, 100 == hard
shuffle(50)
}
 
shuffle(moves) {
// we use some number of random moves to "shuffle" the board
var i = 0
while (i < moves || AreEqual.call(_board, SolvedBoard)) {
if (doMove(RandMove.call())) i = i + 1
}
}
 
isValidMove(m) {
if (m == Move.up) return [_empty - 4, (_empty/4).floor > 0]
if (m == Move.down) return [_empty + 4, (_empty/4).floor < 3]
if (m == Move.right) return [_empty + 1, _empty % 4 < 3]
if (m == Move.left) return [_empty - 1, _empty % 4 > 0]
Fiber.abort("not reached")
}
 
doMove(m) {
var i = _empty
var res = isValidMove(m)
var j = res[0]
var ok = res[1]
if (ok) {
_board.swap(i, j)
_empty = j
_moves = _moves + 1
}
return ok
}
 
play() {
var instructions = """
Please enter "U", "D", "L", or "R" to move the empty cell
up, down, left, or right. You can also enter "Q" to quit.
Upper or lowercase is accepted and only the first character
is important (i.e. you may enter "up" if you like).
"""
System.print(instructions)
System.write("\nStarting board:")
while (!AreEqual.call(_board, SolvedBoard) && !_quit) {
System.print("\n%(this)")
playOneMove()
}
if (AreEqual.call(_board, SolvedBoard)) {
System.print("\n%(this)")
System.print("You solved the puzzle in %(_moves) moves.")
}
}
 
playOneMove() {
while (true) {
var s = Input.option("Enter move #%(_moves + 1) (U, D, L, R or Q): ", "UuDdLlRrQq")
var m
if (s == "U" || s == "u") {
m = Move.up
} else if (s == "D" || s == "d") {
m = Move.down
} else if (s == "L" || s == "l") {
m = Move.left
} else if (s == "R" || s == "r") {
m = Move.right
} else if (s == "Q" || s == "q") {
System.print("Quiting after %(_moves).")
_quit = true
return
}
if (!doMove(m)) {
System.print("That is not a valid move at the moment.")
continue
}
return
}
}
 
toString {
var buf = ""
var i = 0
for (c in _board) {
if (c == 0) {
buf = buf + " ."
} else {
buf = buf + Fmt.swrite("$3d", c)
}
if (i % 4 == 3) buf = buf + "\n"
i = i + 1
}
return buf
}
}
 
var p = Puzzle.new()
p.play()</syntaxhighlight>
 
{{out}}
Sample (very easy!) game:
<pre>
Please enter "U", "D", "L", or "R" to move the empty cell
up, down, left, or right. You can also enter "Q" to quit.
Upper or lowercase is accepted and only the first character
is important (i.e. you may enter "up" if you like).
 
Starting board:
1 2 3 4
6 . 7 8
5 9 11 12
13 10 14 15
 
Enter move #51 (U, D, L, R or Q): l
 
1 2 3 4
. 6 7 8
5 9 11 12
13 10 14 15
 
Enter move #52 (U, D, L, R or Q): d
 
1 2 3 4
5 6 7 8
. 9 11 12
13 10 14 15
 
Enter move #53 (U, D, L, R or Q): r
 
1 2 3 4
5 6 7 8
9 . 11 12
13 10 14 15
 
Enter move #54 (U, D, L, R or Q): d
 
1 2 3 4
5 6 7 8
9 10 11 12
13 . 14 15
 
Enter move #55 (U, D, L, R or Q): r
 
1 2 3 4
5 6 7 8
9 10 11 12
13 14 . 15
 
Enter move #56 (U, D, L, R or Q): r
 
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 .
 
You solved the puzzle in 56 moves.
</pre>
 
=={{header|x86-64 Assembly}}==
<langsyntaxhighlight lang="assembly"> ; Puzzle15 by grosged (march 2019)
; How to play ?.. Just press one of the arrow keys then [enter] to valid
; ( press [Ctrl+C] to escape )
Line 12,232 ⟶ 16,150:
xchg ax,word[puzzle+4+rbx*4]
mov word[puzzle+4+rdx*4],ax
ret</langsyntaxhighlight>
 
=={{header|XBasic}}==
{{trans|Liberty BASIC}}
{{works with|Windows XBasic}}
<langsyntaxhighlight lang="xbasic">
PROGRAM "fifteenpuzzlegame"
VERSION "0.0001"
Line 12,393 ⟶ 16,311:
 
END PROGRAM
</syntaxhighlight>
</lang>
 
=={{header|XPL0}}==
<langsyntaxhighlight XPL0lang="xpl0">int Box, Hole, I;
[Box:= [^ ,^F,^E,^D, \starting configuration
^C,^B,^A,^9, \slide digits into ascending order
Line 12,426 ⟶ 16,344:
other []; \ignore 0 scan code prefix etc.
];
]</langsyntaxhighlight>
 
{{out}}
Line 12,437 ⟶ 16,355:
 
=={{header|Yabasic}}==
<langsyntaxhighlight Yabasiclang="yabasic">dx = 4 : dy = 4 : dxy = dx * dy
dim grid(dx, dy)
 
Line 12,514 ⟶ 16,432:
next y
next x
end sub</langsyntaxhighlight>
 
Adaptation from Phix solution
<langsyntaxhighlight Yabasiclang="yabasic">board$ = "123456789ABCDEF0"
solve$ = board$
pos = 16
Line 12,559 ⟶ 16,477:
loop
print "solved!\n"
</syntaxhighlight>
</lang>
 
=={{header|Zig}}==
<syntaxhighlight lang="zig">
const std = @import("std");
const stdout = std.io.getStdOut().writer();
 
const tokens = [16][]const u8{ " 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8", " 9", "10", "11", "12", "13", "14", "15", " " };
 
const empty_token = 15;
var empty: u8 = empty_token;
var cells: [16]u8 = undefined;
var invalid: bool = false;
 
const Move = enum { no, up, down, left, right };
 
fn showBoard() !void {
try stdout.writeAll("\n");
 
var solved = true;
var i: u8 = 0;
while (i < 16) : (i += 1) {
try stdout.print(" {s} ", .{tokens[cells[i]]});
if ((i + 1) % 4 == 0) try stdout.writeAll("\n");
if (i != cells[i]) solved = false;
}
 
try stdout.writeAll("\n");
 
if (solved) {
try stdout.writeAll("\n\n** You did it! **\n\n");
std.posix.exit(0);
}
}
 
fn updateToken(move: Move) !void {
const newEmpty = switch (move) {
Move.up => if (empty / 4 < 3) empty + 4 else empty,
Move.down => if (empty / 4 > 0) empty - 4 else empty,
Move.left => if (empty % 4 < 3) empty + 1 else empty,
Move.right => if (empty % 4 > 0) empty - 1 else empty,
else => empty,
};
 
if (empty == newEmpty) {
invalid = true;
} else {
invalid = false;
cells[empty] = cells[newEmpty];
cells[newEmpty] = empty_token;
empty = newEmpty;
}
}
 
fn waitForMove() !Move {
const reader = std.io.getStdIn().reader();
if (invalid) try stdout.writeAll("(invalid) ");
try stdout.writeAll("enter u/d/l/r or q: ");
const input = try reader.readBytesNoEof(2);
switch (std.ascii.toLower(input[0])) {
'q' => std.posix.exit(0),
'u' => return Move.up,
'd' => return Move.down,
'l' => return Move.left,
'r' => return Move.right,
else => return Move.no,
}
}
 
fn shuffle(moves: u8) !void {
var random = std.rand.DefaultPrng.init(@intCast(std.time.microTimestamp()));
const rand = random.random();
var n: u8 = 0;
while (n < moves) {
const move: Move = rand.enumValue(Move);
try updateToken(move);
if (!invalid) n += 1;
}
invalid = false;
}
 
pub fn main() !void {
var n: u8 = 0;
while (n < 16) : (n += 1) {
cells[n] = n;
}
 
try shuffle(50);
try showBoard();
 
while (true) {
try updateToken(try waitForMove());
try showBoard();
}
}
</syntaxhighlight>
 
{{out}}
<pre>
1 2 3 4
5 6 7 8
9 10 12
13 14 11 15
 
enter u/d/l/r or q: r
 
1 2 3 4
5 6 7 8
9 10 12
13 14 11 15
 
enter u/d/l/r or q: u
 
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15
 
enter u/d/l/r or q: l
 
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15
 
 
** You did it! **
</pre>
19

edits