Sat, 03 Jan 2015 20:18:00 +0100
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); |