Client for playing 300 publicly available Sokoban puzzles on a computer or phone.
-- Sprites and colors from Michal Zalewski's https://lcamtuf.coredump.cx/sir-box-a-lot with some very light editing (mostly search and replace)

local convert = function(arr)
  for i=1,3 do arr[i] = arr[i]/255 end
  return arr
end

-- colors for the different sprites
-- SC_AIR is global
local SC_HAIR, SC_SKIN, SC_SUIT1, SC_SUIT2  -- player
local SC_CRT1, SC_CRT2, SC_CRT3  -- crate
local SC_SLV1, SC_SLV2, SC_SLV3  -- crate on target
local SC_TGT1, SC_TGT2, SC_TLTG  -- target
local SC_BRK1, SC_BRK2, SC_BRK3  -- Warehouse walls

if dark_theme then
  SC_AIR = { 0, 0, 0 }

  SC_HAIR = convert{ 250, 250, 100 }    -- Player hair / hat
  SC_SKIN = convert{ 120, 100, 80  }    -- Player skin tone
  SC_SUIT1 = convert{ 40,  80,  100 }    -- Player suit left
  SC_SUIT2 = convert{ 40,  60,  80  }    -- Player suit right

  SC_CRT1 = convert{ 60,  30,  30  }    -- Normal crate, outer color
  SC_CRT2 = convert{ 100, 60,  60  }    -- Normal crate, x pattern
  SC_CRT3 = convert{ 40,  0,   40  }    -- Normal crate, inner color

  SC_SLV1 = convert{ 20,  40,  60  }    -- Solved crate, as above
  SC_SLV2 = convert{ 40,  80,  100 }
  SC_SLV3 = convert{ 0,   30,  30  }

  SC_TGT1 = convert{ 0,   20,  20  }    -- Target marker outer glow
  SC_TGT2 = convert{ 0,   50,  100 }    -- Target marker dot

  SC_PLTG = convert{ 0,   50,  255 }    -- Player's suit over target

  SC_BRK1 = convert{ 30,  30,  40  }    -- Warehouse walls
  SC_BRK2 = convert{ 20,  20,  30  }
  SC_BRK3 = convert{ 40,  40,  50  }
else
  SC_AIR = { 0.8, 0.8, 0.8 }

  SC_HAIR = convert{ 250, 200, 100 }    -- Player hair / hat
  SC_SKIN = convert{ 160, 120, 80  }    -- Player skin tone
  SC_SUIT1 = convert{ 40,  80,  100 }    -- Player suit left
  SC_SUIT2 = convert{ 40,  60,  80  }    -- Player suit right

  SC_CRT1 = convert{ 160,  130,  130  }    -- Normal crate, outer color
  SC_CRT2 = convert{ 200, 160,  160  }    -- Normal crate, x pattern
  SC_CRT3 = convert{ 140,  100,   140  }    -- Normal crate, inner color

  SC_SLV1 = convert{ 120,  140,  160  }    -- Solved crate, as above
  SC_SLV2 = convert{ 140,  180,  200 }
  SC_SLV3 = convert{ 100,  130,  130  }

  SC_TGT1 = convert{ 0,   120,  120  }    -- Target marker outer glow
  SC_TGT2 = convert{ 0,   150,  200 }    -- Target marker dot

  SC_PLTG = convert{ 0,   50,  200 }    -- Player's suit over target

  SC_BRK1 = convert{ 130,  130,  140  }    -- Warehouse walls
  SC_BRK2 = convert{ 120,  120,  130  }
  SC_BRK3 = convert{ 140,  140,  150  }
end

local SC_GRS1 = convert{ 0,   40,  90  }    -- Grass / water outside
local SC_GRS2 = convert{ 0,   20,  90  }

sprites = {

  -- 0: Player character

  {
    { SC_AIR,   SC_AIR,   SC_HAIR,  SC_HAIR,  SC_AIR,   SC_AIR   },
    { SC_AIR,   SC_AIR,   SC_SKIN,  SC_SKIN,  SC_AIR,   SC_AIR   },
    { SC_SKIN,  SC_SUIT1, SC_SUIT1, SC_SUIT2, SC_SUIT2, SC_SKIN  },
    { SC_AIR,   SC_AIR,   SC_SUIT1, SC_SUIT2, SC_AIR,   SC_AIR   },
    { SC_AIR,   SC_AIR,   SC_SUIT1, SC_SUIT2, SC_AIR,   SC_AIR   },
    { SC_AIR,   SC_SKIN,  SC_AIR,   SC_AIR,   SC_SKIN,  SC_AIR   },
  },

  -- 1: Player over target

  {
    { SC_AIR,   SC_AIR,   SC_HAIR,  SC_HAIR,  SC_AIR,   SC_AIR   },
    { SC_AIR,   SC_AIR,   SC_SKIN,  SC_SKIN,  SC_AIR,   SC_AIR   },
    { SC_SKIN,  SC_SUIT1, SC_PLTG,  SC_PLTG,  SC_SUIT2, SC_SKIN  },
    { SC_AIR,   SC_AIR,   SC_PLTG,  SC_PLTG,  SC_AIR,   SC_AIR   },
    { SC_AIR,   SC_AIR,   SC_PLTG,  SC_PLTG,  SC_AIR,   SC_AIR   },
    { SC_AIR,   SC_SKIN,  SC_AIR,   SC_AIR,   SC_SKIN,  SC_AIR   },
  },

  -- 2: Crate

  {
    { SC_CRT1,  SC_CRT1,  SC_CRT1,  SC_CRT1,  SC_CRT1,  SC_CRT1  },
    { SC_CRT1,  SC_CRT2,  SC_CRT3,  SC_CRT3,  SC_CRT2,  SC_CRT1  },
    { SC_CRT1,  SC_CRT3,  SC_CRT2,  SC_CRT2,  SC_CRT3,  SC_CRT1  },
    { SC_CRT1,  SC_CRT3,  SC_CRT2,  SC_CRT2,  SC_CRT3,  SC_CRT1  },
    { SC_CRT1,  SC_CRT2,  SC_CRT3,  SC_CRT3,  SC_CRT2,  SC_CRT1  },
    { SC_CRT1,  SC_CRT1,  SC_CRT1,  SC_CRT1,  SC_CRT1,  SC_CRT1  },
  },

  -- 3: Crate at target position

  {
    { SC_SLV1,  SC_SLV1,  SC_SLV1,  SC_SLV1,  SC_SLV1,  SC_SLV1  },
    { SC_SLV1,  SC_SLV2,  SC_SLV3,  SC_SLV3,  SC_SLV2,  SC_SLV1  },
    { SC_SLV1,  SC_SLV3,  SC_SLV2,  SC_SLV2,  SC_SLV3,  SC_SLV1  },
    { SC_SLV1,  SC_SLV3,  SC_SLV2,  SC_SLV2,  SC_SLV3,  SC_SLV1  },
    { SC_SLV1,  SC_SLV2,  SC_SLV3,  SC_SLV3,  SC_SLV2,  SC_SLV1  },
    { SC_SLV1,  SC_SLV1,  SC_SLV1,  SC_SLV1,  SC_SLV1,  SC_SLV1  },
  },

  -- 4: Crate target mark

  {
    { SC_TGT1,  SC_TGT1,  SC_TGT1,  SC_TGT1,  SC_TGT1,  SC_TGT1  },
    { SC_TGT1,  SC_AIR,   SC_AIR,   SC_AIR,   SC_AIR,   SC_TGT1  },
    { SC_TGT1,  SC_AIR,   SC_TGT2,  SC_TGT2,  SC_AIR,   SC_TGT1  },
    { SC_TGT1,  SC_AIR,   SC_TGT2,  SC_TGT2,  SC_AIR,   SC_TGT1  },
    { SC_TGT1,  SC_AIR,   SC_AIR,   SC_AIR,   SC_AIR,   SC_TGT1  },
    { SC_TGT1,  SC_TGT1,  SC_TGT1,  SC_TGT1,  SC_TGT1,  SC_TGT1  },
  },

  -- 5: Wall

  {
    { SC_BRK1,  SC_BRK2,  SC_BRK1,  SC_BRK3,  SC_BRK2,  SC_BRK3  },
    { SC_BRK1,  SC_BRK1,  SC_BRK2,  SC_BRK2,  SC_BRK3,  SC_BRK1  },
    { SC_BRK3,  SC_BRK2,  SC_BRK3,  SC_BRK1,  SC_BRK2,  SC_BRK1  },
    { SC_BRK1,  SC_BRK1,  SC_BRK2,  SC_BRK3,  SC_BRK3,  SC_BRK1  },
    { SC_BRK3,  SC_BRK3,  SC_BRK1,  SC_BRK3,  SC_BRK3,  SC_BRK2  },
    { SC_BRK2,  SC_BRK1,  SC_BRK1,  SC_BRK1,  SC_BRK2,  SC_BRK3  },
  },

  -- 6: Grass

  {
    { SC_GRS1,  SC_GRS1,  SC_GRS1,  SC_GRS2,  SC_GRS2,  SC_GRS2  },
    { SC_GRS2,  SC_GRS2,  SC_GRS2,  SC_GRS1,  SC_GRS1,  SC_GRS1  },
    { SC_GRS1,  SC_GRS1,  SC_GRS1,  SC_GRS2,  SC_GRS2,  SC_GRS2  },
    { SC_GRS2,  SC_GRS2,  SC_GRS2,  SC_GRS1,  SC_GRS1,  SC_GRS1  },
    { SC_GRS1,  SC_GRS1,  SC_GRS1,  SC_GRS2,  SC_GRS2,  SC_GRS2  },
    { SC_GRS2,  SC_GRS2,  SC_GRS2,  SC_GRS1,  SC_GRS1,  SC_GRS1  },
  },

};