Skip to content

Match sets

Inspired a game I saw once, which in turn is inspired by the board game SET!.

Match sets of three cards, where each set has either all cards or no cards matching in every single attribute: color, shape, or number.

Press H to highlight possible matches. Drag to make a match out of adjacent or diagonally-adjacent tiles.

There is no scoring system yet.

A board of square cards, each of them having one to three shapes that are either circles, square, or triangles, and come in either blue, red, or green. A few of them have been highlighted

var draw, keyPressed;
function setup() {
  createCanvas(400, 400);
  let colors = [
    color(255, 0, 0),
    color(0, 255, 0),
    color(0, 0, 255),
  ]
  let shapes = [
    (x,y) => rect(x - 5, y - 5, 10, 10),
    (x,y) => circle(x, y, 10),
    (x,y) => triangle(x, y - 5, x - 5, y + 5, x + 5, y + 5),
    // (x,y) => quad(x, y - 5, x - 5, y, x, y + 5, x + 5, y),
  ]
  let arrangements = [
    [[0, 0]],
    [[-10, 0], [10, 0]],
    [[0, -7], [-10, 7], [10, 7]],
    // [[10, 0], [-10, 0], [0, 10], [0, -10]],
  ]
  let tiles = Array(8 * 9).fill().map(newTile)
  function newTile() {
    return {
      fall: 0,
      sel: false,
      t: [
        floor(random(colors.length)),
        floor(random(shapes.length)),
        floor(random(arrangements.length)),
      ]
    }
  }
  tiles[32] = {fall: 0, sel: false, h: true, t: [0, 0, 0]}
  tiles[32+9] = {fall: 0, sel: false, h: true, t: [1, 1, 1]}
  tiles[32+18] = {fall: 0, sel: false, h: true, t: [2, 2, 2]}
  tiles[12] = {fall: 0, sel: false, h: true, t: [1, 1, 2]}
  tiles[13] = {fall: 0, sel: false, h: true, t: [1, 1, 2]}
  tiles[14] = {fall: 0, sel: false, h: true, t: [1, 1, 2]}
  function drawTile(x, y, {fall, sel, h, t: [c, s, a]}) {
    if (h) {
      stroke(255, 0, 0)
      noFill()
      rect(x - 4, y + fall - 4, 40 + 4 * 2)
    }
    if (sel) {
      fill(250, 250, 50)
      stroke(100, 100, 0)
    } else {
      fill(255)
      stroke(0)
    }
    rect(x, y + fall, 40)
    fill(colors[c])
    stroke(0)
    for (let [dx, dy] of arrangements[a]) {
      let fn = shapes[s]
      fn(x + 40 / 2 + dx, y + 40 / 2 + dy + fall)
    }
  }
  let selectedC = 0
  
  let selectedTraits = {}
  
  draw = function() {
    background(220);
    for (let i = 0; i < tiles.length; i ++) {
      if (tiles[i]) {
        let x = floor(i / 9) * (40 + 80/7)
        let y = (i % 9 - 1) * (40 + 80/7)
        drawTile(x, y, tiles[i])
        if (mouseIsPressed && !tiles[i].sel && mouseX > x && mouseX < x + 40 && mouseY > y && mouseY < y + 40 && selectedC < 3) {
          let neighbor = (selectedC == 0)
          for (let j of [-1, 1, -9, 9, -10, 10, -8, 8]) {
            if ((i + j) % 9 == 0 || !tiles[i + j]) continue;
            if (tiles[i + j].sel) {
              neighbor = true
              break
            }
          }
          if (neighbor) {
            tiles[i].sel = true
            selectedC += tiles[i].sel ? 1 : -1
            for (let ti = 0; ti < tiles[i].t.length; ti ++) {
              selectedTraits[[ti, tiles[i].t[ti]]] |= 0
              selectedTraits[[ti, tiles[i].t[ti]]] += tiles[i].sel ? 1 : -1
            }
          }
        }
        if ((!tiles[i + 1] || tiles[i + 1].fall != 0) && (i + 1) % 9 != 0) {
          tiles[i].fall += 5
          if (tiles[i].fall >= 50) {
            tiles[i].fall = 0
            tiles[i + 1] = tiles[i]
            tiles[i] = undefined
          }
        }
      } else if (i % 9 == 0) {
        tiles[i] = newTile()
      }
    }
      
    if (!mouseIsPressed) {
      let matching = selectedC == 3 && Object.values(selectedTraits).every(v => v == 0 || v == 1 || v == 3)
      
      for (let i = 0; i < tiles.length; i ++) {
        if (tiles[i] && tiles[i].sel) {
          if (matching) {
            tiles[i] = undefined
          } else {
            tiles[i].sel = false
          }
        }
      }
      selectedC = 0
      selectedTraits = {}
    }
  }
  
  keyPressed = function() {
    if (key != 'h') return
    for (let i = 0; i < tiles.length; i ++) {
      if (!tiles[i]) continue
      let found = {}
      let wanted = []
      tiles[i].h = false
      let ot = tiles[i].t
      for (let j of [-1, 1, -9, 9, -10, 10, -8, 8]) {
        if ((i + j) % 9 == 0 || !tiles[i + j]) continue;
        let t = tiles[i + j].t
        let k = 0
        k = k * colors.length + t[0]
        k = k * shapes.length + t[1]
        k = k * arrangements.length + t[2]
        let wk = 0
        wk = wk * colors.length + (2*t[0] - ot[0] + colors.length) % colors.length
        wk = wk * shapes.length + (2*t[1] - ot[1] + shapes.length) % shapes.length
        wk = wk * arrangements.length + (2*t[2] - ot[2] + arrangements.length) % arrangements.length
        found[k] |= 0
        found[k] += wk == k ? 1 : 2
        wanted.push(wk)
      }
      for (let w of wanted) {
        if (found[w] >= 2) {
          tiles[i].h = w
        }
      }
    }
  }
}

(Originally seen at https://editor.p5js.org/bojidar-bg/sketches/sijEyG8Ag)

Experiments tagged p5 (58/85)

Experiments tagged game (6/11)

Experiments tagged wip (3/5)

Experiments on this site (58/85)