As seen in Dr Zye's excellent video: youtube.com/watch?v=…mj-6zm-z&index=3
Rules of the lock pattern:
- Can't use a dot more than once
- Use at least 4 dots
- Order matters
- No skipping
Definition of "most complicated":
- Use all 9 dots
- Use all 8 slopes
I guess I'm missing a few patterns because I found 274 but he's quoting 296 possible ones.
Log in to post a comment.
// LL 2021 const display = 0; // min=0 max=274 step=1 Canvas.setpenopacity(-1); const turtle = new Turtle(); function walk(i) { if (i==0) { for (var j=1; j<=9; j++) { drawDot(j); } slow = !display; target = display ? (display-1) : (Math.random() * 120 | 0); return true; } if (i==1) { getSolutions(); if (target >= solutions.length) return false; console.log(`target: ${target+1} - solution: ${solutions[target]} - count: ${solutions.length}`); return true; } if (solutions[target].length < 2) return false; drawLine(solutions[target][0], solutions[target][1]); solutions[target].shift(); sleep(100); return true; } const dslopes = [ [1, 0], [0, 1], [1, -1], [1, 1], [-1, 2], [1, 2], [-2, 1], [2, 1] ]; function getSolutions() { solutions = []; const solver = new Solver(); var attempts = 0; while (++attempts < 100000) { const pattern = solver.iterate(); if (isGood(pattern)) { solutions.push(pattern); } if (solver.current_dot > 8) break; } solutions.sort(function(a, b) { for (var i = 0, c = Math.min(a.length, b.length); i < c; i++) { if (a[i] != b[i]) return a[i] - b[i]; } return a.length - b.length; }); } class Solver { constructor(start_dot = 1, start_slopes = [], depth = 0) { this.current_dot = start_dot; this.start_slope_count = start_slopes.length; this.used_slopes = [...start_slopes]; this.available_slopes = []; this.depth = depth; for (var j = 1; j <= 8; j++) { var included = false; for (var k=0; k<this.used_slopes.length && !included; k++) { included |= j == this.used_slopes[k]; included |= -j == this.used_slopes[k]; } if (!included) { this.available_slopes.push(j); } } this.findOptions(); this.child_solver = undefined; } findOptions() { this.options = []; this.available_slopes.forEach(slope => { for (var flip = -1; flip <= 1; flip += 2) { this.used_slopes.push(slope * flip); const new_pattern = getPattern(this.current_dot, this.used_slopes); if (new_pattern.length > 0) this.options.push(slope * flip); this.used_slopes.pop(); } }); } iterate() { if (this.used_slopes.length == 8) { const slopes = this.used_slopes; this.used_slopes = []; return getPattern(this.current_dot, slopes); } if (this.child_solver !== undefined) { const pattern = this.child_solver.iterate(); if (this.child_solver.child_solver === undefined && this.child_solver.options.length < 1) { this.child_solver = undefined; } return pattern; } if (this.current_dot > 9) return []; if (this.options.length < 1) { if (this.depth == 0) { this.current_dot++; this.findOptions(); } return []; } const option = this.options.shift(); const new_slopes = (this.used_slopes.length > 0) ? [...this.used_slopes, option] : [ option ]; this.child_solver = new Solver(this.current_dot, new_slopes, this.depth + 1); return this.child_solver.iterate(); } } function getPattern(start_dot, slopes) { const pattern = [ start_dot ]; for (var j=0; j<slopes.length; j++) { var next_dot = nextDot(pattern[pattern.length-1], slopes[j], 1); if (next_dot < 0) return []; if (pattern.includes(next_dot)) { next_dot = nextDot(pattern[pattern.length-1], slopes[j], 2); if (next_dot < 0) return []; } pattern.push(next_dot); } return pattern; } function isGood(pattern) { if (pattern.length != 9) return false; for (var i=0; i<9; i++) { for (var j=i+1; j<9; j++) { if (pattern[i] == pattern[j]) return false; } } return true; } function nextDot(dot, slope_index, step) { const flip = (slope_index < 0) ? -1 : 1; const dx = dslopes[Math.abs(slope_index)-1][0] * flip * step; const dy = dslopes[Math.abs(slope_index)-1][1] * flip * step; const x = (dot-1) % 3, y = (dot-1) / 3 | 0; if (x+dx < 0 || x+dx > 2 || y+dy < 0 || y+dy > 2) return -1; return x + dx + (y + dy) * 3 + 1; } function drawDot(index) { const x = (-1 + ((index-1) % 3)) * 60, y = (-1 + ((index-1) / 3 | 0)) * 60; for (var r = 6; r > 0; r -= .15) turtle.jump(x, y - r), turtle.circle(r, 0, 50); } function drawLine(index0, index1) { const cx0 = (-1 + ((index0-1) % 3)) * 60, cy0 = (-1 + ((index0-1) / 3 | 0)) * 60; const cx1 = (-1 + ((index1-1) % 3)) * 60, cy1 = (-1 + ((index1-1) / 3 | 0)) * 60; const thickness = 1, steps = 60; for (var j = 0, a = 0; j < steps; j++, a += Math.PI * 2 / steps) { const x0 = cx0 + thickness * Math.cos(a), y0 = cy0 + thickness * Math.sin(a); const x1 = cx1 + thickness * Math.cos(a), y1 = cy1 + thickness * Math.sin(a); turtle.jump(x0, y0); turtle.goto(x1, y1); } } function sleep(ms) { if (!slow) return; const start = Date.now(); while (Date.now()-start < ms); }