🐙「三位漁夫」經典謎題的 HTML + JavaScript 實作教學

🐙 三位漁夫平分籮筐 - 運算思維遊戲

🐙 三位漁夫平分籮筐 - 運算思維遊戲

大家好,這裡介紹一個「三位漁夫」經典謎題的 HTML + JavaScript 實作, 透過簡單的前端互動,體驗如何運用「運算思維」解決「每人分得相同重量」的難題。


🐟 問題描述

甲、乙、丙三位漁夫出海捕魚,帶了 21 隻籮筐回來: 7 筐滿 (滿筐魚)、7 筐半 (半筐魚)、7 筐空 (沒有魚) 。 假設每 7 筐滿魚的重量相同,每 7 筐半魚的重量相同, 該怎麼在不重新倒魚的前提下,把這些籮筐平分成 3 份,且每人都剛好拿到魚的總量 = 3.5 筐?

也就是說,最終分配結果需同時滿足:

  • 每位漁夫有 7 隻籮筐
  • 籮筐內的魚總量 = 3.5 筐 (對照: 滿筐=1 筐, 半筐=0.5 筐, 空筐=0 筐)


🧮 解題思維

我們在程式中,先以陣列記錄 21 隻籮筐各自的型態 (滿/半/空);再透過操作,使每位漁夫領取不同數量的筐。 檢查時,只要確定「每位漁夫 7 筐」且「魚量 = 3.5 筐」,即判定成功。

以下範例提供基本的點擊互動 (或可擴充為拖拉), 讓你體驗將籮筐分給不同漁夫的過程。 最後按下「檢查」按鈕,檢測是否正確。


🔧 程式範例

<!DOCTYPE html>
<html lang="zh-Hant">
<head>
  <meta charset="UTF-8">
  <title>三位漁夫平分籮筐 - 小遊戲</title>
  <style>
    /* 略: 與上面程式碼中 CSS 類似,這裡可自行調整外觀 */
  </style>
</head>
<body>
  <h1>三位漁夫平分籮筐</h1>

  <div id="pool" class="basket-area"></div>

  <div class="fisher-container">
    <div class="fisher-column">
      <h3>漁夫 A</h3>
      <div id="aArea" class="fisher-area"></div>
    </div>
    <div class="fisher-column">
      <h3>漁夫 B</h3>
      <div id="bArea" class="fisher-area"></div>
    </div>
    <div class="fisher-column">
      <h3>漁夫 C</h3>
      <div id="cArea" class="fisher-area"></div>
    </div>
  </div>

  <div class="button-row">
    <button id="checkBtn">檢查</button>
    <button id="resetBtn">重置</button>
  </div>

  <div id="message" class="message"></div>

  <script>
  // 資料結構: 21 籮筐 (7 滿、7 半、7 空)
  let baskets = [];

  function initBaskets() {
    baskets = [];
    for(let i=0; i<7; i++){
      baskets.push({ type: 'full',  emoji: '🈵', owner: 'pool' }); 
      baskets.push({ type: 'half',  emoji: '🈶', owner: 'pool' });
      baskets.push({ type: 'empty', emoji: '🈳', owner: 'pool' });
    }
  }

  function renderAll() {
    // DOM
    const pool = document.getElementById('pool');
    const aArea = document.getElementById('aArea');
    const bArea = document.getElementById('bArea');
    const cArea = document.getElementById('cArea');

    pool.innerHTML = '';
    aArea.innerHTML = '';
    bArea.innerHTML = '';
    cArea.innerHTML = '';

    baskets.forEach((b, idx) => {
      const span = document.createElement('span');
      span.className = 'basket';
      span.textContent = b.emoji;

      // 點擊 => 輸入要把此籮筐給誰
      span.addEventListener('click', () => {
        assignBasket(idx);
      });

      if(b.owner === 'pool') {
        pool.appendChild(span);
      } else if(b.owner === 'A') {
        aArea.appendChild(span);
      } else if(b.owner === 'B') {
        bArea.appendChild(span);
      } else {
        cArea.appendChild(span);
      }
    });
  }

  // 點擊 => 使用者輸入要分給誰 (A/B/C/pool)
  function assignBasket(index) {
    const target = prompt("要分給哪位漁夫? (A/B/C), 或輸入 'pool' 放回尚未分配.\n目前持有者: " 
      + baskets[index].owner.toUpperCase());
    if(!target) return;
    const t = target.trim().toUpperCase();

    if(['A','B','C','POOL'].indexOf(t) === -1) {
      alert("請輸入 A/B/C/pool 其中之一");
      return;
    }
    // 檢查是否超過 7 筐
    if(t !== 'POOL') {
      const countTarget = baskets.filter(b => b.owner === t).length;
      // 若原本不在該區 且 目標區已滿 => 報錯
      if(countTarget >= 7 && baskets[index].owner !== t) {
        alert(t + " 已有 7 個籮筐, 無法再放!");
        return;
      }
    }

    baskets[index].owner = (t === 'POOL') ? 'pool' : t;
    renderAll();
  }

  // 按下「檢查」
  function checkResult() {
    const A = baskets.filter(b => b.owner === 'A');
    const B = baskets.filter(b => b.owner === 'B');
    const C = baskets.filter(b => b.owner === 'C');

    if(A.length !== 7 || B.length !== 7 || C.length !== 7) {
      showMessage("分配錯誤: 每位漁夫都要有 7 個籮筐!", false);
      return;
    }

    // 計算魚量
    const fishCount = arr => {
      let sum = 0;
      arr.forEach(bb => {
        if(bb.type === 'full') sum += 1;
        if(bb.type === 'half') sum += 0.5;
      });
      return sum;
    };
    const fA = fishCount(A);
    const fB = fishCount(B);
    const fC = fishCount(C);

    // 都要是 3.5
    if(Math.abs(fA - 3.5) < 0.0001 && Math.abs(fB - 3.5) < 0.0001 && Math.abs(fC - 3.5) < 0.0001) {
      showMessage("恭喜! 成功分配, 每人都拿到 3.5 筐魚!", true);
    } else {
      showMessage(
        "每人都要 3.5 筐魚才行! A="+fA+" B="+fB+" C="+fC, 
        false
      );
    }
  }

  function showMessage(msg, success) {
    const m = document.getElementById('message');
    m.textContent = msg;
    if(success) {
      m.classList.add('success');
    } else {
      m.classList.remove('success');
    }
  }

  function resetGame() {
    initBaskets();
    renderAll();
    showMessage("", false);
  }

  document.getElementById('checkBtn').addEventListener('click', checkResult);
  document.getElementById('resetBtn').addEventListener('click', resetGame);

  // 初始化
  resetGame();
  </script>
</body>
</html>

🔑 解題邏輯

  1. 先以陣列 baskets[] 建立 21 筆籮筐資料 (7x「滿」、7x「半」、7x「空」),並以 owner 屬性表示該筐的持有者 ('pool', 'A', 'B', 'C')。
  2. 透過點擊籮筐,呼叫 assignBasket(),彈出一個 prompt 讓使用者輸入目標所有者。若該漁夫已有 7 筐,則不允許再放。
  3. 按下「檢查」時,驗證每位漁夫是否拿到 7 筐,以及籮筐中魚量是否剛好是 3.5 筐(滿=1.0、半=0.5、空=0)。
  4. 若全部符合,顯示「恭喜!」,否則指出錯誤原因。

🤔 運算思維教學重點

  • 資料結構:將 21 個籮筐以物件方式紀錄 (屬性包含 typeemojiowner), 便於動態更新與查詢。
  • 條件與限制:每位漁夫不得超過 7 個籮筐;魚量總數需為 3.5 筐。 這些都需在操作 (點擊籮筐) 與驗證 (檢查) 時進行判斷。
  • 狀態更新:每次點擊籮筐,就修改 owner,再重新渲染網頁 (DOM 操作)。
  • 邏輯推理:用運算思維 (程式判斷) 取代人在紙上計算或手動分配,實現遊戲化互動。

🎉 結語

透過以上 HTML + JavaScript 教學範例,我們將「三位漁夫平分籮筐」的問題遊戲化, 不但可以更直觀地操作籮筐分配,也可透過程式的「檢查機制」輔助我們檢驗正確性。

希望這個示例能幫助你熟悉運算思維、條件判斷以及前端互動設計。 有興趣的朋友可再進一步優化介面,如改成拖曳操作或加入更多動畫與提示。
祝大家學習愉快,Happy Coding!