Sortez les noms par gendre

Sortez les noms par genre * { margin: 0; padding: 0; box-sizing: border-box; } html, body { overflow-x: hidden; overscroll-behavior: none; position: fixed; width: 100%; height: 100%; } body { font-family: ‘Segoe UI’, Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 20px; display: flex; flex-direction: column; align-items: center; user-select: none; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; overflow-y: auto; } h1 { color: white; margin-bottom: 30px; text-align: center; font-size: 2.5em; text-shadow: 2px 2px 4px rgba(0,0,0,0.3); } .game-container { display: flex; flex-direction: column; gap: 30px; max-width: 1400px; width: 100%; align-items: center; position: relative; flex-shrink: 0; } .containers-row { display: flex; gap: 30px; width: 100%; align-items: flex-start; position: relative; flex-shrink: 0; } .drop-zone { flex: 1; height: 700px; min-height: 700px; max-height: 700px; background: rgba(255, 255, 255, 0.95); border-radius: 15px; padding: 20px; box-shadow: 0 8px 32px rgba(0,0,0,0.1); position: relative; touch-action: none; flex-shrink: 0; } .drop-zone h2 { text-align: center; margin-bottom: 20px; padding: 15px; border-radius: 10px; font-size: 1.8em; position: relative; z-index: 1; } .drop-zone h2 { text-align: center; margin-bottom: 20px; padding: 15px; border-radius: 10px; font-size: 1.8em; } #masculin h2 { background: linear-gradient(135deg, #667eea 0%, #4a5fc7 100%); color: white; } #feminin h2 { background: linear-gradient(135deg, #f093fb 0%, #d946a8 100%); color: white; } .drop-zone.drag-over { background: rgba(255, 255, 255, 1); border: 3px dashed #667eea; } .middle-zone { width: 100%; display: flex; flex-direction: row; align-items: center; justify-content: center; gap: 20px; flex-shrink: 0; height: auto; } .current-card-container { background: rgba(255, 255, 255, 0.95); border-radius: 15px; padding: 30px; box-shadow: 0 8px 32px rgba(0,0,0,0.2); min-height: 120px; min-width: 200px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 20px; flex-shrink: 0; } .noun-card { background: white; padding: 15px 25px; border-radius: 12px; font-size: 1.3em; font-weight: bold; cursor: move; box-shadow: 0 4px 15px rgba(0,0,0,0.15); user-select: none; border: 3px solid #e0e0e0; display: inline-block; width: auto; touch-action: none; will-change: auto; backface-visibility: hidden; -webkit-backface-visibility: hidden; } .noun-card.dragging { opacity: 0.6; cursor: grabbing; } .noun-card.correct { background: linear-gradient(135deg, #4ade80 0%, #22c55e 100%); color: white; border-color: #16a34a; } .noun-card.incorrect { background: linear-gradient(135deg, #f87171 0%, #ef4444 100%); color: white; border-color: #dc2626; } .dropped-cards { position: absolute; top: 90px; left: 10px; right: 10px; bottom: 10px; pointer-events: none; z-index: 10; } .dropped-card { position: absolute; background: white; padding: 15px 25px; border-radius: 12px; font-size: 1.3em; font-weight: bold; box-shadow: 0 4px 15px rgba(0,0,0,0.15); border: 3px solid #e0e0e0; display: inline-block; width: auto; cursor: default; pointer-events: auto; white-space: nowrap; z-index: 100; } .dropped-card:hover { z-index: 10000; } .dropped-card.correct { background: linear-gradient(135deg, #4ade80 0%, #22c55e 100%); color: white; border-color: #16a34a; } .dropped-card.incorrect { background: linear-gradient(135deg, #f87171 0%, #ef4444 100%); color: white; border-color: #dc2626; position: relative; } .dropped-card .tooltip { visibility: hidden; background-color: #1f2937; color: white; text-align: center; padding: 10px 15px; border-radius: 8px; position: absolute; z-index: 10001; bottom: 125%; left: 50%; transform: translateX(-50%); white-space: nowrap; font-size: 0.7em; box-shadow: 0 4px 15px rgba(0,0,0,0.3); pointer-events: none; } .dropped-card .tooltip::after { content: “”; position: absolute; top: 100%; left: 50%; margin-left: -5px; border-width: 5px; border-style: solid; border-color: #1f2937 transparent transparent transparent; } .dropped-card:hover .tooltip { visibility: visible; } .score { background: rgba(255, 255, 255, 0.95); padding: 15px 30px; border-radius: 10px; font-size: 1.2em; font-weight: bold; color: #333; box-shadow: 0 4px 15px rgba(0,0,0,0.1); } .score .correct { color: #22c55e; margin: 0 5px; } .score .total { color: #667eea; margin: 0 5px; } button { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; padding: 15px 30px; border-radius: 10px; font-size: 1.1em; font-weight: bold; cursor: pointer; box-shadow: 0 4px 15px rgba(0,0,0,0.2); transition: transform 0.2s; } button:hover { transform: translateY(-2px); } button:active { transform: translateY(0); } .completed { text-align: center; color: white; font-size: 1.5em; padding: 20px; } @media (max-width: 1024px) { .containers-row { flex-direction: column; } .middle-zone { flex-direction: column; } }

Sortez les noms par genre

Index: 1 / 50 Correct: 0

Masculin

Féminin

const nouns = [ // Masculin – 50 words { word: “arbre”, gender: “m” }, { word: “banc”, gender: “m” }, { word: “ciel”, gender: “m” }, { word: “doigt”, gender: “m” }, { word: “escalier”, gender: “m” }, { word: “feu”, gender: “m” }, { word: “genou”, gender: “m” }, { word: “hiver”, gender: “m” }, { word: “jardin”, gender: “m” }, { word: “lac”, gender: “m” }, { word: “mur”, gender: “m” }, { word: “nez”, gender: “m” }, { word: “oiseau”, gender: “m” }, { word: “pont”, gender: “m” }, { word: “rideau”, gender: “m” }, { word: “sac”, gender: “m” }, { word: “tableau”, gender: “m” }, { word: “verre”, gender: “m” }, { word: “wagon”, gender: “m” }, { word: “zoo”, gender: “m” }, { word: “avion”, gender: “m” }, { word: “ballon”, gender: “m” }, { word: “camion”, gender: “m” }, { word: “dessin”, gender: “m” }, { word: “emploi”, gender: “m” }, { word: “fruit”, gender: “m” }, { word: “gâteau”, gender: “m” }, { word: “hôtel”, gender: “m” }, { word: “journal”, gender: “m” }, { word: “lit”, gender: “m” }, { word: “métier”, gender: “m” }, { word: “neveu”, gender: “m” }, { word: “ordinateur”, gender: “m” }, { word: “pays”, gender: “m” }, { word: “quartier”, gender: “m” }, { word: “repas”, gender: “m” }, { word: “soir”, gender: “m” }, { word: “toit”, gender: “m” }, { word: “visage”, gender: “m” }, { word: “weekend”, gender: “m” }, { word: “bureau”, gender: “m” }, { word: “château”, gender: “m” }, { word: “couteau”, gender: “m” }, { word: “drapeau”, gender: “m” }, { word: “cadeau”, gender: “m” }, { word: “manteau”, gender: “m” }, { word: “chapeau”, gender: “m” }, { word: “bateau”, gender: “m” }, { word: “morceau”, gender: “m” }, { word: “réseau”, gender: “m” }, // Féminin – 50 words { word: “amitié”, gender: “f” }, { word: “banque”, gender: “f” }, { word: “chaise”, gender: “f” }, { word: “danse”, gender: “f” }, { word: “école”, gender: “f” }, { word: “fenêtre”, gender: “f” }, { word: “gare”, gender: “f” }, { word: “heure”, gender: “f” }, { word: “île”, gender: “f” }, { word: “jambe”, gender: “f” }, { word: “langue”, gender: “f” }, { word: “montagne”, gender: “f” }, { word: “nièce”, gender: “f” }, { word: “oreille”, gender: “f” }, { word: “porte”, gender: “f” }, { word: “queue”, gender: “f” }, { word: “route”, gender: “f” }, { word: “soeur”, gender: “f” }, { word: “terre”, gender: “f” }, { word: “usine”, gender: “f” }, { word: “valise”, gender: “f” }, { word: “zone”, gender: “f” }, { word: “année”, gender: “f” }, { word: “bouteille”, gender: “f” }, { word: “cuisine”, gender: “f” }, { word: “douleur”, gender: “f” }, { word: “étoile”, gender: “f” }, { word: “fleur”, gender: “f” }, { word: “guerre”, gender: “f” }, { word: “histoire”, gender: “f” }, { word: “joie”, gender: “f” }, { word: “lettre”, gender: “f” }, { word: “musique”, gender: “f” }, { word: “nature”, gender: “f” }, { word: “orange”, gender: “f” }, { word: “peur”, gender: “f” }, { word: “rivière”, gender: “f” }, { word: “semaine”, gender: “f” }, { word: “tasse”, gender: “f” }, { word: “voix”, gender: “f” }, { word: “affaire”, gender: “f” }, { word: “boulangerie”, gender: “f” }, { word: “chaleur”, gender: “f” }, { word: “différence”, gender: “f” }, { word: “entrée”, gender: “f” }, { word: “forêt”, gender: “f” }, { word: “glace”, gender: “f” }, { word: “hauteur”, gender: “f” }, { word: “idée”, gender: “f” }, { word: “jeunesse”, gender: “f” } ]; let currentNounIndex = 0; let correctCount = 0; let totalAnswered = 0; let shuffledNouns = []; let currentSet = []; let dropOffset = { x: 0, y: 0 }; const SET_SIZE = 50; // Explanations for common gender patterns const genderExplanations = { m: { ‘age’: ‘Les mots en -age sont généralement masculins (exceptions: une page, une plage, une cage, une image, une nage, une rage)’, ‘ège’: ‘Les mots en -ège sont généralement masculins’, ‘é’: ‘Les mots en -é sont souvent masculins’, ‘ment’: ‘Les mots en -ment sont généralement masculins’, ‘eau’: ‘Les mots en -eau sont généralement masculins’, ‘phone’: ‘Les mots en -phone sont généralement masculins’, ‘scope’: ‘Les mots en -scope sont généralement masculins’, ‘isme’: ‘Les mots en -isme sont généralement masculins’, ‘acle’: ‘Les mots en -acle sont masculins’, ‘cle’: ‘Les mots en -cle sont souvent masculins’, ‘ule’: ‘Les mots en -ule sont souvent masculins’ }, f: { ‘tion’: ‘Les mots en -tion sont toujours féminins’, ‘sion’: ‘Les mots en -sion sont toujours féminins’, ‘té’: ‘Les mots en -té sont généralement féminins (abstractions)’, ‘ette’: ‘Les mots en -ette sont généralement féminins’, ‘esse’: ‘Les mots en -esse sont généralement féminins’, ‘ance’: ‘Les mots en -ance sont toujours féminins’, ‘ence’: ‘Les mots en -ence sont toujours féminins’, ‘ure’: ‘Les mots en -ure sont souvent féminins’, ‘ade’: ‘Les mots en -ade sont souvent féminins’, ‘ison’: ‘Les mots en -ison sont généralement féminins’, ‘age’: ‘Exception: page, plage, cage, image, nage, rage sont féminins’, ‘eige’: ‘Les mots en -eige sont féminins (neige)’, ‘orge’: ‘Les mots en -orge sont féminins (forge, gorge)’, ‘oge’: ‘Les mots en -oge sont féminins (horloge, loge)’ } }; // Specific exceptions that need special explanations const specificExplanations = { // Masculine words ending in -eau ‘oiseau’: ‘Les mots en -eau sont masculins’, ‘tableau’: ‘Les mots en -eau sont masculins’, ‘rideau’: ‘Les mots en -eau sont masculins’, ‘gâteau’: ‘Les mots en -eau sont masculins’, ‘bureau’: ‘Les mots en -eau sont masculins’, ‘château’: ‘Les mots en -eau sont masculins’, ‘couteau’: ‘Les mots en -eau sont masculins’, ‘drapeau’: ‘Les mots en -eau sont masculins’, ‘cadeau’: ‘Les mots en -eau sont masculins’, ‘manteau’: ‘Les mots en -eau sont masculins’, ‘chapeau’: ‘Les mots en -eau sont masculins’, ‘bateau’: ‘Les mots en -eau sont masculins’, ‘morceau’: ‘Les mots en -eau sont masculins’, ‘réseau’: ‘Les mots en -eau sont masculins’, // Masculine -age ‘visage’: ‘Les mots en -age sont généralement masculins’, // Feminine exceptions ‘orange’: ‘Exception: “orange” est féminin (fruit)’, ‘voix’: ‘”Voix” est féminin (se termine par -oix)’, ‘nièce’: ‘Les noms de famille féminins en -èce sont féminins’, ‘glace’: ‘Les mots en -ace sont souvent féminins’, // Other specific words ‘hiver’: ‘”Hiver” est masculin (saison)’, ‘escalier’: ‘Les mots en -ier sont généralement masculins’, ‘quartier’: ‘Les mots en -ier sont généralement masculins’, ‘métier’: ‘Les mots en -ier sont généralement masculins’ }; function getExplanation(word, correctGender) { // Check for specific word explanations first if (specificExplanations[word]) { return specificExplanations[word]; } // Check pattern-based explanations const patterns = genderExplanations[correctGender]; for (const [ending, explanation] of Object.entries(patterns)) { if (word.endsWith(ending)) { return explanation; } } // Default explanations based on gender if (correctGender === ‘m’) { return ‘Ce mot est masculin’; } else { return ‘Ce mot est féminin’; } } function shuffleArray(array) { const newArray = […array]; for (let i = newArray.length – 1; i > 0; i–) { const j = Math.floor(Math.random() * (i + 1)); [newArray[i], newArray[j]] = [newArray[j], newArray[i]]; } return newArray; } function initGame() { // Shuffle all nouns and take first 50 shuffledNouns = shuffleArray(nouns); currentSet = shuffledNouns.slice(0, SET_SIZE); currentNounIndex = 0; correctCount = 0; totalAnswered = 0; document.getElementById(‘masculin-cards’).innerHTML = ”; document.getElementById(‘feminin-cards’).innerHTML = ”; updateScore(); showNextNoun(); } function newSet() { // Keep 25 random nouns from current set const shuffledCurrentSet = shuffleArray(currentSet); const keptNouns = shuffledCurrentSet.slice(0, SET_SIZE / 2); // Get remaining nouns (those not in current set) const remainingNouns = nouns.filter(noun => !currentSet.includes(noun)); // Shuffle remaining nouns and take 25 const shuffledRemaining = shuffleArray(remainingNouns); const newNouns = shuffledRemaining.slice(0, SET_SIZE / 2); // Combine kept and new nouns, then shuffle the combined set currentSet = shuffleArray([…keptNouns, …newNouns]); // Reset game state currentNounIndex = 0; correctCount = 0; totalAnswered = 0; document.getElementById(‘masculin-cards’).innerHTML = ”; document.getElementById(‘feminin-cards’).innerHTML = ”; updateScore(); showNextNoun(); } function showNextNoun() { if (currentNounIndex >= currentSet.length) { document.getElementById(‘current-noun’).innerHTML = ‘
Terminé! 🎉
‘; document.getElementById(‘current-noun’).draggable = false; return; } const nounCard = document.getElementById(‘current-noun’); nounCard.textContent = currentSet[currentNounIndex].word; nounCard.className = ‘noun-card’; nounCard.draggable = true; } function updateScore() { document.getElementById(‘correct’).textContent = correctCount; document.getElementById(‘total’).textContent = currentSet.length; document.getElementById(‘current-index’).textContent = currentNounIndex + 1; } function resetGame() { initGame(); } // Drag and drop functionality const currentNoun = document.getElementById(‘current-noun’); const dropZones = document.querySelectorAll(‘.drop-zone’); // Prevent default drag behavior on the entire document document.addEventListener(‘dragover’, (e) => { e.preventDefault(); e.stopPropagation(); }, false); // Only allow drops in drop zones – prevent all other drops document.addEventListener(‘drop’, (e) => { const isInDropZone = e.target.closest(‘.drop-zone’); if (!isInDropZone) { e.preventDefault(); e.stopPropagation(); return false; } }, true); // Prevent scrolling during drag let isDragging = false; currentNoun.addEventListener(‘dragstart’, (e) => { isDragging = true; document.body.style.overflow = ‘hidden’; e.dataTransfer.effectAllowed = ‘move’; e.dataTransfer.setData(‘text/html’, currentNoun.innerHTML); // Calculate offset between cursor and card center const rect = currentNoun.getBoundingClientRect(); dropOffset.x = e.clientX – rect.left; dropOffset.y = e.clientY – rect.top; // Add dragging class after a small delay to show the card setTimeout(() => { currentNoun.classList.add(‘dragging’); }, 0); }); currentNoun.addEventListener(‘dragend’, (e) => { isDragging = false; document.body.style.overflow = ‘auto’; currentNoun.classList.remove(‘dragging’); }); dropZones.forEach(zone => { zone.addEventListener(‘dragover’, (e) => { e.preventDefault(); e.dataTransfer.dropEffect = ‘move’; zone.classList.add(‘drag-over’); }); zone.addEventListener(‘dragleave’, (e) => { // Only remove drag-over if we’re actually leaving the zone if (e.target === zone) { zone.classList.remove(‘drag-over’); } }); zone.addEventListener(‘drop’, (e) => { e.preventDefault(); e.stopPropagation(); zone.classList.remove(‘drag-over’); const currentNoun = currentSet[currentNounIndex]; const droppedZone = zone.id; const isCorrect = (droppedZone === ‘masculin’ && currentNoun.gender === ‘m’) || (droppedZone === ‘feminin’ && currentNoun.gender === ‘f’); // Get the cards container const cardsContainer = document.getElementById(droppedZone + ‘-cards’); const containerRect = cardsContainer.getBoundingClientRect(); // Calculate drop position relative to container let x = e.clientX – containerRect.left – dropOffset.x; let y = e.clientY – containerRect.top – dropOffset.y; // Create new card for dropped zone const newCard = document.createElement(‘div’); newCard.className = ‘dropped-card ‘ + (isCorrect ? ‘correct’ : ‘incorrect’); newCard.textContent = currentNoun.word; newCard.style.position = ‘absolute’; newCard.style.visibility = ‘hidden’; // Add to container first so we can measure it cardsContainer.appendChild(newCard); // Force a reflow to get accurate dimensions newCard.offsetHeight; // Now get its actual size with all padding, borders, and box-shadow const cardRect = newCard.getBoundingClientRect(); const cardWidth = cardRect.width; const cardHeight = cardRect.height; // Get container available space (actual inner dimensions) const availableWidth = containerRect.width; const availableHeight = containerRect.height; // Large margin to keep cards well away from edges (accounting for shadows and borders) const margin = 25; // Ensure card stays completely within container // For X: must be at least margin from left, and at most (containerWidth – cardWidth – margin) from left const maxX = Math.max(margin, availableWidth – cardWidth – margin); const minX = margin; x = Math.max(minX, Math.min(x, maxX)); // For Y: must be at least margin from top, and at most (containerHeight – cardHeight – margin) from top const maxY = Math.max(margin, availableHeight – cardHeight – margin); const minY = margin; y = Math.max(minY, Math.min(y, maxY)); // Set final position and make visible newCard.style.left = x + ‘px’; newCard.style.top = y + ‘px’; newCard.style.visibility = ‘visible’; // Add tooltip for incorrect answers if (!isCorrect) { const tooltip = document.createElement(‘span’); tooltip.className = ‘tooltip’; tooltip.textContent = getExplanation(currentNoun.word, currentNoun.gender); newCard.appendChild(tooltip); } // Update score totalAnswered++; if (isCorrect) { correctCount++; } updateScore(); // Move to next noun currentNounIndex++; showNextNoun(); }); }); // Initialize game on load initGame();