Liberty BASIC Community Forum
« Sliding Square Puzzles »

Welcome Guest. Please Login or Register.
Nov 23rd, 2017, 03:23am


Rules|Home|Help|Search|Recent Posts|Notification


« Previous Topic | Next Topic »
Pages: 1  Notify Send Topic Print
 thread  Author  Topic: Sliding Square Puzzles  (Read 207 times)
tenochtitlanuk
Moderator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM

Gender: Male
Posts: 1169
xx Sliding Square Puzzles
« Thread started on: Jul 14th, 2017, 4:03pm »

I thought it'd be fun to create one of these, as a good example of 'getbmp' and 'drawbmp'. Basically now working. Mouse point/click to move a square- and thus the white 'hole'.

I'd added a button to scramble the positions, but then had a worrying thought- is a random scramble-and-remove-one-square going sometimes to lead to unsolvable arrangements? I can't persuade myself whether some initial conditions are unsolvable... Ideas anyone?

Perhaps I should implement a solving routine and see if it ever hangs?? Or add a random series of moves from the solved position??

Anyway, work in progress shown below. Will put up code here and on my site soon..
User Image

Anyone else got working code for something similar?
EDIT numbers are just for demo purposes- any image can be used..
« Last Edit: Jul 14th, 2017, 4:04pm by tenochtitlanuk » User IP Logged

meerkat
Junior Member
ImageImage


member is offline

Avatar




PM

Gender: Male
Posts: 67
xx Re: Sliding Square Puzzles
« Reply #1 on: Jul 14th, 2017, 4:57pm »

Here's one I wrote a long time ago in Run Basic.
Not nearly as nice as your's - no graphics..

Code:
' ------------------------------------------
' Put the numbers in order
' ------------------------------------------
bf$	= "<SPAN STYLE='font-family:arial; font-weight:700; font-size:20pt'>"
call SetCSS

dim xBox(16)
' -------------------------------------
' Fill the boxes with numbers 1 to 15
' -------------------------------------
for i = 1 to 15
xBox(i)	= i
next i

' -----------------------------------
' Randomally select a box to be open
' The open box has the number 0
' -----------------------------------
x 		= int(rnd(1)*15) + 1
xBox(x)		= 0
xBox(16)	= x

' ----------------------------------
' The boxes are in order by 1 to 15
' Here we shuffle the boxes to make
' the boxes random
' ----------------------------------
numShuffles	= 2
for 	i 	= 1 to 16 * numShuffles
	i1	= int(rnd(1)*16) + 1
	i2	= int(rnd(1)*16) + 1
	hold	= xBox(i1)
	xBox(i1)= xBox(i2)
	xBox(i2)= hold
next i


' ----------------------------------
' find the open box (0) and call it
' the openBox
' ----------------------------------
for i = 1 to 16
if xBox(i) = 0 then openBox = i
next i

' ---------------------------------------
' The main loop
' ---------------------------------------
[loop]

' ----------------------------------------
' Find the row and column of the openBox
' ----------------------------------------
openRow	= int((openBox -1) / 4) + 1
openCol	= ((openBox - 1) mod 4) + 1

cls
' --------------------------------------
' Number Puzzle
' Goal - place numbers in order
' --------------------------------------
html bf$;"<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=6 width=320 height=240 bgcolor=yellow>"
thisBox = 0
for thisRow = 1 to 4
	html "<TR align=center>"
	for thisCol = 1 to 4
		thisBox	= thisBox + 1
		if thisBox = openBox then
			html "<TD bgcolor=white></TD>"	' open box
		    else
			html "<TD BGCOLOR=lightblue width=25%>"
			
			' -------------------------------------------------
			' This determines if this box's row and col is next
			' to the open box's row and col
			' If it is then display it as a link
			' -------------------------------------------------
			xRow	= abs(thisRow - openRow)
			xCol	= abs(thisCol - openCol)
			if xRow + xCol = 1 then
			link	#movBox,str$(xBox(thisBox)),[doMov]
				#movBox cssclass("sBtn")
				#movBox setkey(thisBox)
			else
				html xBox(thisBox)
			end if
		html "</TD>"
		end if
	next thisCol
	html "</TR>"
next thisRow
html "</TABLE>"
wait

' -------------------------------------
' Move the users selected box
' -------------------------------------
[doMov]
thisBox 	= val(EventKey$)
hold		= xBox(openBox)
xBox(openBox)	= xBox(thisBox)
xBox(thisBox)	= hold
openBox		= thisBox

' -------------------------------
' See if the numbers are in order
' If so - they are a winner
' -------------------------------
youWin		= 1
for i = 1 to 15
if xBox(i) <> i then youWin = 0
next i
if youWin = 1 then
	print "Horray! You Win"
	wait
end if

goto [loop]
wait

' ----------------------------
' CSS
' ----------------------------
SUB SetCSS 
CSSClass "a.sBtn", "{
Border-Width:6px; Border-Color:lightGreen; Border-Style:solid; background:lightGreen; 
Font-Size:20pt; Font-Weight:Bold; Font-Family:Arial; color:black;Text-Decoration:None;
}"
 END SUB 
User IP Logged

tenochtitlanuk
Moderator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM

Gender: Male
Posts: 1169
xx Re: Sliding Square Puzzles
« Reply #2 on: Jul 15th, 2017, 04:19am »

Code for present version.. needs 400x400 BMP to work with..
<ctrl><refresh> to rerun the animation.

User Image

Code:
  '***************************************************************************
    '***                                                                     ***
    '***     slidingPuzzle6.bas       12/07/17       tenochtitlanuk          ***
    '***                                                                     ***
    '***************************************************************************


    '   to-dos..
    '       make randomize a button-selected option     -   done
    '       implement 'move clicked square if....'      -   done
    '       add option to save present state??          -   done

    '   Add ImageMagick calls to make the animation and scale
    '       convert aniSquares4.gif -resize 25% quarterSizeAni.gif
    '       convert -delay 100 *.bmp anim.gif

    '       add timing and best-time?



    nomainwin

    WindowWidth  =550
    WindowHeight =470

    dim board( 5, 5)    '   4x4 sub-images.... indexed 1 to 4.  0 and 5 are just outside.
    version      =999   '   for saving image sequence....

    graphicbox #w.gb1, 10, 10, 400, 400

    button #w.b1, "ScreenSave",[screenSave], LR, 90, 350
    button #w.b2, "Randomize", [randomize],  LR, 90, 250



    open "Sliding Box Puzzle" for window as #w

    #w "trapclose quit"

    #w.gb1 "when leftButtonUp [update]"

  [again]
    filedialog "Choose 400x400 bitmap", "testImage.bmp", fName$

    if fn$ ="*.bmp" then [again]

    loadbmp "scr", fName$   'testImage.bmp"

    #w.gb1 "down"
    #w.gb1 "getbmp scr16 0 0 99 99"

    #w.gb1 "drawbmp scr 0 0 ; flush"

    timer 4000, [o]
    wait
  [o]
    timer 0

    for y =0 to 3                   '   create the squares....
        for x = 0 to 3
            Xs  =x *100
            Ys  =y *100
            num = y *4 +x
            #w.gb1 "getbmp scr" +right$( "00" +str$( num), 2) +" "; Xs; " "; Ys; " 99 99"
            board( x +1, y +1) =4 *y +x     '   holds number of screen eg 'scr3' held as '3'.
                                            '   a value of 16 will be used for the empty square...
        next x
    next y

    xN =100 *int( 4 *rnd(1))
    yN =100 *int( 4 *rnd(1))
    #w.gb1 "drawbmp scr16 "; xN; " "; yN
    board( 1 +xN /100, 1 +yN /100) =16

    wait

  [update]                                  '   x, y are <=3 and >=0
    x =int( MouseX /100)
    y =int( MouseY /100)                    '   This is square clicked on. Look for an empty neighbour in four directions...

    if board( 1 +x, 1 +y) =16 then notice "Click a FILLED square!"

    done =0

    select case                                        'The selected square x,y is to....
        case (y <3) and (board( 1+x, 1+y +1) =16)          '   swap with empty square below which moves up
            xN =x: yN =y +1: done =1
        case (x <3) and (board( 1+x +1, 1+y) =16)          '   swap with empty square to right which moves left)
            xN =x +1: yN =y: done =1
        case (x >0) and (board( 1+x -1, 1+y) =16)          '   swap with empty square to left which moves right
            xN =x -1: yN =y: done =1
        case (y >0) and (board( 1+x, 1+y -1) =16)          '   swap with empty square above which moves down
            xN =x: yN =y -1: done =1
        case else
            done =0
    end select

    if done =1 then
        board( 1+xN, 1+yN)      =board( 1+x, 1+y)
        board( 1+x,  1+y)       =16

        scrNum$ =right$( "00" +str$( board( 1+xN, 1+yN)), 2)

        #w.gb1 "drawbmp scr"; scrNum$; " ";  xN *100; " "; yN *100
        #w.gb1 "drawbmp scr16 ";             x  *100; " "; y  *100
    end if

    wait

  [screenSave]
    #w.gb1 "getbmp sc 0 0 399 399"
    bmpsave "sc", "savedScreens\screen" +right$( "000" +str$( version), 3) +".bmp"
    version =version -1
    wait

  [randomize]
    ' randomize squares....
    '
    r$ =""

    for i =0 to 15
        r$ =r$ +right$( "00" +str$( i), 2)
    next i

    for x =0 to 3
        for y =0 to 3
            l   =len( r$)
            p   =1 +2 *int( l /2 *rnd( 1))
            N$  =mid$( r$, p, 2)

            r$  =left$( r$, p -1) +mid$( r$, p +2)

            Xs  =x *100
            Ys  =y *100

            board$( 1+x, 1+y) =N$
            #w.gb1 "drawbmp scr" +N$ +" "; Xs; " "; Ys
        next y
    next x

    sx =100 *int( 4 *rnd( 1)): sy =100 *int( 4 *rnd( 1))
    #w.gb1 "drawbmp scr16 "; sx; " "; sy
    wait


    sub quit h$
        close #w
        end
    end sub
 

« Last Edit: Jul 15th, 2017, 04:20am by tenochtitlanuk » User IP Logged

Jim Hiley
Full Member
ImageImageImage


member is offline

Avatar




PM


Posts: 202
xx Re: Sliding Square Puzzles
« Reply #3 on: Jul 16th, 2017, 01:38am »

on Jul 14th, 2017, 4:03pm, tenochtitlanuk wrote:
I'd added a button to scramble the positions, but then had a worrying thought- is a random scramble-and-remove-one-square going sometimes to lead to unsolvable arrangements? I can't persuade myself whether some initial conditions are unsolvable... Ideas anyone?


To be sure that the puzzle CAN be solved, how about doing a dummy run "backwards" starting with the completed image and making a random number of moves in random directions to get to the starting place.

You could do it in full view (but too fast to remember) or behind the scenes. The number of moves could be used as a degree of difficulty.

Running your code, I kept getting errors when I hit "randomise"
You need to prevent the randomise button from doing anything until all the squares have been drawn.
I added readyToGo = 1 after the squares were drawn and
if readyToGo = 1 then

at the start of the randomize sub.

I also get a few errors which I am yet to track down.

Thanks for the fun.
Jim
User IP Logged

tenochtitlanuk
Moderator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM

Gender: Male
Posts: 1169
xx Re: Sliding Square Puzzles
« Reply #4 on: Jul 16th, 2017, 02:42am »

Thanks Jim fo the comments. Haven't seen you around recently... Hi!

I'd already added last night lines disabling the two buttons and enabling them after the setup and delay.
And had similar thoughts about creating a guaranteed solvable initial state.

You'll have noticed I often put a 'to-do' list at the start of my code. I'll certainly work further on this one, even tho' playing the game is rather boring and irritating! A timer and a saved 'best time' league? Add ability to load any image type and resize it? Add option to add superposed numbers to allow 'cheating' on difficult images?

But I WOULD like a proof- or reference to one- that some random arrangements are unsolvable ( or not)
User IP Logged

Jim Hiley
Full Member
ImageImageImage


member is offline

Avatar




PM


Posts: 202
xx Re: Sliding Square Puzzles
« Reply #5 on: Jul 16th, 2017, 02:43am »

In the randomise sub, you used board$() instead of board()
You also didn't tell the array which squire had the blank in it.
Code:
    '***************************************************************************
    '***                                                                     ***
    '***     slidingPuzzle6.bas       12/07/17       tenochtitlanuk          ***
    '***                                                                     ***
    '***************************************************************************


    '   to-dos..
    '       make randomize a button-selected option     -   done
    '       implement 'move clicked square if....'      -   done
    '       add option to save present state??          -   done

    '   Add ImageMagick calls to make the animation and scale
    '       convert aniSquares4.gif -resize 25% quarterSizeAni.gif
    '       convert -delay 100 *.bmp anim.gif

    '       add timing and best-time?



    'nomainwin

    WindowWidth  =550
    WindowHeight =470

    dim board( 5, 5)    '   4x4 sub-images.... indexed 1 to 4.  0 and 5 are just outside.
    version      =999   '   for saving image sequence....

    graphicbox #w.gb1, 10, 10, 400, 400

    button #w.b1, "ScreenSave",[screenSave], LR, 90, 350
    button #w.b2, "Randomize", [randomize],  LR, 90, 250



    open "Sliding Box Puzzle" for window as #w

    #w "trapclose quit"

    #w.gb1 "when leftButtonUp [update]"

[again]
    filedialog "Choose 400x400 bitmap", "*.bmp", fName$

    if fName$ ="*.bmp" then [again]

    loadbmp "scr", fName$   'testImage.bmp"

    #w.gb1 "down"
    #w.gb1 "getbmp scr16 0 0 99 99"

    #w.gb1 "drawbmp scr 0 0 ; flush"

    timer 4000, [o]
    wait
[o]
    timer 0

    for y =0 to 3                   '   create the squares....
        for x = 0 to 3
            Xs  =x *100
            Ys  =y *100
            num = y *4 +x
            #w.gb1 "getbmp scr" +right$( "00" +str$( num), 2) +" "; Xs; " "; Ys; " 99 99"
            board( x +1, y +1) =4 *y +x     '   holds number of screen eg 'scr3' held as '3'.
            '   a value of 16 will be used for the empty square...
        next x
    next y

    xN =100 *int( 4 *rnd(1))
    yN =100 *int( 4 *rnd(1))
    #w.gb1 "drawbmp scr16 "; xN; " "; yN
    board( 1 +xN /100, 1 +yN /100) =16
    readyToGo = 1
    wait

[update]                                  '   x, y are <=3 and >=0
    x =int( MouseX /100)
    y =int( MouseY /100)                    '   This is square clicked on. Look for an empty neighbour in four directions...
    print x,y,board( 1 +x, 1 +y)
    if board( 1 +x, 1 +y) =16 then notice "Click a FILLED square!"

    done =0

    select case                                        'The selected square x,y is to....
        case (y <3) and (board( 1+x, 1+y +1) =16)          '   swap with empty square below which moves up
        xN =x: yN =y +1: done =1
        case (x <3) and (board( 1+x +1, 1+y) =16)          '   swap with empty square to right which moves left)
        xN =x +1: yN =y: done =1
        case (x >0) and (board( 1+x -1, 1+y) =16)          '   swap with empty square to left which moves right
        xN =x -1: yN =y: done =1
        case (y >0) and (board( 1+x, 1+y -1) =16)          '   swap with empty square above which moves down
        xN =x: yN =y -1: done =1
        case else
        done =0
    end select

    if done =1 then
        board( 1+xN, 1+yN)      =board( 1+x, 1+y)
        board( 1+x,  1+y)       =16

        scrNum$ =right$( "00" +str$( board( 1+xN, 1+yN)), 2)

        #w.gb1 "drawbmp scr"; scrNum$; " ";  xN *100; " "; yN *100
        #w.gb1 "drawbmp scr16 ";             x  *100; " "; y  *100
    end if

    wait

[screenSave]
    #w.gb1 "getbmp sc 0 0 399 399"
    bmpsave "sc", "savedScreens\screen" +right$( "000" +str$( version), 3) +".bmp"
    version =version -1
    wait

[randomize]
    ' randomize squares....
    '
    if readyToGo = 1 then

        r$ =""

        for i =0 to 15
            r$ =r$ +right$( "00" +str$( i), 2)
        next i

        for x =0 to 3
            for y =0 to 3
                l   =len( r$)
                p   =1 +2 *int( l /2 *rnd( 1))
                N$  =mid$( r$, p, 2)

                r$  =left$( r$, p -1) +mid$( r$, p +2)

                Xs  =x *100
                Ys  =y *100

                board( 1+x, 1+y) =val(N$)
                #w.gb1 "drawbmp scr" +N$ +" "; Xs; " "; Ys
            next y
        next x

        sx =int( 4 *rnd( 1)): sy =int( 4 *rnd( 1))
        #w.gb1 "drawbmp scr16 "; sx*100; " "; sy*100
        board( 1+sx, 1+sy) = 16
    end if
    wait


sub quit h$
    close #w
    end
end sub
 

An option for 3x3 would make life easier for some of us!
User IP Logged

tenochtitlanuk
Moderator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM

Gender: Male
Posts: 1169
xx Re: Sliding Square Puzzles
« Reply #6 on: Jul 16th, 2017, 09:47am »

Fair cop! I was originally going to hold the board via imagenames, ie strings, before changing to just numbers. Since any reasonable puzzle has <10 for the dimensions, the 'dim' is unnecessary anyway. And had already corrected the adding of the blank after randomizing.

Feel free to modify or suggest further changes. It was intended as an encouragement for people to modify or use the code.... Takes me back to the Fifties and sliding blocks of 'real plastic' ratger than pixels...
User IP Logged

Pages: 1  Notify Send Topic Print
« Previous Topic | Next Topic »

Rules|Home|Help|Search|Recent Posts|Notification

Donate $6.99 for 50,000 Ad-Free Pageviews!

| |

This forum powered for FREE by Conforums ©
Sign up for your own Free Message Board today!
Terms of Service | Privacy Policy | Conforums Support | Parental Controls