Skip to content

Commit

Permalink
Add sudoku game
Browse files Browse the repository at this point in the history
  • Loading branch information
gfwilliams committed Oct 29, 2024
1 parent 69e344f commit 9805bb1
Show file tree
Hide file tree
Showing 10 changed files with 806 additions and 0 deletions.
1 change: 1 addition & 0 deletions apps/sudoku/ChangeLog
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.01: New App!
1 change: 1 addition & 0 deletions apps/sudoku/app-icon.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

163 changes: 163 additions & 0 deletions apps/sudoku/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
var settings = require("Storage").readJSON("sudoku.json",1)||{};

const Layout = require("Layout");
var puzzle = ""; // start puzzle space for blanks, 81 char str
var solution = ""; // the solution for the puzzle 81 char str
var current = ""; // current puzzle state, 81 char str
var sx=4, sy=4; // selected item
var dx=0, dy=0, dmoved=false; // current drag amount
const DRAG = 20;
const CHOOSERFONT = "12x20:2";
const COL_GOOD = "#00F";
const COL_BAD = "#F00";

function saveSettings() {
settings.puzzle = puzzle;
settings.solution = solution;
settings.current = current;
require("Storage").writeJSON("sudoku.json",settings);
}

function startGame(difficulty) {
let file = require("Storage").read("sudoku.easy.txt");
let games = 0|(file.length/163);
let game = Math.floor(Math.random()*games);
let line = file.substr(game*163, 162);
puzzle = line.substr(0,81).replaceAll("-"," ");
current = ""+puzzle; // new string
solution = line.substr(81,81);
showGrid();
}

function draw() {
g.clear(1);
for (var i=0;i<10;i++) {
g.setColor((i%3)?"#888":g.theme.fg);
g.fillRect(7+18*i, 7, 7+18*i, 169);
g.fillRect(7, 7+18*i, 169, 7+18*i);
}
i = 0;
g.setFont("6x8:2").setFontAlign(0,0);
for (var y=0;y<9;y++)
for (var x=0;x<9;x++)
g.setColor(puzzle[i]==" "?((solution[i]==current[i])?COL_GOOD:COL_BAD):g.theme.fg).drawString(current[i++], 16 + 18*x, 16 + 18*y);
}
function drawSq(x,y,sel) {
g.setColor(sel ? g.theme.bgH : g.theme.bg).fillRect(8+x*18,8+y*18,24+x*18,24+y*18);
g.setFont("6x8:2").setFontAlign(0,0).setColor(sel ? g.theme.fgH : g.theme.fg);
var i = x+y*9;
g.setColor(puzzle[i]==" "?((solution[i]==current[i])?COL_GOOD:COL_BAD):g.theme.fg).drawString(current[i++], 16 + 18*x, 16 + 18*y);
}

// precalculate our layout
var choose = function(num) {
if (num!==undefined) {
Bangle.buzz(100);
var i = sx+sy*9;
current = current.substr(0,i)+num+current.substr(i+1);
}
showGrid();
if (current == solution) {
saveSettings();
E.showMessage(/*LANG*/"Well done,\nyou finished!", {
title:"Sudoku",
buttons : {"Ok":true},
img : require("heatshrink").decompress(atob("k8pwcBkmSpICCnVp0IIFAQl27dt2wOJ9On7/582YtOJBws7tv/DoQKCBwubvvmzVp0wCCHAvf9u2DpE8uOn7waEjQdDq1Itv+DQQCB0gZBkMkyPHj1tHAuGAQOJktt/Ubvo4DAQI3ChMcuPHzd5HAeasICBtFOr/kw3fDQe27RhCofH/lx4xxFSQIFBiu/rNhHAp0DyHx447BHAh0Ekt/61YlodFOgaPBDoJWFAQeJrf1yySBDohWCoVJOgUcKw+YyVOrtly0LKw4eBp4dCjytHBwNOrNlyUbDoVpHAYDBo4dH02EFoTpBDoQ7B2MyZALMCHYsGtOOjALDAQQ7CyM6tFkFIgCDDoPBnkT4wLFAQegxP8z/JBxNwp8E+ALHAQMl+V/n4aIAQI4B4McBxU/z/P8gOKjnx4JHJAQP//5WKSoVwDRICBv//FJTRDBxeT/5WLkmR45WLkitLARNIA"))
}).then(showMenu);
}
};
var numberChooser = new Layout( {
type:"v", c: [
{type:"h", c: [
{type:"btn", font:CHOOSERFONT, label:"1", fillx:1, cb:()=>choose(1) },
{type:"btn", font:CHOOSERFONT, label:"2", fillx:1, cb:()=>choose(2) },
{type:"btn", font:CHOOSERFONT, label:"3", fillx:1, cb:()=>choose(3) }
]},
{type:"h", c: [
{type:"btn", font:CHOOSERFONT, label:"4", fillx:1, cb:()=>choose(4) },
{type:"btn", font:CHOOSERFONT, label:"5", fillx:1, cb:()=>choose(5) },
{type:"btn", font:CHOOSERFONT, label:"6", fillx:1, cb:()=>choose(6) }
]},
{type:"h", c: [
{type:"btn", font:CHOOSERFONT, label:"7", fillx:1, cb:()=>choose(7) },
{type:"btn", font:CHOOSERFONT, label:"8", fillx:1, cb:()=>choose(8) },
{type:"btn", font:CHOOSERFONT, label:"9", fillx:1, cb:()=>choose(9) }
]}
], fillx:1
}, {btns:[ {label:/*LANG*/"Back", cb: l=>choose()} ]});

function showGrid() {
Bangle.setUI({mode:"custom", drag:e=>{
if (e.b) {
dx += e.dx;
dy += e.dy;
while (Math.abs(dx) >= DRAG) {
Bangle.buzz(40);
let old = sx;
sx = (sx+9+Math.sign(dx))%9;
dx -= Math.sign(dx)*DRAG;
drawSq(old,sy,0);
drawSq(sx,sy,1);
dmoved = true;
}
while (Math.abs(dy) >= DRAG) {
Bangle.buzz(40);
let old = sy;
sy = (sy+9+Math.sign(dy))%9;
dy -= Math.sign(dy)*DRAG;
drawSq(sx,old,0);
drawSq(sx,sy,1);
dmoved = true;
}
} else {
if (!dmoved && puzzle[sx+sy*9]==" ") {
Bangle.buzz(100);
setTimeout(showSelectNumber, 10);
}
dx = dy = 0;
dmoved = false;
}
}, btn:() => {
saveSettings();
showMenu();
}});
draw();
drawSq(sx,sy,1);
}

function showSelectNumber() {
g.clear();
numberChooser.setUI();
numberChooser.render();
}

function showMenu() {
var menu = { "" : { title: "Sudoku" } };
if (settings.puzzle)
menu["Resume Game"] = () => {
puzzle = settings.puzzle;
solution = settings.solution;
current = settings.current;
showGrid();
};
menu["New Game"] = () => {
E.showMenu({ "" : { title: /*LANG*/"Difficulty", back : showMenu },
"Easy" : () => startGame("easy"),
"Medium" : () => startGame("medium"),
"Hard" : () => startGame("hard")
});
};
menu["Exit"] = () => load();
E.showMenu(menu);
}

if (settings.puzzle) {
puzzle = settings.puzzle;
solution = settings.solution;
current = settings.current;
showGrid();
} else {
showMenu();
}

E.on("kill", saveSettings); // ensure we save the game
Binary file added apps/sudoku/app.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions apps/sudoku/gen_sudoku.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
Call this to generate the data files needed.
npm install sudoku-gen
*/

var getSudoku = require('sudoku-gen').getSudoku;

// (easy, medium, hard, expert)
function gen(difficulty) {
console.log("Generate", difficulty);
// Get a sudoku of specific difficulty
let result = "";
for (let i=0;i<200;i++) {
const sudoku = getSudoku('easy');
result += sudoku.puzzle + sudoku.solution+"\n";
}
require("fs").writeFileSync("sudoku."+difficulty+".txt", result);
}

gen("easy");
gen("medium");
gen("hard");
17 changes: 17 additions & 0 deletions apps/sudoku/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{ "id": "sudoku",
"name": "Sudoku",
"shortName":"Sudoku",
"version":"0.01",
"description": "A Sudoku game that allows you to play one of 600 pre-made puzzles",
"icon": "app.png",
"screenshots" : [ { "url":"screenshot.png" } ],
"tags": "game",
"supports" : ["BANGLEJS2"],
"storage": [
{"name":"sudoku.app.js","url":"app.js"},
{"name":"sudoku.img","url":"app-icon.js","evaluate":true},
{"name":"sudoku.easy.txt","url":"sudoku.easy.txt"},
{"name":"sudoku.medium.txt","url":"sudoku.medium.txt"},
{"name":"sudoku.hard.txt","url":"sudoku.hard.txt"}
]
}
Binary file added apps/sudoku/screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 9805bb1

Please sign in to comment.