Beermat Puzzle Teaser

So Here It Is - THE SOLUTION

Yes, finally - if you haven't already seen it on the forum - the solution.

My Own Codea (Lua) Listings Detailed and Condensed

Below are a couple of listings of my own Codea project which resolved this puzzle: the first is annotated and has not been minimised to display the logic more readily together and displaying progress with key variables whilst running the code - it also displays the beermat images making resoltion of the problem slower. The second is condensed - removing annotation, progress monitoring and unnecessary displays. The data that is used in both listings is provided after them in a number of tables.

Links to two further pages Sharp MZ80K and Commodore PET show puzzle solutions in different computer Basic dialects and from just less than 40 years ago.


Codea Lua
                        
function setup()
-- set up variables for analysis
    s = require("socket")
    pA,pB,pC,pD = 0,0,0,0
    mirrors = {"00","00","00","00","00","00","00","00"}
    lev1,lev2,lev3,lev4 = 0,0,0,0
    find = false
    font("Baskerville-Bold")
    fontSize(32)
    count = 0
    hits = 0
    solutions = {}
    start = os.time()
    timer = 0
    solTimer = {}
    -- call the analysis engine
    st = s:gettime()
    engine()
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color
    background(40, 40, 50)
    sprite(disc[dAS],200,812,360,360)
    sprite(disc[dBS],576,812,360,360)
    sprite(disc[dCS],576,440,360,360)
    sprite(disc[dDS],200,440,360,360)
    text(count,384,280)
    text(timer,384,240)
    if find == true then
        fill(250, 255, 0, 255)
        text("WE HAVE "..hits.. " SOLUTIONS !!! ",384,200)
        for sol = 1,#solutions do
            text(solutions[sol],384,150)
            text(solTimer[sol].." secs",680,150)
        end
    else
        fill(244, 33, 59, 255)
        text("SORRY NO SOLUTION!!! ",364,200)
    end
end

function engine()
    -- main engine for testing each construction
    limit = 16
    for sh = 1,6 do
        -- six possible orientations of 4 mats with one fixed
        shuffle(sh)
        for sA = 1,limit do
            disc1(pA,sA)
            for sB = 1,limit do
                disc2(pB,sB)
                for sC = 1,limit do
                    disc3(pC,sC)
                    for sD = 1,limit do
                        disc4(pD,sD)
                        checkIt()
                        count = count+1
                    end
                end
            end
        end
        print(level)
    end
    en = s:gettime()
    print(en-st)
    finish = os.time()
    timer = os.difftime(finish,start)
end

function shuffle(n)
    -- reads the configuration of the mats from table
    pos = (n-1)*4+1
    pA = routePlan[pos]
    pB = routePlan[pos+1]
    pC = routePlan[pos+2]
    pD = routePlan[pos+3]
    -- printing out to confirm each configuration has been tested in order
    orientation = "Orientation: "..pA..pB..pC..pD
    print(orientation)
end

function switch(str)
    -- flip the two characters of string prior to comparison
    local temp = string.reverse(str)
    return temp
end

function disc1(mat,edge)
    -- specifies the face and edge of the first mat position
    if edge <= 8 then dA = 1 fA ="F" else dA = 2 fA = "B" edge = edge-8 end
    dAS = (mat-1)*2+dA
    mirStr = double[dAS]
    mirrors[1] = string.sub(mirStr,(edge-1)*2+5,(edge-1)*2+6)
    mirrors[2] = string.sub(mirStr,(edge-1)*2+9,(edge-1)*2+10)
end

function disc2(mat,edge)
    -- specifies the face and edge of the second mat position
    if edge <= 8 then dB = 1 fB ="F" else dB = 2 fB = "B" edge = edge-8 end
    dBS = (mat-1)*2+dB
    mirStr = double[dBS]
    mirrors[3] = string.sub(mirStr,(edge-1)*2+9,(edge-1)*2+10)
    mirrors[4] = string.sub(mirStr,(edge-1)*2+13,(edge-1)*2+14)
end

function disc3(mat,edge)
    -- specifies the face and edge of the third mat position
    if edge <= 8 then dC = 1 fC ="F" else dC = 2 fC = "B" edge = edge-8 end
    dCS = (mat-1)*2+dC
    mirStr = double[dCS]
    mirrors[5] = string.sub(mirStr,(edge-1)*2+13,(edge-1)*2+14)
    mirrors[6] = string.sub(mirStr,(edge-1)*2+1,(edge-1)*2+2)
end

function disc4(mat,edge)
    -- specifies the face and edge of the fourth mat position
    if edge <= 8 then dD = 1 fD ="F" else dD = 2 fD = "B" edge = edge-8 end
    dDS = (mat-1)*2+dD
    mirStr = double[dDS]
    mirrors[7] = string.sub(mirStr,(edge-1)*2+1,(edge-1)*2+2)
    mirrors[8] = string.sub(mirStr,(edge-1)*2+5,(edge-1)*2+6)
end

function checkIt()
    -- works out the number of matches at each level/interface
    level = "Lev"
    if mirrors[1] == switch(mirrors[4]) then lev1 = lev1+1 end
    if mirrors[3] == switch(mirrors[6]) then lev2 = lev2+1 end
    if mirrors[5] == switch(mirrors[8]) then lev3 = lev3+1 end
    if mirrors[7] == switch(mirrors[2]) then lev4 = lev4+1 end
    -- combines matches at each level in a string
    level = level.."-"..lev1.."-"..lev2.."-"..lev3.."-"..lev4
    -- the real check for four matches in each configuration
    if mirrors[1] == switch(mirrors[4]) and mirrors[3] == switch(mirrors[6]) and mirrors[5] == switch(mirrors[8]) and mirrors[7] == switch(mirrors[2]) then
    -- record condition and hits build configuration string and store in table
    find = true
    hits = hits+1
    solution = mirrors[1].."("..pA..fA..")-"..mirrors[3].."("..pB..fB..")-"..mirrors[5].."("..pC..fC..")-"..mirrors[7].."("..pD..fD..")"
    now = os.time()
    timer = os.difftime(now,start)
    table.insert(solutions,hits,solution)
    table.insert(solTimer,hits,timer)
    end
end
                        
                    

A Condensed version

This listing has all remarks and minimised to necessary code

Codea Lua Minimised
                            
function setup()
    s = require("socket")
    pA,pB,pC,pD,lev1,lev2,lev3,lev4 = 0,0,0,0,0,0,0,0
    mirrors = {"00","00","00","00","00","00","00","00"}
    find = false
    font("Baskerville-Bold")
    fontSize(32)
    count, hits = 0,0
    solutions = {}
    solTimer = {}
    st = s:gettime()
    engine()
end

function draw()
    background(40, 40, 50)
    text(count,384,280)
    if find == true then
        fill(250, 255, 0, 255)
        text("WE HAVE "..hits.. " SOLUTIONS !!! ",384,232)
        for sol = 1,#solutions do
            text(solutions[sol],384,200)
            text(solTimer[sol].." secs",384,150)
        end
    else
        fill(244, 33, 59, 255)
        text("SORRY NO SOLUTION!!! ",364,200)
    end
end

function engine()
    limit = 16
    for sh = 1,6 do
        shuffle(sh)
        for sA = 1,limit do
            if sA <= 8 then dA = 1 fA ="F" else dA = 2 fA = "B" sA = sA-8 end
            dAS = (pA-1)*2+dA
            mirStr = double[dAS]
            mirrors[1] = string.sub(mirStr,(sA-1)*2+5,(sA-1)*2+6)
            mirrors[2] = string.sub(mirStr,(sA-1)*2+9,(sA-1)*2+10)
            for sB = 1,limit do
                if sB <= 8 then dB = 1 fB ="F" else dB = 2 fB = "B" sB = sB-8 end
                dBS = (pB-1)*2+dB
                mirStr = double[dBS]
                mirrors[3] = string.sub(mirStr,(sB-1)*2+9,(sB-1)*2+10)
                mirrors[4] = string.sub(mirStr,(sB-1)*2+13,(sB-1)*2+14)
                for sC = 1,limit do
                    if sC <= 8 then dC = 1 fC ="F" else dC = 2 fC = "B" sC = sC-8 end
                    dCS = (pC-1)*2+dC
                    mirStr = double[dCS]
                    mirrors[5] = string.sub(mirStr,(sC-1)*2+13,(sC-1)*2+14)
                    mirrors[6] = string.sub(mirStr,(sC-1)*2+1,(sC-1)*2+2)
                    for sD = 1,limit do
                        if sD <= 8 then dD = 1 fD ="F" else dD = 2 fD = "B" sD = sD-8 end
                        dDS = (pD-1)*2+dD
                        mirStr = double[dDS]
                        mirrors[7] = string.sub(mirStr,(sD-1)*2+1,(sD-1)*2+2)
                        mirrors[8] = string.sub(mirStr,(sD-1)*2+5,(sD-1)*2+6)
                        checkIt()
                        count = count+1
                    end
                end
            end
        end
    end
    en = s:gettime()
    print("Completion : "..en-st)
end

function shuffle(n)
    pos = (n-1)*4+1
    pA = routePlan[pos]
    pB = routePlan[pos+1]
    pC = routePlan[pos+2]
    pD = routePlan[pos+3]
    orientation = "Orientation: "..pA..pB..pC..pD
 --   print(orientation)
end

function switch(str)
    local temp = string.reverse(str)
    return temp
end

function checkIt()
    level = "Lev"
    if mirrors[1] == switch(mirrors[4]) then lev1 = lev1+1 end
    if mirrors[3] == switch(mirrors[6]) then lev2 = lev2+1 end
    if mirrors[5] == switch(mirrors[8]) then lev3 = lev3+1 end
    if mirrors[7] == switch(mirrors[2]) then lev4 = lev4+1 end
    level = level.."-"..lev1.."-"..lev2.."-"..lev3.."-"..lev4
    if mirrors[1] == switch(mirrors[4]) and mirrors[3] == switch(mirrors[6]) and mirrors[5] == switch(mirrors[8]) and mirrors[7] == switch(mirrors[2]) then
    find = true
    hits = hits+1
    solution = mirrors[1].."("..pA..fA..")-"..mirrors[3].."("..pB..fB..")-"..mirrors[5].."("..pC..fC..")-"..mirrors[7].."("..pD..fD..")"
    now = s:gettime()
    table.insert(solutions,hits,solution)
    table.insert(solTimer,hits,now-st)
    end
end
                            
                          

The Common Data Tables used

Codea Lua data
                                
double = {
    "PTTFFPRBBPLBLRRBPTTFFPRBBPLBLRRB",
    "RPBLPHFPTLHPTRLRRPBLPHFPTLHPTRLR",
    "BRFBRFRPBTRTLTTFBRFBRFRPBTRTLTTF",
    "TFTPPBPFFLRFLBPRTFTPPBPFFLRFLBPR",
    "RLFBHRPBFRTRPTBTRLFBHRPBFRTRPTBT",
    "TLTBFLBPBLHRBFHPTLTBFLBPBLHRBFHP",
    "PRPHTBTPBRRHLFFTPRPHTBTPBRRHLFFT",
    "LTFRRTFTRLBFRHLFLTFRRTFTRLBFRHLF"
    }

routePlan = {1,2,3,4,1,2,4,3,1,3,2,4,1,3,4,2,1,4,2,3,1,4,3,2}

disc = {"BeerMatPuz:BM3001F",
    "BeerMatPuz:BM3001B",
    "BeerMatPuz:BM3002F",
    "BeerMatPuz:BM3002B",
    "BeerMatPuz:BM3003F",
    "BeerMatPuz:BM3003B",
    "BeerMatPuz:BM3004F",
    "BeerMatPuz:BM3004B"
}