Compare commits
2 Commits
ca22cb129d
...
fa970170d4
Author | SHA1 | Date | |
---|---|---|---|
fa970170d4 | |||
573608b63c |
22
400.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php http_response_code(400); ?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='fr'>
|
||||||
|
<head>
|
||||||
|
<?php require("head.php"); ?>
|
||||||
|
<title>Requête incorrecte</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>Requête incorrecte</h1>
|
||||||
|
</header>
|
||||||
|
L'adresse URL doit être de la forme :<br/>
|
||||||
|
<?=$dirUrl?>/?<em>grille</em><br/>
|
||||||
|
<em>grille</em> étant une suite de 81 caractères représentant la grille de gauche à droite puis de haut en bas, soit :
|
||||||
|
<ul>
|
||||||
|
<li>un chiffre entre 1 et 9 pour les cases connues</li>
|
||||||
|
<li>un point pour les case vides</li>
|
||||||
|
</ul>
|
||||||
|
Exemple :<br/>
|
||||||
|
<a href='<?=$newGridUrl?>'><?=$newGridUrl?></a>
|
||||||
|
</body>
|
||||||
|
</html>
|
54
404.php
@ -1,54 +0,0 @@
|
|||||||
<?php
|
|
||||||
require("classes.php");
|
|
||||||
$grid = new Grid();
|
|
||||||
$grid->generate();
|
|
||||||
|
|
||||||
header("HTTP/1.0 404 Not Found", true, 404);
|
|
||||||
|
|
||||||
$urlDir = $_SERVER["REQUEST_SCHEME"] . "://" . $_SERVER["HTTP_HOST"] . dirname($_SERVER["DOCUMENT_URI"]);
|
|
||||||
$urlExample = $urlDir . "/" . $grid->toString();
|
|
||||||
?>
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang='fr'>
|
|
||||||
<head>
|
|
||||||
<meta charset='utf-8' />
|
|
||||||
<meta name='viewport' content='width=device-width' />
|
|
||||||
<title>Sudoku non trouvé</title>
|
|
||||||
<link rel='stylesheet' type='text/css' href='style.css' />
|
|
||||||
<link rel="apple-touch-icon" href="thumbnail.php?size=57" sizes="57x57">
|
|
||||||
<link rel="apple-touch-icon" href="thumbnail.php?size=114" sizes="114x114">
|
|
||||||
<link rel="apple-touch-icon" href="thumbnail.php?size=72" sizes="72x72">
|
|
||||||
<link rel="apple-touch-icon" href="thumbnail.php?size=144" sizes="144x144">
|
|
||||||
<link rel="apple-touch-icon" href="thumbnail.php?size=60" sizes="60x60">
|
|
||||||
<link rel="apple-touch-icon" href="thumbnail.php?size=120" sizes="120x120">
|
|
||||||
<link rel="apple-touch-icon" href="thumbnail.php?size=76" sizes="76x76">
|
|
||||||
<link rel="apple-touch-icon" href="thumbnail.php?size=152" sizes="152x152">
|
|
||||||
<link rel="icon" type="image/png" href="thumbnail.php?size=196" sizes="196x196">
|
|
||||||
<link rel="icon" type="image/png" href="thumbnail.php?size=160" sizes="160x160">
|
|
||||||
<link rel="icon" type="image/png" href="thumbnail.php?size=96" sizes="96x96">
|
|
||||||
<link rel="icon" type="image/png" href="thumbnail.php?size=16" sizes="16x16">
|
|
||||||
<link rel="icon" type="image/png" href="thumbnail.php?size=32" sizes="32x32">
|
|
||||||
<link rel="manifest" href="manifest.php">
|
|
||||||
<meta property="og:title" content="Sudoku"/>
|
|
||||||
<meta property="og:type" content="website"/>
|
|
||||||
<meta property="og:url" content="<?=$_SERVER["REQUEST_SCHEME"]."://".$_SERVER["HTTP_HOST"].$_SERVER["DOCUMENT_URI"]?>"/>
|
|
||||||
<meta property="og:image" content="<?=$_SERVER["REQUEST_SCHEME"]."://".$_SERVER["HTTP_HOST"].dirname($_SERVER["DOCUMENT_URI"])?>/thumbnail.php?size=200"/>
|
|
||||||
<meta property="og:image:width" content="200"/>
|
|
||||||
<meta property="og:image:height" content="200"/>
|
|
||||||
<meta property="og:description" content="Remplissez la grille de sorte que chaque ligne, colonne et région (carré de 3×3 cases) contienne tous les chiffres de 1 à 9."/>
|
|
||||||
<meta property="og:locale" content="fr_FR"/>
|
|
||||||
<meta property="og:site_name" content="<?=$_SERVER["HTTP_HOST"]?>"/>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<header>
|
|
||||||
<h1>#404</h1>
|
|
||||||
</header>
|
|
||||||
L'adresse URL doit être de la forme : <?=$urlDir?>/<em>grille</em>,<br/>
|
|
||||||
<em>grille</em> étant une suite de 81 caractères représentant la grille de gauche à droite puis de haut en bas, soit :
|
|
||||||
<ul>
|
|
||||||
<li>un chiffre entre 1 et 9 pour les cases connues</li>
|
|
||||||
<li>un point pour les case vides</li>
|
|
||||||
</ul>
|
|
||||||
Exemple : <a href='<?=$urlExample?>'><?=$urlExample?></a><br/>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
43
classes.php
@ -85,49 +85,6 @@
|
|||||||
array_unset_value($box->value, $neighbour->candidates);
|
array_unset_value($box->value, $neighbour->candidates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function generate_() {
|
|
||||||
// Init with a shuffle row
|
|
||||||
$values = array("1", "2", "3", "4", "5", "6", "7", "8", "9");
|
|
||||||
shuffle($values);
|
|
||||||
forEach($this->rows[0] as $columnId => $box) {
|
|
||||||
$box->value = $values[$columnId];
|
|
||||||
forEach($box->neighbourhood as $neighbour)
|
|
||||||
array_unset_value($box->value, $neighbour->candidates);
|
|
||||||
}
|
|
||||||
// Fill grid
|
|
||||||
$this->solutionsGenerator(true)->current();
|
|
||||||
|
|
||||||
// Remove clues while there is still a unique solution
|
|
||||||
shuffle($this->boxes);
|
|
||||||
$nbClues = count($this->boxes);
|
|
||||||
foreach($this->boxes as $testBox) {
|
|
||||||
$testBoxes = array($testBox);
|
|
||||||
if ($nbClues >= 30)
|
|
||||||
$testBoxes[] = $this->rows[8-$testBox->rowId][8-$testBox->columnId];
|
|
||||||
if ($nbClues >= 61) {
|
|
||||||
$testBoxes[] = $this->rows[8-$testBox->rowId][$testBox->columnId];
|
|
||||||
$testBoxes[] = $this->rows[$testBox->rowId][8-$testBox->columnId];
|
|
||||||
}
|
|
||||||
$testBoxes = array_filter($testBoxes, "isKnown");
|
|
||||||
$erasedValues = array();
|
|
||||||
forEach($testBoxes as $testBox) {
|
|
||||||
$erasedValues[] = $testBox->value;
|
|
||||||
$testBox->value = UNKNOWN;
|
|
||||||
forEach($testBox->neighbourhood as $neighbour)
|
|
||||||
$neighbour->searchCandidates();
|
|
||||||
}
|
|
||||||
if ($this->isValid()) {
|
|
||||||
$nbClues -= count($testBoxes);
|
|
||||||
} else {
|
|
||||||
forEach($testBoxes as $i => $testBox) {
|
|
||||||
$testBox->value = $erasedValues[$i];
|
|
||||||
forEach($testBox->neighbourhood as $neighbour) array_unset_value($testBox->value, $neighbour->candidates);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$validGrids[] = $this->toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
function generate() {
|
function generate() {
|
||||||
// Init with a shuffle row
|
// Init with a shuffle row
|
||||||
|
11
css/bootstrap-dark.min.css
vendored
Normal file
2018
css/bootstrap-icons.css
vendored
Normal file
10
css/bootstrap-night.min.css
vendored
Normal file
6
css/bootstrap.min.css
vendored
Normal file
135
css/style.css
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
body {
|
||||||
|
width: min-content;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="number"]::-webkit-outer-spin-button,
|
||||||
|
input::-webkit-inner-spin-button {
|
||||||
|
-webkit-appearance: none !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="number"]::-webkit-calendar-picker-indicator {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: separate;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
table input {
|
||||||
|
width: 2.5rem !important;
|
||||||
|
height: 2.5rem !important;
|
||||||
|
font-size: 1.3rem !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
text-align: center;
|
||||||
|
-moz-appearance: textfield !important;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
table td.table-primary input,
|
||||||
|
table td.table-active input,
|
||||||
|
table input:not([disabled]) {
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:nth-child(3n+1) td input {
|
||||||
|
border-top-width: 3px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:last-child td input {
|
||||||
|
border-bottom-width: 3px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
td:nth-child(3n+1) input {
|
||||||
|
border-left-width: 3px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
td:last-child input {
|
||||||
|
border-right-width: 3px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:first-child td:first-child {
|
||||||
|
border-top-left-radius: .7rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:first-child td:first-child input {
|
||||||
|
border-top-left-radius: .5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:first-child td:last-child {
|
||||||
|
border-top-right-radius: .7rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:first-child td:last-child input {
|
||||||
|
border-top-right-radius: .5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:last-child td:first-child {
|
||||||
|
border-bottom-left-radius: .7rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:last-child td:first-child input {
|
||||||
|
border-bottom-left-radius: .5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:last-child td:last-child {
|
||||||
|
border-bottom-right-radius: .7rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:last-child td:last-child input {
|
||||||
|
border-bottom-right-radius: .5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
transition: background-color .4s, box-shadow .4s !important;
|
||||||
|
border: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-menu li {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-active {
|
||||||
|
cursor: not-allowed !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
label {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:disabled,
|
||||||
|
:disabled+label {
|
||||||
|
cursor: not-allowed !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
table input:enabled {
|
||||||
|
cursor: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bi::before {
|
||||||
|
vertical-align: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pencil {
|
||||||
|
color: var(--bs-secondary-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme:dark) {
|
||||||
|
.pencil {
|
||||||
|
color: #5a5a5a !important;
|
||||||
|
}
|
||||||
|
}
|
BIN
fonts/bootstrap-icons.woff
Normal file
BIN
fonts/bootstrap-icons.woff2
Normal file
36
head.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Sudoku</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<link href="css/bootstrap-dark.min.css" rel="stylesheet" type="text/css" title="Automatique" />
|
||||||
|
<link href="css/bootstrap.min.css" rel="alternate stylesheet" type="text/css" title="Clair">
|
||||||
|
<link href="css/bootstrap-night.min.css" rel="alternate stylesheet" type="text/css" title="Sombre">
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/bootstrap-icons.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/style.css" />
|
||||||
|
<link rel="apple-touch-icon" href="thumbnail.php?size=57" sizes="57x57">
|
||||||
|
<link rel="apple-touch-icon" href="thumbnail.php?size=114" sizes="114x114">
|
||||||
|
<link rel="apple-touch-icon" href="thumbnail.php?size=72" sizes="72x72">
|
||||||
|
<link rel="apple-touch-icon" href="thumbnail.php?size=144" sizes="144x144">
|
||||||
|
<link rel="apple-touch-icon" href="thumbnail.php?size=60" sizes="60x60">
|
||||||
|
<link rel="apple-touch-icon" href="thumbnail.php?size=120" sizes="120x120">
|
||||||
|
<link rel="apple-touch-icon" href="thumbnail.php?size=76" sizes="76x76">
|
||||||
|
<link rel="apple-touch-icon" href="thumbnail.php?size=152" sizes="152x152">
|
||||||
|
<link rel="icon" type="image/png" href="thumbnail.php?size=196" sizes="196x196">
|
||||||
|
<link rel="icon" type="image/png" href="thumbnail.php?size=160" sizes="160x160">
|
||||||
|
<link rel="icon" type="image/png" href="thumbnail.php?size=96" sizes="96x96">
|
||||||
|
<link rel="icon" type="image/png" href="thumbnail.php?size=16" sizes="16x16">
|
||||||
|
<link rel="icon" type="image/png" href="thumbnail.php?size=32" sizes="32x32">
|
||||||
|
<link rel="manifest" href="manifest.php">
|
||||||
|
<meta property="og:title" content="Sudoku" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:url"
|
||||||
|
content="<?=$_SERVER["REQUEST_SCHEME"]."://".$_SERVER["HTTP_HOST"].$_SERVER["DOCUMENT_URI"]?>" />
|
||||||
|
<meta property="og:image"
|
||||||
|
content="<?=$_SERVER["REQUEST_SCHEME"]."://".$_SERVER["HTTP_HOST"].dirname($_SERVER["DOCUMENT_URI"])?>/thumbnail.php?size=200" />
|
||||||
|
<meta property="og:image:width" content="200" />
|
||||||
|
<meta property="og:image:height" content="200" />
|
||||||
|
<meta property="og:description"
|
||||||
|
content="Remplissez la grille de sorte que chaque ligne, colonne et région (carré de 3×3 cases) contienne tous les chiffres de 1 à 9." />
|
||||||
|
<meta property="og:locale" content="fr_FR" />
|
||||||
|
<meta property="og:site_name" content="<?=$_SERVER["HTTP_HOST"]?>" />
|
||||||
|
<script src='js/sudoku.js'></script>
|
||||||
|
<script src="js/bootstrap.bundle.min.js" integrity="sha384-qKXV1j0HvMUeCBQ+QVp7JcfGl760yU08IQ+GpUo5hlbpg51QRiuqHAJz8+BrxE/N" crossorigin="anonymous"></script>
|
@ -1 +0,0 @@
|
|||||||
<svg id="Capa_1" enable-background="new 0 0 512 512" height="24" viewBox="0 0 512 512" width="24" xmlns="http://www.w3.org/2000/svg"><g><path d="m214.28 498.762c4.098 0 8.029-1.628 10.927-4.526l278.144-278.144c11.398-11.398 11.398-29.879 0-41.277l-152.928-152.928c-11.398-11.398-29.878-11.398-41.277 0l-300.597 300.598c-11.398 11.398-11.398 29.878 0 41.277l130.474 130.474c2.898 2.898 6.828 4.526 10.927 4.526z" fill="#d3e1f5"/><path d="m275.208 386.418-78.91 78.91c-2.898 2.898-6.828 4.526-10.927 4.526h-64.331c-4.098 0-8.029-1.628-10.927-4.526l28.909 28.909c2.898 2.898 6.829 4.526 10.927 4.526h64.331c4.098 0 8.029-1.628 10.927-4.526l78.91-78.91z" fill="#c0d6f2"/><path d="m505.059 176.523-156.344-156.344c-10.455-10.455-28.935-8.925-41.277 3.417l-228.75 228.75 194.205 194.204 228.75-228.75c12.341-12.342 13.871-30.822 3.416-41.277z" fill="#0473ce"/><path d="m187.955 245.061 134.545-134.545c4.023-4.023 10.546-4.023 14.569 0l77.653 77.653c4.023 4.023 4.023 10.546 0 14.569l-134.545 134.545c-4.023 4.023-10.546 4.023-14.569 0l-77.653-77.653c-4.023-4.023-4.023-10.546 0-14.569z" fill="#0055a3"/><path d="m505.059 176.523-28.908-28.909c10.455 10.455 8.925 28.935-3.417 41.277l-228.75 228.75 28.909 28.909 228.75-228.75c12.341-12.342 13.871-30.822 3.416-41.277z" fill="#0067c5"/></g></svg>
|
|
Before Width: | Height: | Size: 1.3 KiB |
@ -1,44 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
||||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
|
||||||
<polygon style="fill:#FFCC75;" points="47.202,417.53 94.404,464.732 47.202,511.945 0,464.743 "/>
|
|
||||||
<polygon style="fill:#082947;" points="236.149,414.811 212.545,438.4 111.564,368.892 166.634,313.823 "/>
|
|
||||||
<polygon style="fill:#274B6D;" points="182.37,329.559 127.301,384.628 73.529,299.384 97.126,275.788 "/>
|
|
||||||
<polygon style="fill:#FF9D49;" points="512,118.078 452.926,59.003 294.044,186.413 166.634,345.296 251.886,430.548 "/>
|
|
||||||
<path style="fill:#274B6D;" d="M143.037,368.892l69.508,69.508c0,0-61.136,0.802-102.397,42.063l-39.35-39.333l20.383-51.855
|
|
||||||
L143.037,368.892z"/>
|
|
||||||
<polygon style="fill:#FFCC75;" points="393.977,0.055 81.39,260.051 166.634,345.296 452.926,59.003 "/>
|
|
||||||
<path style="fill:#185F8D;" d="M73.529,299.384l69.508,69.508l-72.239,72.239L31.458,401.79
|
|
||||||
C72.719,360.529,73.529,299.384,73.529,299.384z"/>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 1.3 KiB |
@ -1,48 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
||||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 511.989 511.989" style="enable-background:new 0 0 511.989 511.989;" xml:space="preserve" width="24" height="24">
|
|
||||||
<rect x="408.399" y="26.854" transform="matrix(-0.7071 0.7071 -0.7071 -0.7071 819.7593 -231.0359)" style="fill:#9EC8E8;" width="98.659" height="54.811"/>
|
|
||||||
<polygon style="fill:#082947;" points="430.604,174.402 186.029,418.976 124.017,372.468 376.343,120.141 "/>
|
|
||||||
<polygon style="fill:#274B6D;" points="384.094,127.892 131.769,380.219 93.012,325.958 337.586,81.384 "/>
|
|
||||||
<polygon style="fill:#4284B2;" points="477.112,127.892 430.604,174.402 376.343,120.141 430.604,81.384 "/>
|
|
||||||
<rect x="20.377" y="439.543" transform="matrix(-0.7071 -0.7071 0.7071 -0.7071 -273.1405 837.2019)" style="fill:#082947;" width="32.886" height="71.254"/>
|
|
||||||
<polygon style="fill:#4284B2;" points="186.029,418.976 69.757,488.74 46.502,465.484 77.509,403.473 139.52,372.468 "/>
|
|
||||||
<g>
|
|
||||||
<polygon style="fill:#6DA8D6;" points="139.52,372.468 46.502,465.484 23.248,442.23 93.012,325.958 "/>
|
|
||||||
|
|
||||||
<rect x="351.209" y="48.511" transform="matrix(-0.7071 0.7071 -0.7071 -0.7071 713.2485 -132.6418)" style="fill:#6DA8D6;" width="65.773" height="65.773"/>
|
|
||||||
</g>
|
|
||||||
<polygon style="fill:#9EC8E8;" points="178.681,193.781 155.426,170.527 302.704,23.249 442.229,162.774 418.975,186.028
|
|
||||||
302.704,69.757 "/>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 1.7 KiB |
@ -1 +0,0 @@
|
|||||||
<svg id="Capa_1" enable-background="new 0 0 497 497" height="24" viewBox="0 0 497 497" width="24" xmlns="http://www.w3.org/2000/svg"><g><g><path d="m282.159 497h-67.319c-5.014 0-9.331-3.539-10.314-8.456l-9.529-47.643h107.004l-9.529 47.643c-.982 4.917-5.299 8.456-10.313 8.456z" fill="#b1abb4"/></g><g><path d="m272.002 440.901-9.529 47.643c-.983 4.917-5.3 8.456-10.314 8.456h30c5.014 0 9.331-3.539 10.314-8.456l9.529-47.643z" fill="#a29aa5"/></g><path d="m302.997 418.462c12.392 0 22.438-10.047 22.438-22.44s-10.046-22.439-22.439-22.439l-54.496-20-54.496 20c-12.393 0-22.439 10.046-22.439 22.439s10.046 22.439 22.438 22.44c-12.392.001-22.438 10.047-22.438 22.439 0 12.393 10.047 22.439 22.44 22.439h108.992c12.393 0 22.439-10.047 22.439-22.439-.001-12.392-10.046-22.439-22.439-22.439z" fill="#f6f6f6"/><path d="m302.996 418.462c12.393 0 22.439-10.047 22.439-22.44s-10.046-22.439-22.439-22.439l-13.031-10-16.969 10c12.393 0 22.439 10.046 22.439 22.439s-10.046 22.44-22.439 22.44c12.393 0 22.439 10.047 22.439 22.439 0 12.393-10.046 22.439-22.439 22.439h30c12.393 0 22.439-10.047 22.439-22.439 0-12.393-10.046-22.439-22.439-22.439z" fill="#eaeaea"/><g><path d="m405.577 157.077c0-87.128-70.938-157.688-158.209-157.073-85.121.6-154.794 69.813-155.93 154.929-.489 36.674 11.595 70.504 32.213 97.463 23.117 30.226 35.092 67.512 35.092 105.565v1.372c0 7.87 6.38 14.25 14.25 14.25h151.017c7.87 0 14.25-6.38 14.25-14.25 0-38.726 12.155-76.653 35.537-107.523 19.945-26.334 31.78-59.15 31.78-94.733z" fill="#f7e365"/></g><g><path d="m247.367.004c-4.64.033-9.23.281-13.769.713 79.668 7.598 141.978 74.702 141.978 156.359 0 35.583-11.835 68.4-31.781 94.734-23.382 30.87-35.537 68.797-35.537 107.523 0 7.87-6.38 14.25-14.25 14.25h30c7.87 0 14.25-6.38 14.25-14.25 0-38.726 12.155-76.653 35.537-107.523 19.946-26.334 31.781-59.15 31.781-94.734.001-87.128-70.938-157.687-158.209-157.072z" fill="#f0d944"/></g><path d="m326.359 109.713c-3.749-1.763-8.216-.154-9.979 3.594l-10.465 22.244c-.075-.049-.145-.103-.222-.149-35.277-21.166-79.107-21.166-114.385 0-.077.046-.147.1-.222.149l-10.465-22.244c-1.764-3.748-6.231-5.357-9.98-3.594-3.748 1.764-5.357 6.231-3.594 9.979l39.048 82.998c6.613 14.056 10.108 29.696 10.108 45.229v11.246 2.333 112.083h15v-106.914h34.594v106.916h15v-112.083-2.333-11.247c0-15.533 3.496-31.173 10.108-45.229l39.048-82.998c1.763-3.748.154-8.216-3.594-9.98zm-49.027 86.592c-7.546 16.041-11.535 33.889-11.535 51.615v3.746h-34.594v-3.746c0-17.726-3.989-35.574-11.535-51.615l-22.263-47.321c.555-.174 1.099-.408 1.62-.72 30.517-18.311 68.433-18.311 98.949 0 .521.313 1.067.541 1.623.715z" fill="#dbb72b"/></g></svg>
|
|
Before Width: | Height: | Size: 2.6 KiB |
@ -1,45 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
||||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve" width="24" height="24">
|
|
||||||
<polygon style="fill:#FF9D49;" points="393.29,213.665 142.441,464.524 87.044,424.954 345.817,150.364 "/>
|
|
||||||
<polygon style="fill:#FFCC75;" points="353.73,158.277 87.044,424.954 47.473,369.557 298.333,118.708 "/>
|
|
||||||
<polygon style="fill:#BD1515;" points="512,94.965 440.78,166.185 377.475,118.708 464.522,47.486 "/>
|
|
||||||
<polygon style="fill:#F2484B;" points="464.516,47.482 385.382,126.615 345.817,71.224 417.038,0.002 "/>
|
|
||||||
<g>
|
|
||||||
|
|
||||||
<rect x="335.974" y="75.292" transform="matrix(-0.7071 0.7071 -0.7071 -0.7071 731.5841 -18.1559)" style="fill:#082947;" width="67.157" height="134.292"/>
|
|
||||||
<polygon style="fill:#082947;" points="71.22,488.261 0,511.998 23.736,440.776 63.305,448.692 "/>
|
|
||||||
</g>
|
|
||||||
<polygon style="fill:#F2EBD9;" points="47.473,369.557 23.736,440.776 71.22,488.261 142.441,464.524 "/>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 1.3 KiB |
@ -1,55 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
||||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
width="574.859px" height="574.86px" viewBox="0 0 574.859 574.86" style="enable-background:new 0 0 574.859 574.86;"
|
|
||||||
xml:space="preserve">
|
|
||||||
<g>
|
|
||||||
<path d="M181.688,521.185V353.841H19.125v167.344c0,10.566,13.34,23.906,23.906,23.906h124.312
|
|
||||||
C177.91,545.091,181.688,531.751,181.688,521.185z M66.938,502.06c0,2.64-2.142,4.781-4.781,4.781s-4.781-2.142-4.781-4.781
|
|
||||||
V377.748c0-2.64,2.142-4.781,4.781-4.781s4.781,2.142,4.781,4.781V502.06z M105.188,502.06c0,2.64-2.142,4.781-4.781,4.781
|
|
||||||
s-4.781-2.142-4.781-4.781V377.748c0-2.64,2.142-4.781,4.781-4.781s4.781,2.142,4.781,4.781V502.06z M143.438,502.06
|
|
||||||
c0,2.64-2.142,4.781-4.781,4.781s-4.781-2.142-4.781-4.781V377.748c0-2.64,2.142-4.781,4.781-4.781s4.781,2.142,4.781,4.781V502.06
|
|
||||||
z"/>
|
|
||||||
<path d="M19.125,334.716h162.562v-19.125h19.125v-19.125h-57.375c0-10.566-6.828-19.125-15.243-19.125H77.399
|
|
||||||
c-8.415,0-15.243,8.559-15.243,19.125H0v19.125h19.125V334.716z"/>
|
|
||||||
<path d="M357.007,191.556C370.968,329.811,243.892,542.08,243.892,542.08c145.235-78.212,169.189-207.363,169.189-207.363
|
|
||||||
c42.333,66.479,44.475,228.305,44.475,228.305c80.995-194.109,0-377.049,0-377.049l117.304,48.874
|
|
||||||
c-19.546-74.014-141.047-125.68-141.047-125.68c-110.322,50.27-249.974,44.686-249.974,44.686
|
|
||||||
C259.249,226.469,357.007,191.556,357.007,191.556z"/>
|
|
||||||
<circle cx="369.782" cy="55.128" r="43.29"/>
|
|
||||||
<path d="M94.43,229.529c5.977-2.391,27.492-13.148,28.764,0c1.271,13.148,11.876,9.562,19.048,0s3.586-25.102,11.953-23.906
|
|
||||||
s15.539-10.758,17.93-21.735c2.391-10.978-22.711-18.905-33.469-21.458s-20.32,13.321-27.492,13.321s-17.93-20.33-25.102-10.768
|
|
||||||
s-11.953,40.641-11.953,40.641c-10.758-5.977-21.516,7.172-25.102,16.734S88.453,231.919,94.43,229.529z"/>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.2 KiB |
43
img/save.svg
@ -1,43 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
||||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
|
||||||
<path style="fill:#DCF4FF;" d="M512,492H0V20h403.213L512,128.787V492z"/>
|
|
||||||
<polygon style="fill:#CCEFFF;" points="403.213,20 256,20 256,492 512,492 512,128.787 "/>
|
|
||||||
<path style="fill:#0A4EAF;" d="M403.213,20H396v175H116V20H0v472h116V315c0-16.568,13.431-30,30-30h220c16.569,0,30,13.432,30,30
|
|
||||||
v177h116V128.787L403.213,20z"/>
|
|
||||||
<g>
|
|
||||||
<rect x="296" y="20" style="fill:#063E8B;" width="40" height="115"/>
|
|
||||||
<path style="fill:#063E8B;" d="M403.213,20H396v175H256v90h110c16.569,0,30,13.432,30,30v177h116V128.787L403.213,20z"/>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 1.0 KiB |
46
img/undo.svg
@ -1,46 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
||||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
width="299.021px" height="299.021px" viewBox="0 0 299.021 299.021" style="enable-background:new 0 0 299.021 299.021;"
|
|
||||||
xml:space="preserve">
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<path d="M292.866,254.432c-2.288,0-4.443-1.285-5.5-3.399c-0.354-0.684-28.541-52.949-146.169-54.727v51.977
|
|
||||||
c0,2.342-1.333,4.48-3.432,5.513c-2.096,1.033-4.594,0.793-6.461-0.63L2.417,154.392C0.898,153.227,0,151.425,0,149.516
|
|
||||||
c0-1.919,0.898-3.72,2.417-4.888l128.893-98.77c1.87-1.426,4.365-1.667,6.461-0.639c2.099,1.026,3.432,3.173,3.432,5.509v54.776
|
|
||||||
c3.111-0.198,7.164-0.37,11.947-0.37c43.861,0,145.871,13.952,145.871,143.136c0,2.858-1.964,5.344-4.75,5.993
|
|
||||||
C293.802,254.384,293.34,254.432,292.866,254.432z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 1.2 KiB |
46
index.php
@ -1,10 +1,40 @@
|
|||||||
<?php
|
<?php
|
||||||
require("classes.php");
|
require("classes.php");
|
||||||
session_start();
|
session_start();
|
||||||
$grid = new Grid();
|
$fullUrl = $_SERVER["REQUEST_SCHEME"]."://".$_SERVER["HTTP_HOST"].$_SERVER["DOCUMENT_URI"];
|
||||||
$grid->generate();
|
$dirUrl = dirname($fullUrl);
|
||||||
$currentGrid = $grid->toString();
|
$currentGrid = strip_tags($_SERVER['QUERY_STRING']);
|
||||||
$_SESSION[$currentGrid] = "checked";
|
|
||||||
header("Location: ".$_SERVER["REQUEST_SCHEME"]."://".$_SERVER["HTTP_HOST"].dirname($_SERVER["DOCUMENT_URI"])."/".$currentGrid);
|
if (preg_match("/^[1-9.]{81}$/", $currentGrid)) {
|
||||||
exit();
|
if (!isset($_SESSION[$currentGrid]) || $_SESSION[$currentGrid] != "checked") {
|
||||||
?>
|
$grid = new Grid();
|
||||||
|
$grid->import($currentGrid);
|
||||||
|
if ($grid->containsDuplicates()) {
|
||||||
|
$warning = "Cette grille contient des doublons.";
|
||||||
|
} else {
|
||||||
|
switch($grid->countSolutions(2)) {
|
||||||
|
case 0:
|
||||||
|
$warning = "Cette grille n'a pas de solution.";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
$validGrids[] = $currentGrid;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$warning = "Cette grille a plusieurs solutions.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
require("sudoku.php");
|
||||||
|
} else {
|
||||||
|
$grid = new Grid();
|
||||||
|
$grid->generate();
|
||||||
|
$gridAsString = $grid->toString();
|
||||||
|
$newGridUrl = "$dirUrl/?$gridAsString";
|
||||||
|
$_SESSION[$gridAsString] = "checked";
|
||||||
|
if (!$currentGrid) {
|
||||||
|
header("Location: $newGridUrl");
|
||||||
|
} else {
|
||||||
|
require("400.php");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
7
js/bootstrap.bundle.min.js
vendored
Normal file
@ -6,7 +6,6 @@ let boxes = []
|
|||||||
let rows = Array.from(Array(9), x => [])
|
let rows = Array.from(Array(9), x => [])
|
||||||
let columns = Array.from(Array(9), x => [])
|
let columns = Array.from(Array(9), x => [])
|
||||||
let regions = Array.from(Array(9), x => [])
|
let regions = Array.from(Array(9), x => [])
|
||||||
let suggestionTimer = null
|
|
||||||
let valueToInsert = ""
|
let valueToInsert = ""
|
||||||
let history = []
|
let history = []
|
||||||
let accessKeyModifiers = "AccessKey+"
|
let accessKeyModifiers = "AccessKey+"
|
||||||
@ -26,7 +25,7 @@ function shuffle(iterable) {
|
|||||||
return array
|
return array
|
||||||
}
|
}
|
||||||
|
|
||||||
window.onload = function () {
|
window.onload = function() {
|
||||||
let rowId = 0
|
let rowId = 0
|
||||||
for (let row of grid.getElementsByTagName('tr')) {
|
for (let row of grid.getElementsByTagName('tr')) {
|
||||||
let columnId = 0
|
let columnId = 0
|
||||||
@ -53,6 +52,9 @@ window.onload = function () {
|
|||||||
rowId++
|
rowId++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (localStorage["highlighterCheckbox.checked"]) {
|
||||||
|
highlighterCheckbox.checked = true
|
||||||
|
}
|
||||||
loadSavedGame()
|
loadSavedGame()
|
||||||
|
|
||||||
boxes.forEach(box => {
|
boxes.forEach(box => {
|
||||||
@ -82,7 +84,7 @@ window.onload = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadSavedGame() {
|
function loadSavedGame() {
|
||||||
const savedGame = localStorage[location.pathname]
|
const savedGame = localStorage[location.search]
|
||||||
if (savedGame) {
|
if (savedGame) {
|
||||||
boxes.forEach((box, i) => {
|
boxes.forEach((box, i) => {
|
||||||
if (!box.disabled && savedGame[i] != UNKNOWN) {
|
if (!box.disabled && savedGame[i] != UNKNOWN) {
|
||||||
@ -90,7 +92,7 @@ function loadSavedGame() {
|
|||||||
box.previousValue = savedGame[i]
|
box.previousValue = savedGame[i]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
fixGridLink.href = savedGame
|
fixGridLink.href = "?" + savedGame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +121,7 @@ function onfocus() {
|
|||||||
} else {
|
} else {
|
||||||
this.select()
|
this.select()
|
||||||
}
|
}
|
||||||
this.style.caretColor = valueToInsert? "transparent": "auto"
|
this.style.caretColor = valueToInsert ? "transparent" : "auto"
|
||||||
}
|
}
|
||||||
|
|
||||||
function onclick() {
|
function onclick() {
|
||||||
@ -143,9 +145,14 @@ function onclick() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function oninput() {
|
function oninput() {
|
||||||
history.push({ box: this, value: this.previousValue, placeholder: this.previousPlaceholder })
|
history.push({
|
||||||
|
box: this,
|
||||||
|
value: this.previousValue,
|
||||||
|
placeholder: this.previousPlaceholder
|
||||||
|
})
|
||||||
undoButton.disabled = false
|
undoButton.disabled = false
|
||||||
saveButton.disabled = false
|
saveButton.disabled = false
|
||||||
|
restartButton.disabled = false
|
||||||
if (pencilRadio.checked) {
|
if (pencilRadio.checked) {
|
||||||
this.previousValue = ""
|
this.previousValue = ""
|
||||||
this.previousPlaceholder = this.value
|
this.previousPlaceholder = this.value
|
||||||
@ -164,6 +171,7 @@ function refreshBox(box) {
|
|||||||
function checkBox(box) {
|
function checkBox(box) {
|
||||||
box.neighbourhood.concat([box]).forEach(neighbour => {
|
box.neighbourhood.concat([box]).forEach(neighbour => {
|
||||||
neighbour.setCustomValidity("")
|
neighbour.setCustomValidity("")
|
||||||
|
neighbour.classList.remove("is-invalid")
|
||||||
searchCandidatesOf(neighbour)
|
searchCandidatesOf(neighbour)
|
||||||
if (neighbour.candidates.size == 0) {
|
if (neighbour.candidates.size == 0) {
|
||||||
neighbour.setCustomValidity("Aucun chiffre possible !")
|
neighbour.setCustomValidity("Aucun chiffre possible !")
|
||||||
@ -171,23 +179,32 @@ function checkBox(box) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (box.value) {
|
if (box.value) {
|
||||||
for (area of [
|
for (area of[{
|
||||||
{ name: "région", neighbours: regions[box.regionId] },
|
name: "région",
|
||||||
{ name: "ligne", neighbours: rows[box.rowId] },
|
neighbours: regions[box.regionId]
|
||||||
{ name: "colonne", neighbours: columns[box.columnId] },
|
}, {
|
||||||
])
|
name: "ligne",
|
||||||
for (neighbour of area.neighbours)
|
neighbours: rows[box.rowId]
|
||||||
if (box != neighbour && box.value == neighbour.value) {
|
}, {
|
||||||
for (neighbour of [box, neighbour]) {
|
name: "colonne",
|
||||||
neighbour.setCustomValidity(`Il y a un autre ${box.value} dans cette ${area.name}.`)
|
neighbours: columns[box.columnId]
|
||||||
|
}, ])
|
||||||
|
for (neighbour of area.neighbours)
|
||||||
|
if (box != neighbour && box.value == neighbour.value) {
|
||||||
|
for (neighbour of[box, neighbour]) {
|
||||||
|
neighbour.setCustomValidity(`Il y a un autre ${box.value} dans cette ${area.name}.`)
|
||||||
|
neighbour.classList.add("is-invalid")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (box.form.checkValidity()) { // Correct grid
|
if (box.form.checkValidity()) { // Correct grid
|
||||||
if (boxes.filter(box => box.value == "").length == 0) {
|
if (boxes.filter(box => box.value == "").length == 0) {
|
||||||
setTimeout(() => alert(`Bravo ! Vous avez résolu la grille.`), 500)
|
|
||||||
saveButton.disabled = true
|
saveButton.disabled = true
|
||||||
|
setTimeout(() => {
|
||||||
|
if (confirm(`Bravo ! Vous avez résolu la grille. En voulez-vous une autre ?`))
|
||||||
|
location = "."
|
||||||
|
}, 400)
|
||||||
}
|
}
|
||||||
} else { // Errors on grid
|
} else { // Errors on grid
|
||||||
box.form.reportValidity()
|
box.form.reportValidity()
|
||||||
@ -218,31 +235,33 @@ function highlight() {
|
|||||||
easyBoxes = []
|
easyBoxes = []
|
||||||
boxes.forEach(box => {
|
boxes.forEach(box => {
|
||||||
if (valueToInsert && box.value == valueToInsert) {
|
if (valueToInsert && box.value == valueToInsert) {
|
||||||
box.classList.add("same-value")
|
box.parentElement.classList.add("table-primary")
|
||||||
box.tabIndex = -1
|
box.tabIndex = -1
|
||||||
} else {
|
} else {
|
||||||
box.classList.remove("same-value")
|
box.parentElement.classList.remove("table-primary")
|
||||||
if (valueToInsert && highlighterCheckbox.checked && !box.candidates.has(valueToInsert)) {
|
box.tabIndex = 0
|
||||||
box.classList.add("forbidden")
|
|
||||||
box.tabIndex = -1
|
|
||||||
} else {
|
|
||||||
box.classList.remove("forbidden")
|
|
||||||
box.tabIndex = 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (valueToInsert && highlighterCheckbox.checked && !box.candidates.has(valueToInsert)) {
|
||||||
|
box.parentElement.classList.add("table-active")
|
||||||
|
box.tabIndex = -1
|
||||||
|
} else {
|
||||||
|
box.parentElement.classList.remove("table-active")
|
||||||
|
box.tabIndex = 0
|
||||||
|
}
|
||||||
|
|
||||||
if (!box.value && box.candidates.size == 1) {
|
if (!box.value && box.candidates.size == 1) {
|
||||||
hintButton.disabled = false
|
hintButton.disabled = false
|
||||||
easyBoxes.push(box)
|
easyBoxes.push(box)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
highlighterCheckbox.label.title = "Surligner les lignes, colonnes et régions contenant déjà " + (valueToInsert? "un " + valueToInsert: "le chiffre sélectionné")
|
highlighterCheckbox.label.title = "Surligner les lignes, colonnes et régions contenant déjà " + (valueToInsert ? "un " + valueToInsert : "le chiffre sélectionné")
|
||||||
}
|
}
|
||||||
|
|
||||||
function onblur() {
|
function onblur() {
|
||||||
if (this.classList.contains("pencil")) {
|
if (this.classList.contains("pencil")) {
|
||||||
this.placeholder = this.value
|
this.placeholder = this.value
|
||||||
this.value = ""
|
this.value = ""
|
||||||
//this.type = "number"
|
//this.type = "number"
|
||||||
this.classList.remove("pencil")
|
this.classList.remove("pencil")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -254,11 +273,7 @@ function insert(radio) {
|
|||||||
} else {
|
} else {
|
||||||
valueToInsert = radio.value
|
valueToInsert = radio.value
|
||||||
}
|
}
|
||||||
if (inkPenRadio.checked) customCursor = "url(img/ink-pen.svg) 2 22"
|
grid.style.cursor = valueToInsert ? "copy" : "text"
|
||||||
if (pencilRadio.checked) customCursor = "url(img/pencil.svg) 2 22"
|
|
||||||
if (eraserRadio.checked) customCursor = "url(img/eraser.svg) 2 22"
|
|
||||||
fallbackCursor = valueToInsert? "copy": "text"
|
|
||||||
grid.style.cursor = `${customCursor}, ${fallbackCursor}`
|
|
||||||
highlight()
|
highlight()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,6 +301,7 @@ function restart() {
|
|||||||
})
|
})
|
||||||
let history = []
|
let history = []
|
||||||
undoButton.disabled = true
|
undoButton.disabled = true
|
||||||
|
restartButton.disabled = true
|
||||||
boxes.forEach(searchCandidatesOf)
|
boxes.forEach(searchCandidatesOf)
|
||||||
refreshUI()
|
refreshUI()
|
||||||
}
|
}
|
||||||
@ -293,13 +309,14 @@ function restart() {
|
|||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
let saveGame = boxes.map(box => box.value || UNKNOWN).join("")
|
let saveGame = boxes.map(box => box.value || UNKNOWN).join("")
|
||||||
localStorage[location.pathname] = saveGame
|
localStorage[location.search] = saveGame
|
||||||
fixGridLink.href = saveGame
|
fixGridLink.href = "?" + saveGame
|
||||||
saveButton.disabled = true
|
saveButton.disabled = true
|
||||||
alert("Partie sauvegardée")
|
alert("Partie sauvegardée")
|
||||||
}
|
}
|
||||||
|
|
||||||
window.onbeforeunload = function(event) {
|
window.onbeforeunload = function(event) {
|
||||||
|
localStorage["highlighterCheckbox.checked"] = highlighterCheckbox.checked
|
||||||
if (!saveButton.disabled) {
|
if (!saveButton.disabled) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.returnValue = "La partie n'est pas sauvegardée. Quitter quand même ?"
|
event.returnValue = "La partie n'est pas sauvegardée. Quitter quand même ?"
|
||||||
@ -312,10 +329,6 @@ function showHint() {
|
|||||||
let box = easyBoxes.pop()
|
let box = easyBoxes.pop()
|
||||||
box.placeholder = "💡"
|
box.placeholder = "💡"
|
||||||
box.focus()
|
box.focus()
|
||||||
/*value = Array.from(box.candidates)[0]
|
|
||||||
radio = document.getElementById("insertRadio" + value)
|
|
||||||
radio.checked = true
|
|
||||||
insert(radio)*/
|
|
||||||
return box
|
return box
|
||||||
}
|
}
|
||||||
hintButton.disabled = true
|
hintButton.disabled = true
|
||||||
@ -329,12 +342,18 @@ function oncontextmenu(event) {
|
|||||||
Array.from(box.candidates).sort().forEach(candidate => {
|
Array.from(box.candidates).sort().forEach(candidate => {
|
||||||
li = document.createElement("li")
|
li = document.createElement("li")
|
||||||
li.innerText = candidate
|
li.innerText = candidate
|
||||||
li.onclick = function (event) {
|
li.classList = "list-group-item list-group-item-action"
|
||||||
|
li.onclick = function(e) {
|
||||||
contextMenu.style.display = "none"
|
contextMenu.style.display = "none"
|
||||||
valueToInsert = event.target.innerText
|
valueToInsert = e.target.innerText
|
||||||
|
grid.style.cursor = "copy"
|
||||||
document.getElementById("insertRadio" + valueToInsert).checked = true
|
document.getElementById("insertRadio" + valueToInsert).checked = true
|
||||||
box.onclick()
|
box.onclick()
|
||||||
}
|
}
|
||||||
|
li.oncontextmenu = function(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
li.onclick(e)
|
||||||
|
}
|
||||||
contextMenu.appendChild(li)
|
contextMenu.appendChild(li)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@ -347,7 +366,7 @@ function oncontextmenu(event) {
|
|||||||
contextMenu.style.top = `${event.pageY}px`
|
contextMenu.style.top = `${event.pageY}px`
|
||||||
contextMenu.style.display = "block"
|
contextMenu.style.display = "block"
|
||||||
|
|
||||||
document.onclick = function (event) {
|
document.onclick = function(event) {
|
||||||
contextMenu.style.display = "none"
|
contextMenu.style.display = "none"
|
||||||
document.onclick = null
|
document.onclick = null
|
||||||
}
|
}
|
||||||
@ -359,4 +378,4 @@ document.onkeydown = function(event) {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
contextMenu.style.display = "none"
|
contextMenu.style.display = "none"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,29 +0,0 @@
|
|||||||
location /sudoku/ {
|
|
||||||
alias /var/www/sudoku/;
|
|
||||||
|
|
||||||
if ($scheme = http) {
|
|
||||||
rewrite ^ https://$server_name$request_uri? permanent;
|
|
||||||
}
|
|
||||||
|
|
||||||
try_files $uri $uri/;
|
|
||||||
|
|
||||||
location ~ [^/]\.php(/|$) {
|
|
||||||
try_files $uri =404;
|
|
||||||
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
|
|
||||||
fastcgi_pass unix:/var/run/php/php7.3-fpm-sudoku.sock;
|
|
||||||
fastcgi_index index.php;
|
|
||||||
include fastcgi_params;
|
|
||||||
fastcgi_param REMOTE_USER $remote_user;
|
|
||||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
|
||||||
fastcgi_param SCRIPT_FILENAME $request_filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
error_page 404 /sudoku/404.php;
|
|
||||||
location /sudoku/404.php {
|
|
||||||
internal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ "^/sudoku/([1-9.]{81})$" {
|
|
||||||
rewrite "^/sudoku/([1-9.]{81})\??(.*)?(#.*)?$" /sudoku/sudoku.php?grid=$1&$2$3 last;
|
|
||||||
}
|
|
325
style.css
@ -1,325 +0,0 @@
|
|||||||
:root {
|
|
||||||
--body-bc: #e8ffff;
|
|
||||||
--body-fc: black;
|
|
||||||
--shadow: lightgray;
|
|
||||||
|
|
||||||
--border-color: #555b6e;
|
|
||||||
|
|
||||||
--box-bc: #F7FFF7;
|
|
||||||
--box-fc: black;
|
|
||||||
--forbidden-box-bc: #FFEE99;
|
|
||||||
--same-value-box-bc: #ffbc25;
|
|
||||||
--placeholder-fc: var(--grid-color);
|
|
||||||
|
|
||||||
--clue-bc: #60D2CB;
|
|
||||||
--forbidden-clue-bc: var(--clue-bc);
|
|
||||||
--same-value-clue-bc: #24737F;
|
|
||||||
--clue-fc: var(--box-bc);
|
|
||||||
--forbidden-clue-fc: var(--forbidden-box-bc);
|
|
||||||
--same-value-clue-fc: var(--forbidden-box-bc);
|
|
||||||
|
|
||||||
--tool-fc: var(--clue-fc);
|
|
||||||
--tool-bc: var(--clue-bc);
|
|
||||||
--selected-tool-bc: var(--same-value-clue-bc);
|
|
||||||
--selected-tool-fc: var(--same-value-clue-fc);
|
|
||||||
--tool-hover-bc: #80DBD5;
|
|
||||||
--selected-tool-hover-bc: #319EAF;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
:root {
|
|
||||||
--body-bc: #1c1c1e;
|
|
||||||
--body-fc: #fefefe;
|
|
||||||
--shadow: darkgray;
|
|
||||||
|
|
||||||
--border-color: #292929;
|
|
||||||
|
|
||||||
--box-bc: #0C151D;
|
|
||||||
--box-fc: #bfcbce;
|
|
||||||
--forbidden-box-bc: #004E52;
|
|
||||||
--same-value-box-bc: #09BC8A;
|
|
||||||
--placeholder-fc: var(--grid-color);
|
|
||||||
|
|
||||||
--clue-bc: #508991;
|
|
||||||
--forbidden-clue-bc: var(--clue-bc);
|
|
||||||
--same-value-clue-bc: #75DDDD;
|
|
||||||
--clue-fc: var(--box-bc);
|
|
||||||
--forbidden-clue-fc: var(--forbidden-box-bc);
|
|
||||||
--same-value-clue-fc: var(--forbidden-box-bc);
|
|
||||||
|
|
||||||
--tool-fc: var(--clue-fc);
|
|
||||||
--tool-bc: var(--clue-bc);
|
|
||||||
--selected-tool-bc: var(--same-value-clue-bc);
|
|
||||||
--selected-tool-fc: var(--same-value-clue-fc);
|
|
||||||
--tool-hover-bc: #61A0A8;
|
|
||||||
--selected-tool-hover-bc: #9DE7E7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: sans-serif;
|
|
||||||
width: min-content;
|
|
||||||
margin: auto;
|
|
||||||
background: var(--body-bc);
|
|
||||||
color: var(--body-fc)
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
text-align: center;
|
|
||||||
font-weight: 50;
|
|
||||||
margin: 2rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 1rem;
|
|
||||||
text-indent: 1rem;
|
|
||||||
text-shadow: .1rem .1rem var(--shadow);
|
|
||||||
}
|
|
||||||
|
|
||||||
section, div, footer {
|
|
||||||
align-items: center;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
text-align: center;
|
|
||||||
margin: 1rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
div {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
row-gap: 0.5rem;
|
|
||||||
column-gap: 0.3rem;
|
|
||||||
margin: 0.5rem auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.grid {
|
|
||||||
border-spacing: 0;
|
|
||||||
margin: auto;
|
|
||||||
cursor: url(img/ink-pen.svg) 2 22, text;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid td, tr {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid tr:nth-child(3n+1) td {
|
|
||||||
border-top: 2px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid tr:nth-child(3n+2) td {
|
|
||||||
border-top: 1px solid var(--border-color);
|
|
||||||
border-bottom: 1px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid tr:nth-child(3n) td {
|
|
||||||
border-bottom: 2px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid td:nth-child(3n+1) {
|
|
||||||
border-left: 2px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid td:nth-child(3n+2) {
|
|
||||||
border-left: 1px solid var(--border-color);
|
|
||||||
border-right: 1px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid td:nth-child(3n+3) {
|
|
||||||
border-right: 2px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.grid input {
|
|
||||||
width: 2.5rem;
|
|
||||||
height: 2.5rem;
|
|
||||||
border: 0;
|
|
||||||
border-radius: 0;
|
|
||||||
padding: 0;
|
|
||||||
text-align: center;
|
|
||||||
transition: background 0.5s;
|
|
||||||
-moz-appearance: textfield;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="number"]::-webkit-outer-spin-button,
|
|
||||||
input::-webkit-inner-spin-button {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="number"]::-webkit-calendar-picker-indicator {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input:enabled {
|
|
||||||
font-size: 1.4rem;
|
|
||||||
color: var(--box-fc);
|
|
||||||
background: var(--box-bc);
|
|
||||||
cursor: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input.pencil,
|
|
||||||
.grid input::placeholder {
|
|
||||||
color: #666 !important;
|
|
||||||
font-size: 0.9rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input:disabled {
|
|
||||||
font-size: 1.3rem;
|
|
||||||
font-weight: bold;
|
|
||||||
color: var(--clue-fc);
|
|
||||||
background: var(--clue-bc);
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input.forbidden:enabled {
|
|
||||||
background: var(--forbidden-box-bc);
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input.same-value:enabled {
|
|
||||||
background: var(--same-value-box-bc);
|
|
||||||
cursor: not-allowed !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input.forbidden:disabled {
|
|
||||||
color: var(--forbidden-clue-fc);
|
|
||||||
background: var(--forbidden-clue-bc) !important;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input.same-value:disabled {
|
|
||||||
color: var(--same-value-clue-fc) !important;
|
|
||||||
background: var(--same-value-clue-bc) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input.one-candidate {
|
|
||||||
cursor: help !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools div {
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button,
|
|
||||||
.tools input + label {
|
|
||||||
color: var(--tool-fc);
|
|
||||||
background: var(--clue-bc);
|
|
||||||
border: 1px outset var(--clue-bc);
|
|
||||||
font-size: 1.3rem;
|
|
||||||
font-weight: bold;
|
|
||||||
min-width:20px;
|
|
||||||
padding: 6px;
|
|
||||||
margin: .1rem;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools img {
|
|
||||||
display: block;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools input {
|
|
||||||
position: fixed;
|
|
||||||
opacity: 0;
|
|
||||||
width: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button:enabled:checked,
|
|
||||||
.tools input:enabled:checked + label {
|
|
||||||
border-style: inset;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button.same-value:enabled,
|
|
||||||
.tools input:enabled:checked + label {
|
|
||||||
background: var(--selected-tool-bc);
|
|
||||||
color: var(--selected-tool-fc);
|
|
||||||
border-color: var(--selected-tool-bc);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button:enabled:hover,
|
|
||||||
.tools input:enabled:hover + label {
|
|
||||||
background: var(--tool-hover-bc);
|
|
||||||
border-color: var(--tool-hover-bc);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button:enabled:checked:hover,
|
|
||||||
.tools input:enabled:checked:hover + label {
|
|
||||||
background: var(--selected-tool-hover-bc);
|
|
||||||
border-color: var(--selected-tool-hover-bc);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button:disabled,
|
|
||||||
.tools input:disabled + label {
|
|
||||||
color: #ccc;
|
|
||||||
background: darkgrey;
|
|
||||||
border-style: outset;
|
|
||||||
border-color: darkgrey;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button:disabled * {
|
|
||||||
filter: grayscale(100%);
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button.warning:hover {
|
|
||||||
background: #ff5050;
|
|
||||||
border-color: #ff5050;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.context-menu {
|
|
||||||
display: none;
|
|
||||||
z-index: 1000;
|
|
||||||
position: absolute;
|
|
||||||
overflow: hidden;
|
|
||||||
border: 1px solid #CCC;
|
|
||||||
white-space: nowrap;
|
|
||||||
font-family: sans-serif;
|
|
||||||
background: #EEE;
|
|
||||||
color: #333;
|
|
||||||
border-top-right-radius: 3px;
|
|
||||||
border-bottom-left-radius: 3px;
|
|
||||||
border-bottom-right-radius: 3px;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu li {
|
|
||||||
padding: 6px 10px;
|
|
||||||
cursor: default;
|
|
||||||
list-style-type: none;
|
|
||||||
transition: all .3s ease;
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu li:hover {
|
|
||||||
background-color: #DEF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu li.error {
|
|
||||||
color: #888
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu li.error:hover {
|
|
||||||
background-color: #EEE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: var(--forbidden-clue-bc);
|
|
||||||
}
|
|
||||||
|
|
||||||
a:visited {
|
|
||||||
color: var(--same-value-clue-bc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.credits {
|
|
||||||
font-size: 0.8rem;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
308
style.css.bak
@ -1,308 +0,0 @@
|
|||||||
body {
|
|
||||||
font-family: sans-serif;
|
|
||||||
width: min-content;
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
text-align: center;
|
|
||||||
margin: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
section, div, footer {
|
|
||||||
align-items: center;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
text-align: center;
|
|
||||||
margin: 0.8rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
div {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
row-gap: 0.5rem;
|
|
||||||
column-gap: 0.3rem;
|
|
||||||
margin: 0.5rem auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.grid {
|
|
||||||
border-spacing: 0;
|
|
||||||
border: 1px solid black;
|
|
||||||
border-radius: 6px;
|
|
||||||
margin: auto;
|
|
||||||
cursor: url(img/ink-pen.svg) 2 22, text;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid td, tr {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid tr:first-child td:first-child {
|
|
||||||
border-top-left-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid tr:first-child td:first-child input {
|
|
||||||
border-top-left-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid tr:first-child td:last-child {
|
|
||||||
border-top-right-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid tr:first-child td:last-child input {
|
|
||||||
border-top-right-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid tr:last-child td:first-child {
|
|
||||||
border-bottom-left-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid tr:last-child td:first-child > input {
|
|
||||||
border-bottom-left-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid tr:last-child td:last-child {
|
|
||||||
border-bottom-right-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid tr:last-child td:last-child input {
|
|
||||||
border-bottom-right-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid tr:nth-child(3n+1) td {
|
|
||||||
border-top: 1px solid black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid tr:nth-child(3n+2) td {
|
|
||||||
border-top: 1px solid grey;
|
|
||||||
border-bottom: 1px solid grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid tr:nth-child(3n) td {
|
|
||||||
border-bottom: 1px solid black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid td:nth-child(3n+1) {
|
|
||||||
border-left: 1px solid black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid td:nth-child(3n+2) {
|
|
||||||
border-left: 1px solid grey;
|
|
||||||
border-right: 1px solid grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid td:nth-child(3n+3) {
|
|
||||||
border-right: 1px solid black;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.grid input {
|
|
||||||
width: 2.5rem;
|
|
||||||
height: 2.5rem;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
border: 0;
|
|
||||||
border-radius: 0;
|
|
||||||
padding: 0;
|
|
||||||
text-align: center;
|
|
||||||
transition: background 0.5s;
|
|
||||||
-moz-appearance: textfield;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="number"]::-webkit-outer-spin-button,
|
|
||||||
input::-webkit-inner-spin-button {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="number"]::-webkit-calendar-picker-indicator {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input:enabled {
|
|
||||||
background: white;
|
|
||||||
color: darkblue;
|
|
||||||
cursor: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input.pencil,
|
|
||||||
.grid input::placeholder {
|
|
||||||
color: #666 !important;
|
|
||||||
font-size: 0.9rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input:disabled {
|
|
||||||
color: white !important;
|
|
||||||
background: #6666ff !important;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input.forbidden:enabled {
|
|
||||||
background: #f9f99f;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input.same-value:enabled {
|
|
||||||
background: #ffff33;
|
|
||||||
cursor: not-allowed !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input.forbidden:disabled {
|
|
||||||
color: #f9f99f;
|
|
||||||
background: #6666ff;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input.same-value:disabled,
|
|
||||||
.tools button.same-value:enabled,
|
|
||||||
.tools input:enabled:checked + label {
|
|
||||||
color: #f9f99f !important;
|
|
||||||
background: #00b359 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input.one-candidate {
|
|
||||||
cursor: help !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.tools button,
|
|
||||||
.tools input + label {
|
|
||||||
color: white;
|
|
||||||
text-shadow: -1px -1px #5b6c9e;
|
|
||||||
background: #8ca6f2;
|
|
||||||
border: 2px outset #8ca6f2;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 1.3rem;
|
|
||||||
min-width:20px;
|
|
||||||
padding: 4px 5px 5px 5px;
|
|
||||||
margin: 0px 1px 1px 1px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools img {
|
|
||||||
display: block;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools input {
|
|
||||||
position: fixed;
|
|
||||||
opacity: 0;
|
|
||||||
width: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button:enabled:hover,
|
|
||||||
.tools button:enabled:focus,
|
|
||||||
.tools input:enabled:hover + label,
|
|
||||||
.tools input:enabled:focus + label {
|
|
||||||
border-width: 1px;
|
|
||||||
border-style: outset;
|
|
||||||
padding: 5px 5px 5px 6px;
|
|
||||||
margin: 1px 1px 1px 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools input:enabled:checked:hover + label,
|
|
||||||
.tools input:enabled:checked:focus + label {
|
|
||||||
border-width: 3px;
|
|
||||||
border-style: inset;
|
|
||||||
padding: 4px 2px 2px 5px;
|
|
||||||
margin: 1px 1px 1px 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools input:enabled:checked + label {
|
|
||||||
text-shadow: -1px -1px #005f2f;
|
|
||||||
border: 2px inset #00b359;
|
|
||||||
background: #00b359;
|
|
||||||
padding: 4px 4px 4px 5px;
|
|
||||||
margin: 1px 1px 0px 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button:enabled:active,
|
|
||||||
.tools input:enabled:active + label {
|
|
||||||
border-width: 4px !important;
|
|
||||||
border-style: inset !important;
|
|
||||||
padding: 4px 0px 0px 5px !important;
|
|
||||||
margin: 0px 1px 0px 2px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button:disabled,
|
|
||||||
.tools input:disabled + label {
|
|
||||||
text-shadow: -1px -1px #555;
|
|
||||||
color: #ccc;
|
|
||||||
background: darkgrey;
|
|
||||||
border: 1px outset darkgrey;
|
|
||||||
padding: 5px 6px 6px 6px;
|
|
||||||
margin: 0px 1px 1px 1px;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button:disabled * {
|
|
||||||
filter: grayscale(100%);
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button.warning:hover {
|
|
||||||
background: #ff5050;
|
|
||||||
border-color: #ff5050;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.context-menu {
|
|
||||||
display: none;
|
|
||||||
z-index: 1000;
|
|
||||||
position: absolute;
|
|
||||||
overflow: hidden;
|
|
||||||
border: 1px solid #CCC;
|
|
||||||
white-space: nowrap;
|
|
||||||
font-family: sans-serif;
|
|
||||||
background: #EEE;
|
|
||||||
color: #333;
|
|
||||||
border-top-right-radius: 3px;
|
|
||||||
border-bottom-left-radius: 3px;
|
|
||||||
border-bottom-right-radius: 3px;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu li {
|
|
||||||
padding: 6px 10px;
|
|
||||||
cursor: default;
|
|
||||||
list-style-type: none;
|
|
||||||
transition: all .3s ease;
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu li:hover {
|
|
||||||
background-color: #DEF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu li.error {
|
|
||||||
color: #888
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu li.error:hover {
|
|
||||||
background-color: #EEE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.credits {
|
|
||||||
font-size: 0.8rem;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
body {
|
|
||||||
color: #eee;
|
|
||||||
background: #121212;
|
|
||||||
}
|
|
||||||
|
|
||||||
body a {
|
|
||||||
color: #809fff;
|
|
||||||
}
|
|
||||||
}
|
|
328
style.css.bak2
@ -1,328 +0,0 @@
|
|||||||
:root {
|
|
||||||
--body-bc: #e8ffff;
|
|
||||||
--body-fc: black;
|
|
||||||
--shadow: lightgray;
|
|
||||||
|
|
||||||
--border-color: #555b6e;
|
|
||||||
|
|
||||||
--box-bc: #F7FFF7;
|
|
||||||
--box-fc: black;
|
|
||||||
--forbidden-box-bc: #FFEE99;
|
|
||||||
--same-value-box-bc: #ffbc25;
|
|
||||||
--placeholder-fc: var(--grid-color);
|
|
||||||
|
|
||||||
--clue-bc: #60D2CB;
|
|
||||||
--forbidden-clue-bc: var(--clue-bc);
|
|
||||||
--same-value-clue-bc: #24737F;
|
|
||||||
--clue-fc: var(--box-bc);
|
|
||||||
--forbidden-clue-fc: var(--forbidden-box-bc);
|
|
||||||
--same-value-clue-fc: var(--forbidden-box-bc);
|
|
||||||
|
|
||||||
--tool-fc: var(--clue-fc);
|
|
||||||
--tool-bc: var(--clue-bc);
|
|
||||||
--selected-tool-bc: var(--same-value-clue-bc);
|
|
||||||
--selected-tool-fc: var(--same-value-clue-fc);
|
|
||||||
--tool-hover-bc: #80DBD5;
|
|
||||||
--selected-tool-hover-bc: #319EAF;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
:root {
|
|
||||||
--body-bc: #1c1c1e;
|
|
||||||
--body-fc: #fefefe;
|
|
||||||
--shadow: darkgray;
|
|
||||||
|
|
||||||
--border-color: #292929;
|
|
||||||
|
|
||||||
--box-bc: #0C151D;
|
|
||||||
--box-fc: #bfcbce;
|
|
||||||
--forbidden-box-bc: #004E52;
|
|
||||||
--same-value-box-bc: #09BC8A;
|
|
||||||
--placeholder-fc: var(--grid-color);
|
|
||||||
|
|
||||||
--clue-bc: #508991;
|
|
||||||
--forbidden-clue-bc: var(--clue-bc);
|
|
||||||
--same-value-clue-bc: #75DDDD;
|
|
||||||
--clue-fc: var(--box-bc);
|
|
||||||
--forbidden-clue-fc: var(--forbidden-box-bc);
|
|
||||||
--same-value-clue-fc: var(--forbidden-box-bc);
|
|
||||||
|
|
||||||
--tool-fc: var(--clue-fc);
|
|
||||||
--tool-bc: var(--clue-bc);
|
|
||||||
--selected-tool-bc: var(--same-value-clue-bc);
|
|
||||||
--selected-tool-fc: var(--same-value-clue-fc);
|
|
||||||
--tool-hover-bc: #61A0A8;
|
|
||||||
--selected-tool-hover-bc: #9DE7E7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: sans-serif;
|
|
||||||
width: min-content;
|
|
||||||
margin: auto;
|
|
||||||
background: var(--body-bc);
|
|
||||||
color: var(--body-fc)
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
text-align: center;
|
|
||||||
font-weight: 50;
|
|
||||||
margin: 2rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 1rem;
|
|
||||||
text-indent: 1rem;
|
|
||||||
text-shadow: .1rem .1rem var(--shadow);
|
|
||||||
}
|
|
||||||
|
|
||||||
section,
|
|
||||||
div,
|
|
||||||
footer {
|
|
||||||
align-items: center;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
text-align: center;
|
|
||||||
margin: 1rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
div {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
row-gap: 0.5rem;
|
|
||||||
column-gap: 0.3rem;
|
|
||||||
margin: 0.5rem auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.grid {
|
|
||||||
border-spacing: 0;
|
|
||||||
margin: auto;
|
|
||||||
cursor: url(img/ink-pen.svg) 2 22, text;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid td,
|
|
||||||
tr {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid tr:nth-child(3n+1) td {
|
|
||||||
border-top: 2px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid tr:nth-child(3n+2) td {
|
|
||||||
border-top: 1px solid var(--border-color);
|
|
||||||
border-bottom: 1px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid tr:nth-child(3n) td {
|
|
||||||
border-bottom: 2px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid td:nth-child(3n+1) {
|
|
||||||
border-left: 2px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid td:nth-child(3n+2) {
|
|
||||||
border-left: 1px solid var(--border-color);
|
|
||||||
border-right: 1px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid td:nth-child(3n+3) {
|
|
||||||
border-right: 2px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.grid input {
|
|
||||||
width: 2.5rem;
|
|
||||||
height: 2.5rem;
|
|
||||||
border: 0;
|
|
||||||
border-radius: 0;
|
|
||||||
padding: 0;
|
|
||||||
text-align: center;
|
|
||||||
transition: background 0.5s;
|
|
||||||
-moz-appearance: textfield;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="number"]::-webkit-outer-spin-button,
|
|
||||||
input::-webkit-inner-spin-button {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="number"]::-webkit-calendar-picker-indicator {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input:enabled {
|
|
||||||
font-size: 1.4rem;
|
|
||||||
color: var(--box-fc);
|
|
||||||
background: var(--box-bc);
|
|
||||||
cursor: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input.pencil,
|
|
||||||
.grid input::placeholder {
|
|
||||||
color: #666 !important;
|
|
||||||
font-size: 0.9rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input:disabled {
|
|
||||||
font-size: 1.3rem;
|
|
||||||
font-weight: bold;
|
|
||||||
color: var(--clue-fc);
|
|
||||||
background: var(--clue-bc);
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input.forbidden:enabled {
|
|
||||||
background: var(--forbidden-box-bc);
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input.same-value:enabled {
|
|
||||||
background: var(--same-value-box-bc);
|
|
||||||
cursor: not-allowed !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input.forbidden:disabled {
|
|
||||||
color: var(--forbidden-clue-fc);
|
|
||||||
background: var(--forbidden-clue-bc) !important;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input.same-value:disabled {
|
|
||||||
color: var(--same-value-clue-fc) !important;
|
|
||||||
background: var(--same-value-clue-bc) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid input.one-candidate {
|
|
||||||
cursor: help !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools div {
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button,
|
|
||||||
.tools input+label {
|
|
||||||
color: var(--tool-fc);
|
|
||||||
background: var(--clue-bc);
|
|
||||||
border: 1px outset var(--clue-bc);
|
|
||||||
font-size: 1.3rem;
|
|
||||||
font-weight: bold;
|
|
||||||
min-width: 20px;
|
|
||||||
padding: 6px;
|
|
||||||
margin: .1rem;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools img {
|
|
||||||
display: block;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools input {
|
|
||||||
position: fixed;
|
|
||||||
opacity: 0;
|
|
||||||
width: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button:enabled:checked,
|
|
||||||
.tools input:enabled:checked+label {
|
|
||||||
border-style: inset;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button.same-value:enabled,
|
|
||||||
.tools input:enabled:checked+label {
|
|
||||||
background: var(--selected-tool-bc);
|
|
||||||
color: var(--selected-tool-fc);
|
|
||||||
border-color: var(--selected-tool-bc);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button:enabled:hover,
|
|
||||||
.tools input:enabled:hover+label {
|
|
||||||
background: var(--tool-hover-bc);
|
|
||||||
border-color: var(--tool-hover-bc);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button:enabled:checked:hover,
|
|
||||||
.tools input:enabled:checked:hover+label {
|
|
||||||
background: var(--selected-tool-hover-bc);
|
|
||||||
border-color: var(--selected-tool-hover-bc);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button:disabled,
|
|
||||||
.tools input:disabled+label {
|
|
||||||
color: #ccc;
|
|
||||||
background: darkgrey;
|
|
||||||
border-style: outset;
|
|
||||||
border-color: darkgrey;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button:disabled * {
|
|
||||||
filter: grayscale(100%);
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools button.warning:hover {
|
|
||||||
background: #ff5050;
|
|
||||||
border-color: #ff5050;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.context-menu {
|
|
||||||
display: none;
|
|
||||||
z-index: 1000;
|
|
||||||
position: absolute;
|
|
||||||
overflow: hidden;
|
|
||||||
border: 1px solid #CCC;
|
|
||||||
white-space: nowrap;
|
|
||||||
font-family: sans-serif;
|
|
||||||
background: #EEE;
|
|
||||||
color: #333;
|
|
||||||
border-top-right-radius: 3px;
|
|
||||||
border-bottom-left-radius: 3px;
|
|
||||||
border-bottom-right-radius: 3px;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu li {
|
|
||||||
padding: 6px 10px;
|
|
||||||
cursor: default;
|
|
||||||
list-style-type: none;
|
|
||||||
transition: all .3s ease;
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu li:hover {
|
|
||||||
background-color: #DEF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu li.error {
|
|
||||||
color: #888
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu li.error:hover {
|
|
||||||
background-color: #EEE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: var(--forbidden-clue-bc);
|
|
||||||
}
|
|
||||||
|
|
||||||
a:visited {
|
|
||||||
color: var(--same-value-clue-bc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.credits {
|
|
||||||
font-size: 0.8rem;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
163
sudoku.php
@ -1,133 +1,102 @@
|
|||||||
<?php
|
|
||||||
require("classes.php");
|
|
||||||
session_start();
|
|
||||||
$currentGrid = strip_tags($_GET['grid']);
|
|
||||||
$_SESSION["currentGrid"] = $currentGrid;
|
|
||||||
|
|
||||||
if (!in_array($currentGrid, $validGrids)) {
|
|
||||||
$grid = new Grid();
|
|
||||||
$grid->import($currentGrid);
|
|
||||||
if ($grid->containsDuplicates()) {
|
|
||||||
$warning = "Cette grille contient des doublons.";
|
|
||||||
} else {
|
|
||||||
switch($grid->countSolutions(2)) {
|
|
||||||
case 0:
|
|
||||||
$warning = "Cette grille n'a pas de solution.";
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
$validGrids[] = $currentGrid;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$warning = "Cette grille a plusieurs solutions.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang='fr' prefix="og: https://ogp.me/ns#">
|
<html lang='fr' prefix="og: https://ogp.me/ns#">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset='utf-8' />
|
<?php require_once("head.php") ?>
|
||||||
<meta name='viewport' content='width=device-width' />
|
|
||||||
<title>Sudoku</title>
|
|
||||||
<link rel='stylesheet' type='text/css' href='style.css' />
|
|
||||||
<script src='sudoku.js'></script>
|
|
||||||
<link rel="apple-touch-icon" href="thumbnail.php?size=57" sizes="57x57">
|
|
||||||
<link rel="apple-touch-icon" href="thumbnail.php?size=114" sizes="114x114">
|
|
||||||
<link rel="apple-touch-icon" href="thumbnail.php?size=72" sizes="72x72">
|
|
||||||
<link rel="apple-touch-icon" href="thumbnail.php?size=144" sizes="144x144">
|
|
||||||
<link rel="apple-touch-icon" href="thumbnail.php?size=60" sizes="60x60">
|
|
||||||
<link rel="apple-touch-icon" href="thumbnail.php?size=120" sizes="120x120">
|
|
||||||
<link rel="apple-touch-icon" href="thumbnail.php?size=76" sizes="76x76">
|
|
||||||
<link rel="apple-touch-icon" href="thumbnail.php?size=152" sizes="152x152">
|
|
||||||
<link rel="icon" type="image/png" href="thumbnail.php?size=196" sizes="196x196">
|
|
||||||
<link rel="icon" type="image/png" href="thumbnail.php?size=160" sizes="160x160">
|
|
||||||
<link rel="icon" type="image/png" href="thumbnail.php?size=96" sizes="96x96">
|
|
||||||
<link rel="icon" type="image/png" href="thumbnail.php?size=16" sizes="16x16">
|
|
||||||
<link rel="icon" type="image/png" href="thumbnail.php?size=32" sizes="32x32">
|
|
||||||
<link rel="manifest" href="manifest.php">
|
|
||||||
<meta property="og:title" content="Sudoku"/>
|
|
||||||
<meta property="og:type" content="website"/>
|
|
||||||
<meta property="og:url" content="<?=$_SERVER["REQUEST_SCHEME"]."://".$_SERVER["HTTP_HOST"].$_SERVER["DOCUMENT_URI"]?>"/>
|
|
||||||
<meta property="og:image" content="<?=$_SERVER["REQUEST_SCHEME"]."://".$_SERVER["HTTP_HOST"].dirname($_SERVER["DOCUMENT_URI"])?>/thumbnail.php?size=200"/>
|
|
||||||
<meta property="og:image:width" content="200"/>
|
|
||||||
<meta property="og:image:height" content="200"/>
|
|
||||||
<meta property="og:description" content="Remplissez la grille de sorte que chaque ligne, colonne et région (carré de 3×3 cases) contienne tous les chiffres de 1 à 9."/>
|
|
||||||
<meta property="og:locale" content="fr_FR"/>
|
|
||||||
<meta property="og:site_name" content="<?=$_SERVER["HTTP_HOST"]?>"/>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
|
||||||
|
<body class="text-center">
|
||||||
<header>
|
<header>
|
||||||
<h1>Sudoku</h1>
|
<h1 class="display-4 mb-3">Sudoku</h1>
|
||||||
</header>
|
</header>
|
||||||
<section class="tools">
|
<div class='d-flex justify-content-between mb-2'>
|
||||||
<div>
|
<div class='radioGroup btn-group'>
|
||||||
<input id='highlighterCheckbox' type="checkbox" onclick='highlight()'/><label for='highlighterCheckbox' title='Surligner les lignes, colonnes et régions contenant déjà le chiffre sélectionné'><img src='img/highlighter.svg' alt='Surligneur'></label>
|
<input type='radio' id='inkPenRadio' class='btn-check' name='tool' checked />
|
||||||
<input type='radio' id='inkPenRadio' name='tool' onclick='grid.style.cursor = "url(img/ink-pen.svg) 2 22, auto"' checked/><label for='inkPenRadio' title='Écrire un chiffre'><img src='img/ink-pen.svg' alt='Stylo indélébile'/></label>
|
<label for='inkPenRadio' class='btn btn-primary' title='Écrire un chiffre'>
|
||||||
<input type='radio' id='pencilRadio' name='tool' onclick='grid.style.cursor = "url(img/pencil.svg) 2 22, auto"'/><label for='pencilRadio' title='Prendre des notes'><img src='img/pencil.svg' alt='Crayon'/></label>
|
<i class="bi bi-pen-fill"></i>
|
||||||
<input type='radio' id='eraserRadio' name='tool' onclick='grid.style.cursor = "url(img/eraser.svg) 2 22, auto"'/><label for='eraserRadio' title='Effacer une case'><img src='img/eraser.svg' alt='Gomme'/></label>
|
</label>
|
||||||
<button type='button' class='warning' onclick='restart()' title='Recommencer'><img src='img/restart.svg' alt='Recommencer'/></button>
|
<input type='radio' id='pencilRadio' class='btn-check' name='tool' />
|
||||||
<button id='undoButton' type='button' onclick='undo()' disabled title='Annuler' accesskey='z'><img src='img/undo.svg' alt='Annuler'/></button>
|
<label for='pencilRadio' class='btn btn-primary' title='Prendre des notes'>
|
||||||
<button id="hintButton" type="button" onclick="showHint()" title="Afficher un indice" accesskey="h" disabled=""><img src='img/light-bulb.svg' alt='Ampoule'/></button>
|
<i class="bi bi-pencil-fill"></i>
|
||||||
<button id='saveButton' type='button' onclick='save()' disabled title='Sauvegarder' accesskey='s'><img src='img/save.svg' alt='Disquette'/></button>
|
</label>
|
||||||
|
<input type='radio' id='eraserRadio' class='btn-check' name='tool' '/>
|
||||||
|
<label for='eraserRadio' class='btn btn-primary' title='Effacer une case'>
|
||||||
|
<i class="bi bi-eraser-fill"></i>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
<input id='highlighterCheckbox' type="checkbox" class='btn-check' onclick='highlight()' />
|
||||||
<form id='sudokuForm'>
|
<label for='highlighterCheckbox' class='btn btn-primary' title='Surligner les lignes, colonnes et régions contenant déjà le chiffre sélectionné'>
|
||||||
<table id='grid' class='grid'>
|
<i class="bi bi-magic"></i>
|
||||||
|
</label>
|
||||||
|
<button id="hintButton" type="button" class='btn btn-primary' onclick="showHint()" title="Montrer une case avec une seule possibilité" accesskey="H" disabled="">
|
||||||
|
<i class="bi bi-lightbulb-fill"></i>
|
||||||
|
</button>
|
||||||
|
<button id='restartButton' type='button' class='btn btn-primary' onclick='restart()' disabled title='Recommencer'>
|
||||||
|
<i class="bi bi-x-circle-fill"></i></i>
|
||||||
|
</button>
|
||||||
|
<button id='undoButton' type='button' class='btn btn-primary' onclick='undo()' disabled title='Annuler' accesskey='Z'>
|
||||||
|
<i class="bi bi-arrow-counterclockwise"></i>
|
||||||
|
</button>
|
||||||
|
<button id='saveButton' type='button' class='btn btn-primary' onclick='save()' disabled title='Sauvegarder' accesskey='S'>
|
||||||
|
<i class="bi bi-save-fill"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form id='sudokuForm' class='needs-validation' novalidate>
|
||||||
|
<table id='grid' class='table mb-2'>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php
|
<?php
|
||||||
for ($row = 0; $row < 9; $row++) {
|
for ($row = 0; $row < 81; $row += 9) {
|
||||||
?>
|
?>
|
||||||
<tr>
|
<tr class="input-group d-inline-block">
|
||||||
<?php
|
<?php
|
||||||
for ($column = 0; $column < 9; $column++) {
|
for ($column = 0; $column < 9; $column++) {
|
||||||
$value = $currentGrid[9*$row+$column];
|
$value = $currentGrid[$row+$column];
|
||||||
if ($value == UNKNOWN) {
|
if ($value == UNKNOWN) {
|
||||||
?>
|
?>
|
||||||
<td><input type='number' min='1' max='9' step='1' value='' title='Valeurs possibles [Clic-droit]'/></td>
|
<td><input type='number' min='1' max='9' step='1' value='' class='form-control'
|
||||||
<?php
|
title='Valeurs possibles [Clic-droit]' /></td>
|
||||||
|
<?php
|
||||||
} else {
|
} else {
|
||||||
?>
|
?>
|
||||||
<td><input type='number' min='1' max='9' step='1' value='<?=$value?>' disabled/></td>
|
<td><input type='number' min='1' max='9' step='1' value='<?=$value?>' class='form-control' disabled /></td>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
</tr>
|
</tr>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</form>
|
</form>
|
||||||
<section class='tools'>
|
<div class='d-flex mb-2'>
|
||||||
<div id='insertRadioGroup' class='insertRadioGroup'>
|
<div id='insertRadioGroup' class='radioGroup btn-group flex-fill'>
|
||||||
<?php
|
<?php
|
||||||
for($value=1; $value<=9; $value++) {
|
for($value=1; $value<=9; $value++) {
|
||||||
echo " <input type='radio' id='insertRadio$value' value='$value' name='insertRadioGroup' onclick='insert(this)' accesskey='$value'/><label for='insertRadio$value' title='Insérer un $value'>$value</label>\n";
|
echo " <input type='radio'class='btn-check' id='insertRadio$value' value='$value' name='insertRadioGroup' onclick='insert(this)' accesskey='$value'/><label for='insertRadio$value' class='btn btn-primary' title='Insérer un $value'>$value</label>\n";
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</div>
|
||||||
<section>
|
<div class='mb-3'>
|
||||||
<?php
|
<?php
|
||||||
if (isset($warning))
|
if (isset($warning))
|
||||||
echo(" <strong>⚠️ $warning ⚠️</strong><br/>\n");
|
echo(" <strong>⚠️ $warning ⚠️</strong><br/>\n");
|
||||||
else
|
else
|
||||||
echo(" Remplissez la grille de sorte que chaque ligne, colonne et région (carré de 3×3 cases) contienne tous les chiffres de 1 à 9.\n")
|
echo(" Remplissez la grille de sorte que chaque ligne, colonne et région (carré de 3×3 cases) contienne tous les chiffres de 1 à 9.\n")
|
||||||
?>
|
?>
|
||||||
</section>
|
</div>
|
||||||
<ul id='contextMenu' class='context-menu'></ul>
|
<ul id='contextMenu' class='context-menu modal-content shadow list-group w-auto position-absolute'></ul>
|
||||||
<footer>
|
<footer>
|
||||||
<div id='links'>
|
<div id='links' class='list-group mb-2'>
|
||||||
<a href=''>Lien vers cette grille</a><br/>
|
<a href='.' class='list-group-item list-group-item-action'>Nouvelle grille</a>
|
||||||
<a href='.'>Nouvelle grille</a><br/>
|
<a href='' class='list-group-item list-group-item-action'>Lien vers cette grille</a>
|
||||||
<a href='.................................................................................'>Grille vierge</a><br/>
|
<a href='?.................................................................................' class='list-group-item list-group-item-action'>Grille
|
||||||
<a href='' id='fixGridLink'>Figer cette grille</a>
|
vierge</a>
|
||||||
|
<a href='' id='fixGridLink' class='list-group-item list-group-item-action'>Figer la grille enregistrée</a>
|
||||||
</div>
|
|
||||||
<div class='credits'>
|
|
||||||
Icônes par <a href='https://www.flaticon.com/authors/freepik' title='Freepik' target="_blank">Freepik</a> chez <a href='https://www.flaticon.com/' title='Flaticon' target="_blank">www.flaticon.com</a>
|
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
|
||||||
|
</html>
|
@ -14,10 +14,11 @@
|
|||||||
$thumbnail = imagecreate($size, $size);
|
$thumbnail = imagecreate($size, $size);
|
||||||
$transparent = imagecolorallocate($thumbnail, 1, 1, 1);
|
$transparent = imagecolorallocate($thumbnail, 1, 1, 1);
|
||||||
imagecolortransparent($thumbnail, $transparent);
|
imagecolortransparent($thumbnail, $transparent);
|
||||||
$black = imagecolorallocate($thumbnail, 85, 91, 110);
|
$darkerBorder = imagecolorallocate($thumbnail, 150, 155, 160);
|
||||||
$grey = imagecolorallocate($thumbnail, 85, 91, 110);
|
$lighterBorder = imagecolorallocate($thumbnail, 210, 225, 230);
|
||||||
$blue = imagecolorallocate($thumbnail, 96, 210, 203);
|
$emptyBoxBC = imagecolorallocate($thumbnail, 255, 255, 255);
|
||||||
$white = imagecolorallocate($thumbnail, 247, 255, 247);
|
$clueBC = imagecolorallocate($thumbnail, 255, 255, 255);
|
||||||
|
$clueFC = imagecolorallocate($thumbnail, 150, 155, 160);
|
||||||
|
|
||||||
if ($size <= 36) {
|
if ($size <= 36) {
|
||||||
$boxSize = floor(($size-4) / 9);
|
$boxSize = floor(($size-4) / 9);
|
||||||
@ -27,8 +28,8 @@
|
|||||||
$lineStart = $start + 1;
|
$lineStart = $start + 1;
|
||||||
$lineEnd = $end - 2;
|
$lineEnd = $end - 2;
|
||||||
for ($i = $start; $i < $end; $i += 3*$boxSize + 1) {
|
for ($i = $start; $i < $end; $i += 3*$boxSize + 1) {
|
||||||
ImageLine($thumbnail, $lineStart, $i, $lineEnd, $i, $black);
|
ImageLine($thumbnail, $lineStart, $i, $lineEnd, $i, $darkerBorder);
|
||||||
ImageLine($thumbnail, $i, $lineStart, $i, $lineEnd, $black);
|
ImageLine($thumbnail, $i, $lineStart, $i, $lineEnd, $darkerBorder);
|
||||||
}
|
}
|
||||||
$x = $start;
|
$x = $start;
|
||||||
$y = $start;
|
$y = $start;
|
||||||
@ -37,9 +38,9 @@
|
|||||||
if ($i % 3 == 0) $x++;
|
if ($i % 3 == 0) $x++;
|
||||||
if ($i % 27 == 0) $y++;
|
if ($i % 27 == 0) $y++;
|
||||||
if ($value == UNKNOWN) {
|
if ($value == UNKNOWN) {
|
||||||
$bgColor = $white;
|
$bgColor = $emptyBoxBC;
|
||||||
} else {
|
} else {
|
||||||
$bgColor = $blue;
|
$bgColor = $clueFC;
|
||||||
}
|
}
|
||||||
imagefilledrectangle($thumbnail, $x, $y, $x+$boxSizeMinusOne, $y+$boxSizeMinusOne, $bgColor);
|
imagefilledrectangle($thumbnail, $x, $y, $x+$boxSizeMinusOne, $y+$boxSizeMinusOne, $bgColor);
|
||||||
$x += $boxSize;
|
$x += $boxSize;
|
||||||
@ -56,21 +57,21 @@
|
|||||||
$lineStart = $start + 1;
|
$lineStart = $start + 1;
|
||||||
$lineEnd = $end - 2;
|
$lineEnd = $end - 2;
|
||||||
for ($i = $start + $boxSize; $i < $end - $boxSize; $i += $boxSize) {
|
for ($i = $start + $boxSize; $i < $end - $boxSize; $i += $boxSize) {
|
||||||
ImageLine($thumbnail, $lineStart, $i, $lineEnd, $i, $grey);
|
ImageLine($thumbnail, $lineStart, $i, $lineEnd, $i, $lighterBorder);
|
||||||
ImageLine($thumbnail, $i, $lineStart, $i, $lineEnd, $grey);
|
ImageLine($thumbnail, $i, $lineStart, $i, $lineEnd, $lighterBorder);
|
||||||
}
|
}
|
||||||
for ($i = $start; $i < $end; $i += 3*$boxSize) {
|
for ($i = $start; $i < $end; $i += 3*$boxSize) {
|
||||||
ImageLine($thumbnail, $lineStart, $i, $lineEnd, $i, $black);
|
ImageLine($thumbnail, $lineStart, $i, $lineEnd, $i, $darkerBorder);
|
||||||
ImageLine($thumbnail, $i, $lineStart, $i, $lineEnd, $black);
|
ImageLine($thumbnail, $i, $lineStart, $i, $lineEnd, $darkerBorder);
|
||||||
}
|
}
|
||||||
$x = $start + 1;
|
$x = $start + 1;
|
||||||
$y = $start + 1;
|
$y = $start + 1;
|
||||||
$boxSizeMinusTwo = $boxSize - 2;
|
$boxSizeMinusTwo = $boxSize - 2;
|
||||||
foreach(str_split($currentGrid) as $i => $value) {
|
foreach(str_split($currentGrid) as $i => $value) {
|
||||||
if ($value == UNKNOWN) {
|
if ($value == UNKNOWN) {
|
||||||
$bgColor = $white;
|
$bgColor = $emptyBoxBC;
|
||||||
} else {
|
} else {
|
||||||
$bgColor = $blue;
|
$bgColor = $clueFC;
|
||||||
}
|
}
|
||||||
imagefilledrectangle($thumbnail, $x, $y, $x+$boxSizeMinusTwo, $y+$boxSizeMinusTwo, $bgColor);
|
imagefilledrectangle($thumbnail, $x, $y, $x+$boxSizeMinusTwo, $y+$boxSizeMinusTwo, $bgColor);
|
||||||
$x += $boxSize;
|
$x += $boxSize;
|
||||||
@ -89,26 +90,26 @@
|
|||||||
$fontSize = floor($boxSize/2) - 4;
|
$fontSize = floor($boxSize/2) - 4;
|
||||||
$fdx = floor(($boxSize - imagefontwidth($fontSize)) / 2);
|
$fdx = floor(($boxSize - imagefontwidth($fontSize)) / 2);
|
||||||
$fdy = ceil(($boxSize - imagefontheight($fontSize)) / 2) - 1;
|
$fdy = ceil(($boxSize - imagefontheight($fontSize)) / 2) - 1;
|
||||||
$fontColor = $white;
|
$fontColor = $emptyBoxBC;
|
||||||
for ($i = $start + $boxSize; $i < $end - $boxSize; $i += $boxSize) {
|
for ($i = $start + $boxSize; $i < $end - $boxSize; $i += $boxSize) {
|
||||||
ImageLine($thumbnail, $lineStart, $i, $lineEnd, $i, $grey);
|
ImageLine($thumbnail, $lineStart, $i, $lineEnd, $i, $lighterBorder);
|
||||||
ImageLine($thumbnail, $i, $lineStart, $i, $lineEnd, $grey);
|
ImageLine($thumbnail, $i, $lineStart, $i, $lineEnd, $lighterBorder);
|
||||||
}
|
}
|
||||||
for ($i = $start; $i < $end; $i += 3*$boxSize) {
|
for ($i = $start; $i < $end; $i += 3*$boxSize) {
|
||||||
ImageLine($thumbnail, $lineStart, $i, $lineEnd, $i, $black);
|
ImageLine($thumbnail, $lineStart, $i, $lineEnd, $i, $darkerBorder);
|
||||||
ImageLine($thumbnail, $i, $lineStart, $i, $lineEnd, $black);
|
ImageLine($thumbnail, $i, $lineStart, $i, $lineEnd, $darkerBorder);
|
||||||
}
|
}
|
||||||
$x = $start + 1;
|
$x = $start + 1;
|
||||||
$y = $start + 1;
|
$y = $start + 1;
|
||||||
$boxSizeMinusTwo = $boxSize - 2;
|
$boxSizeMinusTwo = $boxSize - 2;
|
||||||
foreach(str_split($currentGrid) as $i => $value) {
|
foreach(str_split($currentGrid) as $i => $value) {
|
||||||
if ($value == UNKNOWN) {
|
if ($value == UNKNOWN) {
|
||||||
$bgColor = $white;
|
$bgColor = $emptyBoxBC;
|
||||||
} else {
|
} else {
|
||||||
$bgColor = $blue;
|
$bgColor = $clueBC;
|
||||||
}
|
}
|
||||||
imagefilledrectangle($thumbnail, $x, $y, $x+$boxSizeMinusTwo, $y+$boxSizeMinusTwo, $bgColor);
|
imagefilledrectangle($thumbnail, $x, $y, $x+$boxSizeMinusTwo, $y+$boxSizeMinusTwo, $bgColor);
|
||||||
if ($value != UNKNOWN) imagestring($thumbnail, $fontSize, $x + $fdx, $y + $fdy, $value, $fontColor);
|
if ($value != UNKNOWN) imagestring($thumbnail, $fontSize, $x + $fdx, $y + $fdy, $value, $clueFC);
|
||||||
$x += $boxSize;
|
$x += $boxSize;
|
||||||
if ($i % 9 == 8) {
|
if ($i % 9 == 8) {
|
||||||
$y += $boxSize;
|
$y += $boxSize;
|
||||||
|