cake / index.html
Lashtw's picture
Update index.html
f222430 verified
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>110年國中教育會考數學科非選題第2題─切蛋糕模擬器</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
/* 自定義樣式以符合原作顏色邏輯 */
.green-text { color: #10b981; font-weight: bold; }
.red-text { color: #ef4444; font-weight: bold; }
.highlighted { font-size: 1.1em; padding: 0 2px; }
/* 蛋糕格線動畫 */
.cake-cell {
transition: all 0.3s ease;
}
/* 滑桿樣式優化 */
input[type=range] {
-webkit-appearance: none;
width: 100%;
background: transparent;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
height: 20px;
width: 20px;
border-radius: 50%;
background: #4f46e5;
cursor: pointer;
margin-top: -8px;
box-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 4px;
cursor: pointer;
background: #e5e7eb;
border-radius: 2px;
}
</style>
</head>
<body class="bg-gray-50 min-h-screen font-sans text-gray-800">
<div class="max-w-4xl mx-auto p-4 sm:p-6">
<!-- 標題 -->
<header class="mb-8 text-center">
<h1 class="text-2xl sm:text-3xl font-bold text-gray-900 mb-2">110年國中教育會考數學科非選題第2題</h1>
<p class="text-lg text-indigo-600 font-medium">切蛋糕模擬器</p>
</header>
<!-- Tab 切換 -->
<div class="bg-white rounded-xl shadow-lg overflow-hidden border border-gray-100">
<div class="flex border-b border-gray-200">
<button onclick="switchTab('tab1')" id="btn-tab1" class="flex-1 py-4 text-center font-medium text-indigo-600 border-b-2 border-indigo-600 bg-indigo-50 transition-colors">
第一小題 (總和限制 4)
</button>
<button onclick="switchTab('tab2')" id="btn-tab2" class="flex-1 py-4 text-center font-medium text-gray-500 hover:text-indigo-600 transition-colors">
第二小題 (總和限制 20)
</button>
</div>
<!-- 內容區域 -->
<div class="p-6 sm:p-8">
<!-- 第一小題內容 -->
<div id="tab1" class="space-y-8 block">
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8 items-start">
<!-- 控制區 -->
<div class="space-y-6">
<div class="bg-gray-50 p-5 rounded-lg border border-gray-200">
<label class="block mb-2 font-bold text-gray-700">
橫切次數 (綠色): <span id="val-h1" class="green-text text-xl">0</span>
</label>
<input type="range" id="input-h1" min="0" max="4" value="0" step="1"
oninput="updateSim('tab1', 'h')">
</div>
<div class="bg-gray-50 p-5 rounded-lg border border-gray-200">
<label class="block mb-2 font-bold text-gray-700">
縱切次數 (紅色): <span id="val-v1" class="red-text text-xl">0</span>
</label>
<input type="range" id="input-v1" min="0" max="4" value="0" step="1"
oninput="updateSim('tab1', 'v')">
</div>
<div class="text-lg font-medium p-4 bg-indigo-50 rounded-lg text-indigo-900">
總小塊數:<span id="result-total1" class="font-bold text-2xl">1</span>
</div>
<button onclick="toggleCalc('calc1')" class="w-full py-2 px-4 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg transition shadow-md">
顯示/隱藏 計算過程
</button>
<div id="calc1" class="hidden p-4 bg-yellow-50 border border-yellow-200 rounded-lg text-sm sm:text-base font-mono leading-relaxed">
<!-- 計算過程將插入此處 -->
</div>
</div>
<!-- 蛋糕視覺區 -->
<div class="flex justify-center items-center bg-gray-100 rounded-xl p-4 min-h-[300px]">
<div id="cake1" class="relative bg-white shadow-xl border-2 border-gray-800 transition-all duration-300"
style="width: 100%; max-width: 400px; aspect-ratio: 1/1;">
</div>
</div>
</div>
</div>
<!-- 第二小題內容 -->
<div id="tab2" class="space-y-8 hidden">
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8 items-start">
<!-- 控制區 -->
<div class="space-y-6">
<div class="bg-gray-50 p-5 rounded-lg border border-gray-200">
<label class="block mb-2 font-bold text-gray-700">
橫切次數 (綠色): <span id="val-h2" class="green-text text-xl">0</span>
</label>
<input type="range" id="input-h2" min="0" max="20" value="0" step="1"
oninput="updateSim('tab2', 'h')">
</div>
<div class="bg-gray-50 p-5 rounded-lg border border-gray-200">
<label class="block mb-2 font-bold text-gray-700">
縱切次數 (紅色): <span id="val-v2" class="red-text text-xl">0</span>
</label>
<input type="range" id="input-v2" min="0" max="20" value="0" step="1"
oninput="updateSim('tab2', 'v')">
</div>
<div class="grid grid-cols-2 gap-4">
<div class="p-3 bg-gray-100 rounded-lg text-center">
<div class="text-sm text-gray-500">未焦脆小塊</div>
<div id="result-non-crispy2" class="text-xl font-bold text-gray-800">1</div>
</div>
<div class="p-3 bg-gray-600 rounded-lg text-center">
<div class="text-sm text-gray-200">焦脆小塊</div>
<div id="result-crispy2" class="text-xl font-bold text-white">0</div>
</div>
</div>
<button onclick="toggleCalc('calc2')" class="w-full py-2 px-4 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg transition shadow-md">
顯示/隱藏 計算過程
</button>
<div id="calc2" class="hidden p-4 bg-yellow-50 border border-yellow-200 rounded-lg text-sm sm:text-base font-mono leading-relaxed">
<!-- 計算過程將插入此處 -->
</div>
</div>
<!-- 蛋糕視覺區 -->
<div class="flex justify-center items-center bg-gray-100 rounded-xl p-4 min-h-[300px]">
<div id="cake2" class="relative bg-white shadow-xl border-2 border-gray-800 transition-all duration-300"
style="width: 100%; max-width: 400px; aspect-ratio: 1/1;">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// 初始化狀態
const state = {
tab1: { h: 0, v: 0, maxSum: 4, highlightCrispy: false },
tab2: { h: 0, v: 0, maxSum: 20, highlightCrispy: true }
};
// Tab 切換邏輯
function switchTab(tabId) {
document.getElementById('tab1').classList.add('hidden');
document.getElementById('tab2').classList.add('hidden');
document.getElementById(tabId).classList.remove('hidden');
// 更新按鈕樣式
const btn1 = document.getElementById('btn-tab1');
const btn2 = document.getElementById('btn-tab2');
const activeClass = "text-indigo-600 border-b-2 border-indigo-600 bg-indigo-50";
const inactiveClass = "text-gray-500 hover:text-indigo-600";
if(tabId === 'tab1') {
btn1.className = `flex-1 py-4 text-center font-medium transition-colors ${activeClass}`;
btn2.className = `flex-1 py-4 text-center font-medium transition-colors ${inactiveClass}`;
} else {
btn1.className = `flex-1 py-4 text-center font-medium transition-colors ${inactiveClass}`;
btn2.className = `flex-1 py-4 text-center font-medium transition-colors ${activeClass}`;
}
}
// 顯示/隱藏計算過程
function toggleCalc(id) {
const el = document.getElementById(id);
if (el.classList.contains('hidden')) {
el.classList.remove('hidden');
} else {
el.classList.add('hidden');
}
}
// 核心更新邏輯
function updateSim(tab, source) {
const hInput = document.getElementById(`input-h${tab === 'tab1' ? '1' : '2'}`);
const vInput = document.getElementById(`input-v${tab === 'tab1' ? '1' : '2'}`);
let h = parseInt(hInput.value);
let v = parseInt(vInput.value);
const max = state[tab].maxSum;
// 限制總和邏輯 (模仿原作的 update_sliders)
if (h + v > max) {
if (source === 'h') {
v = max - h;
vInput.value = v;
} else {
h = max - v;
hInput.value = h;
}
}
// 更新狀態
state[tab].h = h;
state[tab].v = v;
// 更新數字顯示
document.getElementById(`val-h${tab === 'tab1' ? '1' : '2'}`).innerText = h;
document.getElementById(`val-v${tab === 'tab1' ? '1' : '2'}`).innerText = v;
renderCake(tab);
updateCalculations(tab);
}
// 渲染蛋糕網格
function renderCake(tab) {
const { h, v, highlightCrispy } = state[tab];
const container = document.getElementById(`cake${tab === 'tab1' ? '1' : '2'}`);
// 設定 Grid
container.style.display = 'grid';
container.style.gridTemplateRows = `repeat(${h + 1}, 1fr)`;
container.style.gridTemplateColumns = `repeat(${v + 1}, 1fr)`;
let html = '';
// 生成格子
for (let r = 0; r <= h; r++) {
for (let c = 0; c <= v; c++) {
const isEdge = (r === 0 || r === h || c === 0 || c === v);
// 如果需要高亮焦脆部分(第二小題) 且 是邊緣
const isCrispy = highlightCrispy && isEdge;
const bgClass = isCrispy ? 'bg-gray-500' : 'bg-white';
html += `<div class="cake-cell border border-gray-800 ${bgClass}"></div>`;
}
}
container.innerHTML = html;
}
// 更新數學計算
function updateCalculations(tab) {
const { h, v } = state[tab];
const totalPieces = (h + 1) * (v + 1);
const crispyPieces = (h + 1) * 2 + (v + 1) * 2 - 4; // 扣掉重複的四個角
// 如果只有 1x1,上述公式會出錯 (1*2 + 1*2 -4 = 0),但在物理上整塊都是邊。
// 邏輯修正:如果是 0 切,只有 1 塊,它是邊。
// 實際上公式對於 h,v >= 1 是通用的。如果是 0,0, crispty 計算出來是 0,實際上應為 1。
// 但依照考題邏輯,通常討論切開後的狀況。
// 為了嚴謹,我們使用另一種算法:Total - Inner
const innerH = Math.max(0, h - 1); // 實際上中間塊對應的倍率
const innerV = Math.max(0, v - 1);
const nonCrispyCalc = innerH * innerV; // 方法2的核心
// 修正顯示邏輯:
// 若 total = 1 (h=0, v=0),nonCrispy = 0, crispy = 1
const realNonCrispy = (h < 1 || v < 1) ? 0 : nonCrispyCalc;
const realCrispy = totalPieces - realNonCrispy;
// 生成計算 HTML 字串
const calcHtml = `
<div class="mb-2">橫切次數:<span class='green-text highlighted'>${h}</span></div>
<div class="mb-4">縱切次數:<span class='red-text highlighted'>${v}</span></div>
<div class="font-bold underline mb-1 text-gray-700">方法1 (扣除法):</div>
<div class="mb-1">焦脆小塊:(<span class='green-text highlighted'>${h}</span> + 1) × 2 + (<span class='red-text highlighted'>${v}</span> + 1) × 2 - 4 = <strong>${realCrispy}</strong></div>
<div class="mb-4">未焦脆小塊:(<span class='green-text highlighted'>${h}</span> + 1) × (<span class='red-text highlighted'>${v}</span> + 1) - ${realCrispy} = <strong>${realNonCrispy}</strong></div>
<div class="font-bold underline mb-1 text-gray-700">方法2 (核心公式):</div>
<div>未焦脆小塊:(<span class='green-text highlighted'>${h}</span> - 1) × (<span class='red-text highlighted'>${v}</span> - 1) = <strong>${(h-1)*(v-1)}</strong></div>
<div class="text-xs text-gray-500 mt-1">(註:若結果為負數或零,代表沒有內部區塊)</div>
`;
// 更新 DOM
if (tab === 'tab1') {
document.getElementById('result-total1').innerText = totalPieces;
document.getElementById('calc1').innerHTML = calcHtml;
} else {
document.getElementById('result-non-crispy2').innerText = realNonCrispy;
document.getElementById('result-crispy2').innerText = realCrispy;
document.getElementById('calc2').innerHTML = calcHtml;
}
}
// 頁面載入後初始化
window.onload = function() {
updateSim('tab1', 'h');
updateSim('tab2', 'h');
};
</script>
</body>
</html>