js/src/tests/ecma_6/Comprehensions/sudoku.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6
michael@0 7 function copy(obj) {
michael@0 8 var o = {};
michael@0 9 for (var i in obj)
michael@0 10 o[i] = obj[i];
michael@0 11 return o;
michael@0 12 }
michael@0 13
michael@0 14 Array.prototype.contains = String.prototype.contains = function (e) {
michael@0 15 for (var elt of this)
michael@0 16 if (elt == e)
michael@0 17 return true;
michael@0 18 return false;
michael@0 19 }
michael@0 20
michael@0 21 Array.prototype.repeat = String.prototype.repeat = function (n) {
michael@0 22 var s = this.constructor();
michael@0 23 for (var i = 0; i < n; i++)
michael@0 24 s = s.concat(this);
michael@0 25 return s;
michael@0 26 }
michael@0 27
michael@0 28 String.prototype.center = function (w) {
michael@0 29 var n = this.length;
michael@0 30 if (w <= n)
michael@0 31 return this;
michael@0 32 var m = Math.floor((w - n) / 2);
michael@0 33 return ' '.repeat(m) + this + ' '.repeat(w - n - m);
michael@0 34 }
michael@0 35
michael@0 36 Array.prototype.toString = Array.prototype.toSource
michael@0 37 Object.prototype.toString = Object.prototype.toSource
michael@0 38
michael@0 39 function all(seq) {
michael@0 40 for (var e of seq)
michael@0 41 if (!e)
michael@0 42 return false;
michael@0 43 return true;
michael@0 44 }
michael@0 45
michael@0 46 function some(seq) {
michael@0 47 for (var e of seq)
michael@0 48 if (e)
michael@0 49 return e;
michael@0 50 return false;
michael@0 51 }
michael@0 52
michael@0 53 function cross(A, B) {
michael@0 54 return [for (a of A) for (b of B) a+b];
michael@0 55 }
michael@0 56
michael@0 57 function dict(A) {
michael@0 58 var d = {};
michael@0 59 for (var e of A)
michael@0 60 d[e[0]] = e[1];
michael@0 61 return d;
michael@0 62 }
michael@0 63
michael@0 64 function set(A) {
michael@0 65 var s = [];
michael@0 66 for (var e of A)
michael@0 67 if (!s.contains(e))
michael@0 68 s.push(e);
michael@0 69 return s;
michael@0 70 }
michael@0 71
michael@0 72 function zip(A, B) {
michael@0 73 var z = [];
michael@0 74 var n = Math.min(A.length, B.length);
michael@0 75 for (var i = 0; i < n; i++)
michael@0 76 z.push([A[i], B[i]]);
michael@0 77 return z;
michael@0 78 }
michael@0 79
michael@0 80 rows = 'ABCDEFGHI';
michael@0 81 cols = '123456789';
michael@0 82 digits = '123456789';
michael@0 83 squares = cross(rows, cols);
michael@0 84 unitlist = [for (c of cols) cross(rows, c)]
michael@0 85 .concat([for (r of rows) cross(r, cols)])
michael@0 86 .concat([for (rs of ['ABC','DEF','GHI']) for (cs of ['123','456','789']) cross(rs, cs)]);
michael@0 87 units = dict((for (s of squares)
michael@0 88 [s, [for (u of unitlist) if (u.contains(s)) u]]));
michael@0 89
michael@0 90 peers = dict((for (s of squares)
michael@0 91 [s, set([for (u of units[s]) for (s2 of u) if (s2 != s) s2])]));
michael@0 92
michael@0 93 // Given a string of 81 digits (or . or 0 or -), return a dict of {cell:values}.
michael@0 94 function parse_grid(grid) {
michael@0 95 grid = [for (c of grid) if ('0.-123456789'.contains(c)) c];
michael@0 96 var values = dict((for (s of squares) [s, digits]));
michael@0 97
michael@0 98 for (var pair of zip(squares, grid)) {
michael@0 99 var s = pair[0], d = pair[1];
michael@0 100 if (digits.contains(d) && !assign(values, s, d))
michael@0 101 return false;
michael@0 102 }
michael@0 103 return values;
michael@0 104 }
michael@0 105
michael@0 106 // Eliminate all the other values (except d) from values[s] and propagate.
michael@0 107 function assign(values, s, d) {
michael@0 108 if (all((for (d2 of values[s]) if (d2 != d) eliminate(values, s, d2))))
michael@0 109 return values;
michael@0 110 return false;
michael@0 111 }
michael@0 112
michael@0 113 // Eliminate d from values[s]; propagate when values or places <= 2.
michael@0 114 function eliminate(values, s, d) {
michael@0 115 if (!values[s].contains(d))
michael@0 116 return values; // Already eliminated
michael@0 117 values[s] = values[s].replace(d, '');
michael@0 118 if (values[s].length == 0)
michael@0 119 return false; // Contradiction: removed last value
michael@0 120 if (values[s].length == 1) {
michael@0 121 // If there is only one value (d2) left in square, remove it from peers
michael@0 122 var d2 = values[s][0];
michael@0 123 if (!all((for (s2 of peers[s]) eliminate(values, s2, d2))))
michael@0 124 return false;
michael@0 125 }
michael@0 126 // Now check the places where d appears in the units of s
michael@0 127 for (var u of units[s]) {
michael@0 128 var dplaces = [for (s of u) if (values[s].contains(d)) s];
michael@0 129 if (dplaces.length == 0)
michael@0 130 return false;
michael@0 131 if (dplaces.length == 1)
michael@0 132 // d can only be in one place in unit; assign it there
michael@0 133 if (!assign(values, dplaces[0], d))
michael@0 134 return false;
michael@0 135 }
michael@0 136 return values;
michael@0 137 }
michael@0 138
michael@0 139 // Used for debugging.
michael@0 140 function print_board(values) {
michael@0 141 var width = 1 + Math.max.apply(Math, [for (s of squares) values[s].length]);
michael@0 142 var line = '\n' + ['-'.repeat(width*3)].repeat(3).join('+');
michael@0 143 for (var r of rows)
michael@0 144 print([for (c of cols)
michael@0 145 values[r+c].center(width) + ('36'.contains(c) && '|' || '')]
michael@0 146 .join('') + ('CF'.contains(r) && line || ''));
michael@0 147 print('\n');
michael@0 148 }
michael@0 149
michael@0 150 easy = "..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..";
michael@0 151
michael@0 152 print_board(parse_grid(easy));
michael@0 153
michael@0 154 // Using depth-first search and constraint propagation, try all possible values.
michael@0 155 function search(values) {
michael@0 156 if (!values)
michael@0 157 return false; // Failed earlier
michael@0 158 if (all((for (s of squares) values[s].length == 1)))
michael@0 159 return values; // Solved!
michael@0 160
michael@0 161 // Choose the unfilled square s with the fewest possibilities
michael@0 162 // XXX Math.min etc. should work with generator expressions and other iterators
michael@0 163 // XXX Math.min etc. should work on arrays (lists or tuples in Python) as well as numbers
michael@0 164 var a = [for (s of squares) if (values[s].length > 1) values[s].length + s].sort();
michael@0 165 var s = a[0].slice(-2);
michael@0 166
michael@0 167 return some((for (d of values[s]) search(assign(copy(values), s, d))));
michael@0 168 }
michael@0 169
michael@0 170 hard = '4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......';
michael@0 171
michael@0 172 print_board(search(parse_grid(hard)))
michael@0 173
michael@0 174 if (typeof reportCompare === "function")
michael@0 175 reportCompare(true, true);

mercurial