| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8" /> |
| <title>Data Factory Intro TicTacToe</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| </head> |
| <body class="bg-gradient-to-br from-green-50 to-teal-100 flex items-center justify-center min-h-screen"> |
| <div class="max-w-5xl w-full bg-white rounded-2xl shadow-lg p-6"> |
| <h1 class="text-3xl font-extrabold mb-4 text-center text-teal-800">Data Factory Intro TicTacToe</h1> |
| <p class="text-center text-sm text-gray-600 mb-4"> |
| Source: <a href="https://learn.microsoft.com/en-us/azure/data-factory/introduction" |
| class="text-blue-600 underline" target="_blank"> |
| Azure Data Factory Introduction |
| </a> |
| </p> |
|
|
| <div id="banner" class="hidden bg-green-100 border border-green-300 text-green-800 font-bold text-center py-2 rounded mb-4"></div> |
|
|
| <div class="flex items-start justify-center space-x-4"> |
| <div id="board" class="grid grid-cols-3 gap-1 border-4 border-gray-300 rounded-lg p-2 bg-white mx-auto"></div> |
| <div id="questionPanel" class="w-1/2 bg-gray-50 rounded-lg shadow p-4"> |
| <h2 id="panelQuestion" class="text-xl font-semibold text-gray-800">Select a square to view the question</h2> |
| <ul id="panelChoices" class="mt-4 space-y-2"></ul> |
| <p id="panelHint" class="mt-3 text-sm text-gray-600 hidden"></p> |
| <button id="hintBtn" class="mt-4 px-3 py-1 bg-gray-200 text-gray-700 rounded hover:bg-gray-300">Show Hint</button> |
| </div> |
| </div> |
|
|
| <div class="flex justify-between mt-6"> |
| <p id="status" class="text-lg font-medium text-gray-800"></p> |
| <button id="restartBtn" class="px-4 py-2 bg-teal-700 text-white rounded hover:bg-teal-800">Restart</button> |
| </div> |
| </div> |
|
|
| <script> |
| const questions = [ |
| { |
| question: 'What is Azure Data Factory primarily used for?', |
| choices: [ |
| 'Writing SQL queries', |
| 'Orchestrating data movement and transformation', |
| 'Hosting Power BI dashboards', |
| 'Managing Kubernetes clusters' |
| ], |
| answer: 2, |
| hint: 'Think about data workflows in the cloud.' |
| }, |
| { |
| question: 'Which component defines the actions in a pipeline?', |
| choices: ['Integration Runtime', 'Linked Service', 'Activity', 'Dataset'], |
| answer: 3, |
| hint: 'It’s the smallest functional unit of work.' |
| }, |
| { |
| question: 'What does a dataset represent?', |
| choices: ['A processing activity', 'Data schema and location', 'User identity', 'Network resource'], |
| answer: 2, |
| hint: 'It points to or references the data you use.' |
| }, |
| { |
| question: 'What is a linked service in ADF?', |
| choices: ['Data storage itself', 'Connection information to resources', 'Transformation logic', 'Security policy'], |
| answer: 2, |
| hint: 'Think connection string to external resource.' |
| }, |
| { |
| question: 'What is the purpose of Integration Runtime?', |
| choices: ['Define datasets', 'Provide compute environment', 'Visualize pipelines', 'Monitor logs'], |
| answer: 2, |
| hint: 'It powers data movement and transformation.' |
| }, |
| { |
| question: 'Which transformation feature allows visual Spark-based logic?', |
| choices: ['Mapping Data Flows', 'Power BI', 'Azure Functions', 'Logic Apps'], |
| answer: 1, |
| hint: 'It abstracts Spark cluster complexity.' |
| }, |
| { |
| question: 'How can pipelines be automated and version-controlled?', |
| choices: ['PowerShell only', 'CI/CD with Git or Azure DevOps', 'Manual export/import', 'Direct editing in portal'], |
| answer: 2, |
| hint: 'Best for DevOps and automation.' |
| }, |
| { |
| question: 'How does ADF monitor pipeline executions?', |
| choices: ['Azure Monitor & UI', 'Export logs manually', 'Only email alerts', 'No monitoring'], |
| answer: 1, |
| hint: 'It integrates with Azure Monitor and portal UI.' |
| }, |
| { |
| question: 'ADF supports ingestion from which data sources?', |
| choices: [ |
| 'Only Azure Blob Storage', |
| 'Over 90 connectors including on-prem and cloud', |
| 'Only REST APIs', |
| 'Only SQL databases' |
| ], |
| answer: 2, |
| hint: 'It integrates with many source types.' |
| } |
| ]; |
| |
| let currentPlayer, boardState, cellQuestions, selectedCell; |
| const boardEl = document.getElementById('board'); |
| const statusEl = document.getElementById('status'); |
| const bannerEl = document.getElementById('banner'); |
| const hintBtn = document.getElementById('hintBtn'); |
| const panelQuestion = document.getElementById('panelQuestion'); |
| const panelChoices = document.getElementById('panelChoices'); |
| const panelHint = document.getElementById('panelHint'); |
| const restartBtn = document.getElementById('restartBtn'); |
| |
| function initGame() { |
| currentPlayer = 'X'; |
| boardState = Array(9).fill(''); |
| bannerEl.classList.add('hidden'); |
| statusEl.innerText = ''; |
| const shuffled = questions.sort(() => 0.5 - Math.random()); |
| cellQuestions = shuffled.slice(0, 9); |
| panelQuestion.innerText = 'Select a square to view the question'; |
| panelChoices.innerHTML = ''; |
| panelHint.classList.add('hidden'); |
| renderBoard(); |
| } |
| |
| function renderBoard() { |
| boardEl.innerHTML = ''; |
| boardState.forEach((mark, idx) => { |
| const btn = document.createElement('button'); |
| let cls = 'bg-white h-24 w-24 flex items-center justify-center text-2xl font-bold rounded-lg shadow hover:bg-gray-100'; |
| if (mark === 'X') cls += ' text-blue-600'; |
| if (mark === 'O') cls += ' text-red-600'; |
| btn.className = cls; |
| btn.innerText = mark; |
| btn.disabled = mark !== ''; |
| btn.addEventListener('click', () => openQuestion(idx)); |
| boardEl.appendChild(btn); |
| }); |
| statusEl.innerText = `Current: ${currentPlayer}`; |
| } |
| |
| function openQuestion(idx) { |
| selectedCell = idx; |
| const q = cellQuestions[idx]; |
| panelQuestion.innerText = q.question; |
| panelChoices.innerHTML = ''; |
| panelHint.classList.add('hidden'); |
| panelHint.innerText = q.hint; |
| q.choices.forEach((c, i) => { |
| const li = document.createElement('li'); |
| const btn = document.createElement('button'); |
| btn.innerText = c; |
| btn.className = 'w-full text-left px-4 py-2 bg-gray-100 rounded hover:bg-gray-200'; |
| btn.addEventListener('click', () => handleAnswer(i + 1)); |
| li.appendChild(btn); |
| panelChoices.appendChild(li); |
| }); |
| } |
| |
| function handleAnswer(choice) { |
| const q = cellQuestions[selectedCell]; |
| if (choice === q.answer) { |
| boardState[selectedCell] = currentPlayer; |
| renderBoard(); |
| if (checkWin()) return endGame(`${currentPlayer} wins!`); |
| if (boardState.every(c => c)) return endGame('Stalemate!'); |
| } else { |
| alert('Incorrect! Turn missed.'); |
| } |
| currentPlayer = currentPlayer === 'X' ? 'O' : 'X'; |
| statusEl.innerText = `Current: ${currentPlayer}`; |
| } |
| |
| function checkWin() { |
| const wins = [ |
| [0,1,2],[3,4,5],[6,7,8], |
| [0,3,6],[1,4,7],[2,5,8], |
| [0,4,8],[2,4,6] |
| ]; |
| return wins.some(combo => combo.every(i => boardState[i] === currentPlayer)); |
| } |
| |
| function endGame(msg) { |
| bannerEl.innerText = `🎉 ${msg}`; |
| bannerEl.classList.remove('hidden'); |
| document.querySelectorAll('#board button').forEach(b => b.disabled = true); |
| } |
| |
| hintBtn.addEventListener('click', () => panelHint.classList.toggle('hidden')); |
| restartBtn.addEventListener('click', initGame); |
| initGame(); |
| </script> |
| </body> |
| </html> |
|
|