Engel's enigma - a simple rotating disc puzzle.

Game development specific discussions.
Post Reply
3622
Posts: 24
Joined: Mar 14, 2015 23:53

Engel's enigma - a simple rotating disc puzzle.

Post by 3622 »

Shuffle the two discs and then unscramble them back to their original starting position.

Invented by Douglas A Engel and features in The Armchair Universe by A K Dewdney.

Requires Multiput.bi ( thanks to D J Peters). I include it in the same directory .

The top arrow buttons rotate the top disc clockwise / anticlockwise.
The bottom buttons do the same for the bottom disc.

The Restart button resets the puzzle to its original starting position.

The Shuffle button resets the puzzle to its original starting position and then shuffles the two discs.

Quit program by clicking close (the X) in the title bar.

No win detection included as it's kind of obvious.

No solve routine included as it's kind of difficult.

Code: Select all

'		Engel's Enigma

#include "MultiPut.bi"													' Thank you DJ

screen 19, 32, 2
windowtitle "Engel's Enigma"

randomize

const as ulong white = rgb (255, 255, 255)
const as ulong near_white = rgb (255, 255, 254)
const as ulong transparent = rgb (255, 0, 255)
const as ulong black = rgb (0, 0, 0)
const as ulong near_black = rgb (0, 0, 1)
const as ulong red = rgb (255, 0, 0)
const as ulong blue = rgb (0, 0, 255)
const as ulong green = rgb (0, 128, 0)
const as ulong yellow = rgb (255, 255, 0)
const as ulong bluegrey = rgb (128, 128, 255)
const as ulong pink = rgb (255, 128, 128)
const as ulong brown = rgb (128, 0, 0)

type colour
    x as integer
    y as integer
    col as ulong
end type

dim as colour top_col(30), bot_col(30)    

dim as integer i, j 
dim as integer x, y, buttons, result

dim shuffle As Any Ptr = ImageCreate(100, 100)
dim restart As Any Ptr = ImageCreate(100, 100)
dim clock as any ptr = imagecreate (99, 99)
dim aclock as any ptr = imagecreate (99, 99)
dim top as any ptr = imagecreate(341, 341)
dim bottom as any ptr = imagecreate(341, 341)

data 351,52,red,399,50,red,448,53,red,493,77,blue,518,118,blue,539,160,blue
data 540,213,green,516,257,green,492,301,green,445,324,bluegrey,400,326,bluegrey,351,323,bluegrey
data 305,299,green,280,257,green,259,215,green,256,162,yellow,281,119,yellow,304,79,yellow
data 351,103,pink,397,107,pink,449,108,pink,467,147,pink,490,189,pink,467,229,pink
data 447,270,pink,397,270,pink,353,271,pink,331,227,pink,304,189,pink,328,147,pink
data 400, 190, brown
data 351,274,pink,399,272,pink,447,273,pink,493,300,green,517,339,green,536,383,green
data 540,436,yellow,521,479,yellow,491,515,yellow,446,543,red,399,546,red,350,543,red
data 302,517,blue,279,479,blue,260,433,blue,258,381,green,277,341,green,303,300,green
data 353,324,bluegrey,402,328,bluegrey,446,325,bluegrey,469,369,bluegrey,494,407,bluegrey,470,446,bluegrey
data 446,493,bluegrey,400,492,bluegrey,353,489,bluegrey,329,448,bluegrey,306,409,bluegrey,329,365,bluegrey
data 400, 411, brown

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

sub draw_box (x as integer, y as integer, w as integer, h as integer)

line (x, y) - step (w, 0), white
line (x, y) - step (0,  h), white

line (x, y + h) - step ( w, 0), black
line (x + w, y) - step (0,  h), black

end sub

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

sub draw_shuffle

cls
line (0, 0) - step (100, 100), transparent, bf
color black, transparent
'print : print "Shuffle"
draw string (0, 16), "Shuff"
draw string (38, 16), "le"
color white, black

end sub

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

sub draw_restart

cls
line (0, 0) - step (100, 100), transparent, bf
color black, transparent
print : print "Restart"
color white, black

end sub

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

sub draw_clock

cls
paint (0, 0),transparent

line (0, 0) - step (100, 100), black, b

circle (49, 59), 30, near_black, , , , f
circle (49, 59), 20, transparent, , , , f

line (0, 51) - step (49, 15), transparent
line (99, 40) - step (-50, 20), transparent

paint (49, 85), transparent

line (58, 56) - step (29, -10), black
line - step (-9, 19), black
line -  (58, 56), black

paint (63, 56), black

end sub

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

sub draw_aclock

cls
paint (0, 0), transparent

line (0, 200) - step (100, 100), black, b

circle (50, 259), 30, near_black, , , , f
circle (50, 259), 20, transparent, , , , f

line (100, 251) - step (-49, 15), transparent
line (0, 240) - step (50, 20), transparent

paint (50, 285), transparent

line (41, 255) - step (-29, -10), black
line - step (9, 19), black
line -  (41, 255), black

paint (35, 255), black

end sub

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

sub draw_disc (x as integer)

cls

circle (209, 300 + x), 170, near_white
circle (591, 300 + x), 170, near_white

circle (400, -31 + x), 170, near_white

circle (591, 79 + x), 170, near_white
circle (209, 79 + x), 170, near_white

circle (400, 190 + x), 50, near_white
circle (400, 190 + x), 170, near_white

circle (400, 411 + x), 50, near_white
circle (400, 411 + x), 170, near_white

line (336, 80 + x) - step (128, 0), near_white
line (336, 300 + x) - step (128, 0), near_white

line (336, 80 + x) - step (-62, 110), near_white
line - step (62, 110), near_white
line (230, 190 + x) - (273, 190 + x), near_white

line (336, 80 + x) - step (-64, -110), near_white
line (336, 300 + x) - step (-62, 110), near_white
line (464, 300 + x) - step (62, 110), near_white
line (464, 300 + x) - step (62, -110), near_white
line - step (50, 0), near_white
line (526, 190 + x) - step (-62, -110), near_white
line - step (62, -110), near_white

circle (400, 190 + x), 170, white
paint (0, 0), transparent, white

circle (400, 190 + x), 170, near_white

end sub

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

sub start_config_discs (top_col () as colour, bot_col() as colour, top as any ptr, bottom as any ptr)

dim as integer i

restore

for i = 0 to 30
    read top_col(i).x, top_col(i).y, top_col(i).col
next    
    
for i = 0 to 30
    read bot_col(i).x, bot_col(i).y, bot_col(i).col
next  

circle top, (400 - 229, 190 - 19), 170, near_white '
for i = 0 to 30
    paint top, (top_col(i).x - 229, top_col(i).y - 19), top_col(i).col, near_white
next    
circle top, (400 - 229, 190 - 19), 170, transparent '
put (229, 19), top, trans

circle bottom, (400 - 229, 411 - 240), 170, near_white '
for i = 0 to 30
    paint bottom, (bot_col(i).x - 229, bot_col(i).y - 240), bot_col(i).col, near_white
next   
circle bottom, (400 - 229, 411 - 240), 170, transparent '
put (229, 240), bottom, trans

end sub

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

sub rotate_discs(top_col() as colour, bot_col() as colour, top as any ptr, bottom as any ptr, image as any ptr, direction as integer, which_disc as integer, speed as integer, stepp as integer)

dim as integer i

for i = 1 to (60 * stepp) step speed
    screenlock()
    if which_disc = 0 then  
        multiput ( , 400, 190, image, , , i * direction, true)
        circle  (400, 190), 170, near_white '
    else
        multiput ( , 400, 411, image, , , i * direction, true)
        circle  (400, 411), 170, near_white '
    end if            
    screenunlock()
    sleep 12
next


for i = 0 to 29
    top_col(i).col = point (top_col(i).x, top_col(i).y)
    bot_col(i).col = point (bot_col(i).x, bot_col(i).y)
next    

screenlock

pcopy 1, 0
circle top, (400 - 229, 190 - 19), 170, near_white '
for i = 0 to 30
    paint top, (top_col(i).x - 229, top_col(i).y - 19), top_col(i).col, near_white
next    
circle top, (400 - 229, 190 - 19), 170, transparent '
put (229, 19), top, trans


circle bottom, (400 - 229, 411 - 240), 170, near_white '
for i = 0 to 30
    paint bottom, (bot_col(i).x - 229, bot_col(i).y - 240), bot_col(i).col, near_white
next   
circle bottom, (400 - 229, 411 - 240), 170, transparent '
put (229, 240), bottom, trans

screenunlock

end sub

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

sub shuffle_discs (top_col () as colour, bot_col() as colour, top as any ptr, bottom as any ptr)

dim as integer i, rand1, rand2, stepp

start_config_discs(top_col(), bot_col(), top, bottom)

sleep 250

for i = 0 to 9
    if i > 4 then 
        rand1 = 1
    else
        rand1 = -1
    end if 
    rand2 xor= 1       
    stepp = rnd * 5
    if stepp = 0 then stepp = 5         
    if rand2 = 0 then
        rotate_discs(top_col(), bot_col(), top, bottom, top, rand1, rand2, 4, stepp)        
    else
        rotate_discs(top_col(), bot_col(), top, bottom, bottom, rand1, rand2, 4, stepp)    
    end if
next                

end sub

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

draw_shuffle
Get (0, 0) - (99, 99), shuffle

draw_restart
Get (0, 0) - (99, 99), restart

draw_clock
get (1, 1) - (99, 99), clock

draw_aclock
get (1, 201) - step (98, 98), aclock

draw_disc (0)
get (229, 19) - step (341, 341), top

draw_disc (221)
get (229, 240) - step (341, 341), bottom

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

' initialise back_drop

screenlock

for i = 0 to 799
    for j = 0 to 599
        pset (i, j), rgb (128 + ((rnd * 20) - 10), 128 + ((rnd * 20) - 10), 215 + ((rnd * 80) - 40))          
    next
next       

draw_box (58, 48, 100, 100)
draw_box (642, 48, 100, 100)

draw_box (58, 263, 100, 75)
draw_box (642, 263, 100, 75)

draw_box (58, 459, 100, 100)
draw_box (642, 459,100, 100)

put (59, 49), aclock, trans
put (643, 49), clock, trans

multiput ( , 143, 340, shuffle, 1.5, 1.5, 0, true)
multiput ( , 725, 339, restart, 1.5, 1.5, 0, true)

put (59, 458), aclock, trans
put (643, 458), clock, trans

line (294, 6) - step (212, 0), near_white
line (294, 594) - step (212, 0), near_white

line (400, 190) - step (-106, -183), near_white
line (400, 190) - step (106, -183), near_white

line (400, 411) - step (-106, 183), near_white
line (400, 411) - step (106, 183), near_white

line (400, 190) - step (-212, 0), near_white
line - step (106, -183), near_white
line (400, 190) - step (212, 0), near_white
line - step (-106, -183), near_white
line (400, 411) - step (-212, 0), near_white
line - step (106, 183), near_white
line (400, 411) - step (212, 0), near_white
line - step (-106, 183), near_white

line (188, 190) - step (64, 111), near_white

line (612, 190) - step (-64, 111), near_white

line (188, 411) - step (64, -111), near_white

line (612, 411) - step (-64, -111), near_white

circle (400, 190), 170, near_white
circle (400, 411), 170, near_white

paint (400, 14), red, near_white
paint(550, 98), blue, near_white
paint(540, 300), green, near_white
paint(550, 500), yellow, near_white
paint (400, 588), red, near_white
paint(247, 500), blue, near_white
paint(260, 300), green, near_white
paint(247, 100), yellow, near_white

screenunlock

imagedestroy shuffle
imagedestroy restart
imagedestroy clock
imagedestroy aclock

pcopy 0, 1

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

start_config_discs (top_col(), bot_col(), top, bottom)

do

    do
        result = getmouse (x, y, , buttons)
        if inkey = chr(255) & "k" then 
            imagedestroy top
            imagedestroy bottom
            exit do, do
        end if    
        sleep 25
    loop while result <> 0    
    
    if buttons = 1 then

        if x > 58 and x < 158 then
            select case y
                case 49 to 147
                    line (58, 48) - step (100, 100), bluegrey, b
                    sleep 150
                    draw_box (58, 48, 100, 100)               
                    rotate_discs(top_col(), bot_col(), top, bottom, top, -1, 0, 3, 1)
                case 264 to 337
                    line (58, 263) - step (100, 75), bluegrey, b
                    sleep 150
                    draw_box (58, 263, 100, 75)
                    shuffle_discs(top_col(), bot_col(), top, bottom)
                case 460 to 558
                    line (58, 459) - step (100, 100), bluegrey, b
                    sleep 150
                    draw_box (58, 459, 100, 100)
                    rotate_discs(top_col(), bot_col(), top, bottom, bottom, -1, 1, 3, 1)                
            end select
        end if    
            
        if x > 642 and x < 742 then
            select case y
                case 49 to 147
                    line (642, 48) - step (100, 100), bluegrey, b
                    sleep 150
                    draw_box (642, 48, 100, 100)
                    rotate_discs(top_col(), bot_col(), top, bottom, top, 1, 0, 3, 1)                                    
                case 264 to 337
                    line (642, 263) - step (100, 75), bluegrey, b
                    sleep 150
                    draw_box (642, 263, 100, 75)                
                    start_config_discs(top_col(), bot_col(), top, bottom)
                case 460 to 558
                    line (642, 459) - step (100, 100), bluegrey, b
                    sleep 150
                    draw_box (642, 459, 100, 100)                
                    rotate_discs(top_col(), bot_col(), top, bottom, bottom, 1, 1, 3, 1)                
            end select
        end if
        
    end if

    while buttons
        getmouse(x, y, , buttons)
    wend 
        
sleep 25

loop 
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Engel's enigma - a simple rotating disc puzzle.

Post by badidea »

Very nice!
3622
Posts: 24
Joined: Mar 14, 2015 23:53

Re: Engel's enigma - a simple rotating disc puzzle.

Post by 3622 »

Thank you!
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Engel's enigma - a simple rotating disc puzzle.

Post by badidea »

With a Rubik's cube 12 different moves are possible at each moment, here only four. So I would think that this puzzle is easy, but I do not know yet how to solve it when scrambled.

I noticed that the buttons do not always respond to a short mouse-click. This is maybe be caused by the double getmouse in the main loop (or the 25 ms delay, or my mouse is just old). You can also save the previous state off the buttons to detect a mouse button press (without re-trigger) event. Like this:

Code: Select all

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

start_config_discs (top_col(), bot_col(), top, bottom)
dim as integer old_buttons
do

    do
        old_buttons = buttons
        result = getmouse (x, y, , buttons)
        if inkey = chr(255) & "k" then
            imagedestroy top
            imagedestroy bottom
            exit do, do
        end if   
        sleep 1 '25
    loop while result <> 0   
   
    if buttons = 1 and old_buttons <> 1 then

        if x > 58 and x < 158 then
            select case y
                case 49 to 147
                    line (58, 48) - step (100, 100), bluegrey, b
                    sleep 150
                    draw_box (58, 48, 100, 100)               
                    rotate_discs(top_col(), bot_col(), top, bottom, top, -1, 0, 3, 1)
                case 264 to 337
                    line (58, 263) - step (100, 75), bluegrey, b
                    sleep 150
                    draw_box (58, 263, 100, 75)
                    shuffle_discs(top_col(), bot_col(), top, bottom)
                case 460 to 558
                    line (58, 459) - step (100, 100), bluegrey, b
                    sleep 150
                    draw_box (58, 459, 100, 100)
                    rotate_discs(top_col(), bot_col(), top, bottom, bottom, -1, 1, 3, 1)               
            end select
        end if   
           
        if x > 642 and x < 742 then
            select case y
                case 49 to 147
                    line (642, 48) - step (100, 100), bluegrey, b
                    sleep 150
                    draw_box (642, 48, 100, 100)
                    rotate_discs(top_col(), bot_col(), top, bottom, top, 1, 0, 3, 1)                                   
                case 264 to 337
                    line (642, 263) - step (100, 75), bluegrey, b
                    sleep 150
                    draw_box (642, 263, 100, 75)               
                    start_config_discs(top_col(), bot_col(), top, bottom)
                case 460 to 558
                    line (642, 459) - step (100, 100), bluegrey, b
                    sleep 150
                    draw_box (642, 459, 100, 100)               
                    rotate_discs(top_col(), bot_col(), top, bottom, bottom, 1, 1, 3, 1)               
            end select
        end if
       
    end if

    'while buttons
    '    getmouse(x, y, , buttons)
    'wend
       
sleep 1 '25

loop
3622
Posts: 24
Joined: Mar 14, 2015 23:53

Re: Engel's enigma - a simple rotating disc puzzle.

Post by 3622 »

Hi Badidea

Thanks for your feedback.

Dewdney says "Engel writes that several people adept at Rubik's cube have not been able to get anywhere with the puzzle"
I totally agree. Considering that it is only shuffled 10 times it appears to be extremely difficult to me.
I have yet to discover ways to interchange pieces without disturbing everything else which is the method I use for the Rubik's cube.

With regard to the buttons issue, I cannot replicate this. My system is an old Core 2 duo.

The second getmouse can be removed. I only included it to wait for the left mouse button to be released.
This is to prevent multiple moves and remembering mouse clicks while shuffling is in process.

Incidently, the first version I made had an orange background because I (erroneously) had it in my head that Engel was Dutch!
Post Reply