-
Hervé Allesant a rédigéHervé Allesant a rédigé
index.html 11,34 Kio
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Sudoku Thématique</title>
<style>
.container {
max-width: 600px;
margin: 20px auto;
text-align: center;
}
.setup, .message, .controls {
margin: 20px;
}
.board {
display: inline-grid;
gap: 2px;
background: #ccc;
padding: 2px;
margin: 20px 0;
}
.cell {
width: 60px;
height: 60px;
background: white;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 24px;
}
.cell.selected {
background: #e3f2fd;
}
.cell.conflict {
background: #ffebee;
}
.cell.fixed {
background: #f5f5f5;
cursor: not-allowed;
}
.icons {
display: flex;
gap: 10px;
justify-content: center;
margin: 20px;
}
.icon-choice {
padding: 10px;
cursor: pointer;
border: 1px solid #ccc;
border-radius: 4px;
}
.icon-choice:hover {
background: #e3f2fd;
}
button {
padding: 10px 20px;
margin: 5px;
cursor: pointer;
}
.message {
font-size: 24px;
color: #4CAF50;
display: none;
}
select {
padding: 8px;
margin: 5px;
font-size: 16px;
}
</style>
</head>
<body>
<div class="container">
<div class="setup" id="setup">
<h2>Choisissez la taille</h2>
<button onclick="initGame(3)">3x3</button>
<button onclick="initGame(9)">9x9</button>
</div>
<div class="controls" id="controls" style="display: none;">
<select id="themeSelect" onchange="changeTheme()">
<option value="jardin">Jardin</option>
<option value="fruits">Fruits</option>
<option value="emotions">Émotions</option>
<option value="meteo">Météo</option>
</select>
<button onclick="newGame()">Nouvelle partie</button>
</div>
<div id="gameBoard"></div>
<div id="message" class="message">Félicitations ! Vous avez résolu le puzzle !</div>
</div>
<script>
const themes = {
jardin: ['🌸', '🌿', '🍀', '🌺', '🌻', '🌹', '🌷', '🌼', '🍁'],
fruits: ['🍎', '🍌', '🍇', '🍊', '🍓', '🍐', '🍑', '🍒', '🥝'],
emotions: ['😀', '😍', '😎', '😊', '🤔', '😮', '😴', '🤓', '😇'],
meteo: ['☀️', '🌧️', '⛈️', '🌈', '❄️', '🌤️', '🌙', '⭐', '☁️']
};
let size, board, selectedCell, currentTheme, fixedCells;
function changeTheme() {
currentTheme = document.getElementById('themeSelect').value;
updateBoard();
updateIconChoices();
}
function updateIconChoices() {
const iconContainer = document.querySelector('.icons');
iconContainer.innerHTML = '';
for(let i = 0; i < size; i++) {
const iconChoice = document.createElement('div');
iconChoice.className = 'icon-choice';
iconChoice.textContent = themes[currentTheme][i];
iconChoice.onclick = () => placeIcon(i);
iconContainer.appendChild(iconChoice);
}
}
function newGame() {
document.getElementById('setup').style.display = 'block';
document.getElementById('controls').style.display = 'none';
document.getElementById('gameBoard').innerHTML = '';
document.getElementById('message').style.display = 'none';
}
function generateSolution(size) {
const solution = Array(size).fill().map(() => Array(size).fill(null));
function isValid(num, row, col) {
for(let i = 0; i < size; i++) {
if(solution[row][i] === num || solution[i] && solution[i][col] === num) return false;
}
if (size === 9) {
const blockRow = Math.floor(row / 3) * 3;
const blockCol = Math.floor(col / 3) * 3;
for(let i = 0; i < 3; i++) {
for(let j = 0; j < 3; j++) {
if(solution[blockRow + i] &&
solution[blockRow + i][blockCol + j] === num) return false;
}
}
}
return true;
}
function solve(row = 0, col = 0) {
if(col === size) {
row++;
col = 0;
}
if(row === size) return true;
const nums = Array.from({length: size}, (_, i) => i);
for(let i = nums.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[nums[i], nums[j]] = [nums[j], nums[i]];
}
for(const num of nums) {
if(isValid(num, row, col)) {
solution[row][col] = num;
if(solve(row, col + 1)) return true;
solution[row][col] = null;
}
}
return false;
}
solve();
return solution;
}
function initGame(boardSize) {
size = boardSize;
const solution = generateSolution(size);
board = Array(size).fill().map(() => Array(size).fill(null));
fixedCells = new Set();
currentTheme = document.getElementById('themeSelect')?.value || 'jardin';
selectedCell = null;
document.getElementById('setup').style.display = 'none';
document.getElementById('controls').style.display = 'block';
const cellsToFill = size === 3 ? 4 : 20;
for(let i = 0; i < cellsToFill; i++) {
const row = Math.floor(Math.random() * size);
const col = Math.floor(Math.random() * size);
if(board[row][col] === null) {
board[row][col] = solution[row][col];
fixedCells.add(`${row}-${col}`);
}
}
createBoard();
}
function createBoard() {
const gameBoard = document.getElementById('gameBoard');
gameBoard.innerHTML = '';
document.getElementById('message').style.display = 'none';
const boardElement = document.createElement('div');
boardElement.className = 'board';
boardElement.style.gridTemplateColumns = `repeat(${size}, 1fr)`;
for(let i = 0; i < size; i++) {
for(let j = 0; j < size; j++) {
const cell = document.createElement('div');
cell.className = 'cell';
if(fixedCells.has(`${i}-${j}`)) {
cell.classList.add('fixed');
} else {
cell.onclick = () => selectCell(i, j);
}
if(board[i][j] !== null) {
cell.textContent = themes[currentTheme][board[i][j]];
}
boardElement.appendChild(cell);
}
}
gameBoard.appendChild(boardElement);
const icons = document.createElement('div');
icons.className = 'icons';
for(let i = 0; i < size; i++) {
const iconChoice = document.createElement('div');
iconChoice.className = 'icon-choice';
iconChoice.textContent = themes[currentTheme][i];
iconChoice.onclick = () => placeIcon(i);
icons.appendChild(iconChoice);
}
gameBoard.appendChild(icons);
}
function selectCell(row, col) {
if(fixedCells.has(`${row}-${col}`)) return;
const cells = document.querySelectorAll('.cell');
cells.forEach(cell => cell.classList.remove('selected'));
cells[row * size + col].classList.add('selected');
selectedCell = { row, col };
}
function placeIcon(iconIndex) {
if(!selectedCell || fixedCells.has(`${selectedCell.row}-${selectedCell.col}`)) return;
const { row, col } = selectedCell;
board[row][col] = iconIndex;
updateBoard();
checkConflicts();
checkWin();
}
function checkConflicts() {
const cells = document.querySelectorAll('.cell');
cells.forEach(cell => cell.classList.remove('conflict'));
for(let row = 0; row < size; row++) {
for(let col = 0; col < size; col++) {
if(board[row][col] === null) continue;
for(let i = 0; i < size; i++) {
if(i !== col && board[row][i] === board[row][col]) {
cells[row * size + col].classList.add('conflict');
cells[row * size + i].classList.add('conflict');
}
if(i !== row && board[i][col] === board[row][col]) {
cells[row * size + col].classList.add('conflict');
cells[i * size + col].classList.add('conflict');
}
}
if(size === 9) {
const blockRow = Math.floor(row / 3) * 3;
const blockCol = Math.floor(col / 3) * 3;
for(let i = 0; i < 3; i++) {
for(let j = 0; j < 3; j++) {
if((blockRow + i !== row || blockCol + j !== col) &&
board[blockRow + i][blockCol + j] === board[row][col]) {
cells[row * size + col].classList.add('conflict');
cells[(blockRow + i) * size + blockCol + j].classList.add('conflict');
}
}
}
}
}
}
}
function checkWin() {
const isFull = board.every(row => row.every(cell => cell !== null));
if(!isFull) return;
const hasConflicts = document.querySelectorAll('.conflict').length > 0;
if(!hasConflicts) {
document.getElementById('message').style.display = 'block';
}
}
function updateBoard() {
const cells = document.querySelectorAll('.cell');
for(let row = 0; row < size; row++) {
for(let col = 0; col < size; col++) {
const value = board[row][col];
cells[row * size + col].textContent =
value !== null ? themes[currentTheme][value] : '';
}
}
}
</script>
</body>
</html>