15 puzzle game: Difference between revisions

From Rosetta Code
Content added Content deleted
(J: bugfix (board needs to be solvable))
m (J: present move options in sorted order)
Line 20: Line 20:


shift=: |.!._"0 2
shift=: |.!._"0 2
taxi=: |:,/"2(_1 1 shift i.4 4),_1 1 shift"0 1/ i.4 4
taxi=: /:~"1 |:,/"2(_1 1 shift i.4 4),_1 1 shift"0 1/ i.4 4


showboard=:3 :0
showboard=:3 :0
Line 90: Line 90:
│13│14│15│12│
│13│14│15│12│
└──┴──┴──┴──┘
└──┴──┴──┴──┘
Valid moves: 7 15 10 11
Valid moves: 7 10 11 15
move which number? 11
move which number? 11
current board:
current board:
Line 102: Line 102:
│13│14│15│12│
│13│14│15│12│
└──┴──┴──┴──┘
└──┴──┴──┴──┘
Valid moves: 8 12 11
Valid moves: 8 11 12
move which number? 12
move which number? 12
current board:
current board:

Revision as of 15:12, 6 February 2016

15 puzzle game is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Implement the Fifteen Puzzle Game.

J

Implementation:

<lang J>require'general/misc/prompt'

genboard=:3 :0

 b=. ?~16
 if. 0<C.!.2 b do.
   b=. (<0 _1)C. b
 end.
 a: (b i.0)} <"0 b

)

done=: (<"0]1+i.15),a:

shift=: |.!._"0 2 taxi=: /:~"1 |:,/"2(_1 1 shift i.4 4),_1 1 shift"0 1/ i.4 4

showboard=:3 :0

 echo 'current board:'
 echo 4 4$y

)

help=:0 :0

 Slide a number block into the empty space
 until you get:

┌──┬──┬──┬──┐ │1 │2 │3 │4 │ ├──┼──┼──┼──┤ │5 │6 │7 │8 │ ├──┼──┼──┼──┤ │9 │10│11│12│ ├──┼──┼──┼──┤ │13│14│15│ │ └──┴──┴──┴──┘

 Or type 'q' to quit.

)

getmove=:3 :0

 showboard y
 blank=. y i. a:
 options=. ;y {~ _ -.~ blank { taxi
 whilst. -. n e. options do.
   echo 'Valid moves: ',":options
   t=. prompt 'move which number? '
   if. 'q' e. t do.
     echo 'giving up'
     throw.
   elseif. 'h' e. t do.
     echo help
     showboard y
   end.
   n=. {._".t
 end.
 (<blank,y i.<n) C. y

)

game=: 3 :0

 echo '15 puzzle'
 echo 'h for help, q to quit'
 board=. genboard
 whilst. -. done-:board do.
   board=. getmove board
 end.
 showboard board
 echo 'You win.'

)</lang>

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.

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:

<lang J> game 15 puzzle h for help, q to quit current board: ┌──┬──┬──┬──┐ │1 │2 │3 │4 │ ├──┼──┼──┼──┤ │5 │6 │7 │8 │ ├──┼──┼──┼──┤ │9 │10│ │11│ ├──┼──┼──┼──┤ │13│14│15│12│ └──┴──┴──┴──┘ Valid moves: 7 10 11 15 move which number? 11 current board: ┌──┬──┬──┬──┐ │1 │2 │3 │4 │ ├──┼──┼──┼──┤ │5 │6 │7 │8 │ ├──┼──┼──┼──┤ │9 │10│11│ │ ├──┼──┼──┼──┤ │13│14│15│12│ └──┴──┴──┴──┘ Valid moves: 8 11 12 move which number? 12 current board: ┌──┬──┬──┬──┐ │1 │2 │3 │4 │ ├──┼──┼──┼──┤ │5 │6 │7 │8 │ ├──┼──┼──┼──┤ │9 │10│11│12│ ├──┼──┼──┼──┤ │13│14│15│ │ └──┴──┴──┴──┘ You win.</lang>

Ring

CalmoSoft Fifteen Puzzle Game written in Ring Programming Language (http://ring-lang.net)

Output: [image]

The code:

load "guilib.ring"

App1 = new qApp {

        rnd = []  
        empty = 16        

        win1 = new qWidget() {
                   move(0,0)
                   resize(350,400)
                   setWindowTitle("CalmoSoft Fifteen Puzzle Game")
                   
                new qPushButton(win1)
                {
                       setgeometry(100,220,120,30)
                       settext("Scramble")
                       setclickevent("scramble()")                        
                }

                 btn1 = new qPushButton(win1)
                {
                            setgeometry(100,100,30,30)
                            setclickevent("moveTile(1)")                   
                }                

                btn2 = new qPushButton(win1)
                {
                           setgeometry(130,100,30,30)
                           setclickevent("moveTile(2)")                      
                } 

                btn3 = new qPushButton(win1)
                {
                           setgeometry(160,100,30,30)
                           setclickevent("moveTile(3)")                        
                }
 
                btn4 = new qPushButton(win1)
                {
                           setgeometry(190,100,30,30)
                           setclickevent("moveTile(4)")
                }

                btn5 = new qPushButton(win1)
                {
                           setgeometry(100,130,30,30)
                           setclickevent("moveTile(5)")
                }
    
                btn6 = new qPushButton(win1)
                {
                           setgeometry(130,130,30,30)
                           setclickevent("moveTile(6)")
                }

                btn7 = new qPushButton(win1)
                {
                           setgeometry(160,130,30,30)
                           setclickevent("moveTile(7)")
                }

                btn8 = new qPushButton(win1)
                {
                           setgeometry(190,130,30,30)
                           setclickevent("moveTile(8)")
                }

                btn9 = new qPushButton(win1)   
                {
                           setgeometry(100,160,30,30)
                           setclickevent("moveTile(9)")
                }

                btn10 = new qPushButton(win1)   
                {
                             setgeometry(130,160,30,30)
                             setclickevent("moveTile(10)")
                }

                btn11 = new qPushButton(win1)   
                {
                             setgeometry(160,160,30,30)
                             setclickevent("moveTile(11)")
                }

                btn12 = new qPushButton(win1)   
                {
                             setgeometry(190,160,30,30)
                             setclickevent("moveTile(12)")
                }

                btn13 = new qPushButton(win1)   
                {
                             setgeometry(100,190,30,30)
                             setclickevent("moveTile(13)")
                }

                btn14 = new qPushButton(win1)   
                {
                             setgeometry(130,190,30,30)
                             setclickevent("moveTile(14)")
                }

                btn15 = new qPushButton(win1)   
                {
                             setgeometry(160,190,30,30)
                             setclickevent("moveTile(15)")
                }

                btn16 = new qPushButton(win1)   
                {
                             setgeometry(190,190,30,30)
                             settext("")
                             setclickevent("moveTile(16)")
                }

                resetbtn = new qPushButton(win1)   
                {
                                setgeometry(100,250,120,30)
                                settext("Reset")
                                setclickevent("resetTiles()")
                }

                button = [btn1, btn2, btn3, btn4, btn5, btn6, btn7, btn8, btn9, btn10, btn11, btn12, btn13, btn14, btn15, btn16]
                for i = 1 to 15
                     button[i] {settext(string(i))}
                next
                show()
        }
        exec()
}

func scramble
       for n= 1 to 300   
            nr=random(16)
            up = (empty = (nr - 4))
            down = (empty = (nr + 4))
            left = ((empty = (nr - 1)) and ((nr % 4) != 1))
            right = ((empty = (nr + 1)) and ((nr % 4) != 0))
            move = up or down or left  or right
            if move = 1 and (nr != 0)
               button[nr] { temp = text() }
               button[empty]  {settext(temp)}
               button[nr]  {settext("")}
               empty = nr
            ok
       next

func moveTile nr2
       up = (empty = (nr2 - 4))
       down = (empty = (nr2 + 4))
       left = ((empty = (nr2- 1)) and ((nr2 % 4) != 1))
       right = ((empty = (nr2 + 1)) and ((nr2 % 4) != 0))
       move = up or down or left  or right
       if move = 1    
          button[nr2] { temp2 = text() }
          button[empty]  {settext(temp2)}
          button[nr2]  {settext("")}
          empty = nr2
       ok

func resetTiles
       empty = 16
       for i = 1 to 15
            button[i] {settext(string(i))}
       next
       button[16] {settext("")}