Gamemaster
General
Game
Playing
cram
Description
Our game is a 4x4 version of Cram, based on Martin Gardner’s domino-placement game. In standard Cram, players take turns placing a domino on any two orthogonally adjacent empty squares, and the last player able to move wins. Our version keeps these core rules but adapts the game to a smaller 4x4 board so it can be clearly represented and tested in Gamemaster. We also visually track which player placed each domino by colouring occupied squares red or blue, making the game state easier to follow during play.
Rulesheet
role(red) role(blue) row(1) row(2) row(3) row(4) col(1) col(2) col(3) col(4) base(cell(R,C,empty)) :- row(R) & col(C) base(cell(R,C,W)) :- role(W) base(control(red)) base(control(blue)) action(place(R1,C1,R2,C2)) :- adjacent(R1,C1,R2,C2) init(cell(R,C,empty)) :- row(R) & col(C) init(control(red)) adjacent(1,1,1,2) adjacent(1,2,1,3) adjacent(1,3,1,4) adjacent(2,1,2,2) adjacent(2,2,2,3) adjacent(2,3,2,4) adjacent(3,1,3,2) adjacent(3,2,3,3) adjacent(3,3,3,4) adjacent(4,1,4,2) adjacent(4,2,4,3) adjacent(4,3,4,4) adjacent(1,1,2,1) adjacent(2,1,3,1) adjacent(3,1,4,1) adjacent(1,2,2,2) adjacent(2,2,3,2) adjacent(3,2,4,2) adjacent(1,3,2,3) adjacent(2,3,3,3) adjacent(3,3,4,3) adjacent(1,4,2,4) adjacent(2,4,3,4) adjacent(3,4,4,4) legal(place(R1,C1,R2,C2)) :- adjacent(R1,C1,R2,C2) & cell(R1,C1,empty) & cell(R2,C2,empty) place(R1,C1,R2,C2) :: control(red) ==> cell(R1,C1,red) & cell(R2,C2,red) place(R1,C1,R2,C2) :: control(blue) ==> cell(R1,C1,blue) & cell(R2,C2,blue) place(R1,C1,R2,C2) :: ~cell(R1,C1,empty) place(R1,C1,R2,C2) :: ~cell(R2,C2,empty) place(R1,C1,R2,C2) :: control(red) ==> ~control(red) & control(blue) place(R1,C1,R2,C2) :: control(blue) ==> ~control(blue) & control(red) openpair :- adjacent(R1,C1,R2,C2) & cell(R1,C1,empty) & cell(R2,C2,empty) terminal :- ~openpair goal(red,0) :- terminal & control(red) goal(blue,100) :- terminal & control(red) goal(blue,0) :- terminal & control(blue) goal(red,100) :- terminal & control(blue) goal(red,50) :- ~terminal goal(blue,50) :- ~terminal
Stylesheet
function renderstate(state) { var container = document.createElement('div'); container.style.textAlign = 'center'; container.style.fontFamily = 'Arial, sans-serif'; var title = document.createElement('h2'); title.innerHTML = '4x4 Cram'; container.appendChild(title); var turn = document.createElement('div'); turn.style.marginBottom = '12px'; turn.style.fontSize = '18px'; if (compfindp(seq('control','red'), state, seq())) { turn.innerHTML = 'Turn: red'; turn.style.color = 'red'; } else if (compfindp(seq('control','blue'), state, seq())) { turn.innerHTML = 'Turn: blue'; turn.style.color = 'blue'; } else { turn.innerHTML = 'Turn: unknown'; } container.appendChild(turn); var table = document.createElement('table'); table.style.borderCollapse = 'collapse'; table.style.margin = 'auto'; for (var r = 1; r <= 4; r++) { var row = table.insertRow(); for (var c = 1; c <= 4; c++) { var square = row.insertCell(); square.style.width = '70px'; square.style.height = '70px'; square.style.border = '2px solid black'; square.style.textAlign = 'center'; square.style.verticalAlign = 'middle'; square.style.fontSize = '18px'; square.style.fontWeight = 'bold'; if (compfindp(seq('cell', r.toString(), c.toString(), 'red'), state, seq())) { square.style.backgroundColor = 'red'; square.style.color = 'white'; square.innerHTML = 'R'; } else if (compfindp(seq('cell', r.toString(), c.toString(), 'blue'), state, seq())) { square.style.backgroundColor = 'blue'; square.style.color = 'white'; square.innerHTML = 'B'; } else { square.style.backgroundColor = '#f5f5f5'; square.innerHTML = ''; } } } container.appendChild(table); var note = document.createElement('p'); note.style.marginTop = '12px'; note.innerHTML = 'Place a domino on two adjacent empty squares.'; container.appendChild(note); return container; }
Ownership