/Minh họa bài toán tháp Hà Nội với JQuery

Minh họa bài toán tháp Hà Nội với JQuery

Chào mừng đến với bài Minh họa bài toán tháp Hà Nội với jQuery trên trang web của chúng tôi! Trong chuyến phiêu lưu này, chúng ta sẽ cùng nhau giải trí với bài toán kinh điển – Tháp Hà Nội – một cách thú vị và vui vẻ với sự giúp đỡ của HTML, Javascriptthư viện jQuery.

Hãy sẵn sàng cho một cuộc hành trình đầy màu sắc và niềm vui, khi chúng ta sẽ tạo ra những đoạn mã tuyệt vời, vừa giải trí vừa học hỏi. Bạn sẽ không chỉ thấy được sức mạnh của jQuery, mà còn trải nghiệm được sự hứng khởi và sáng tạo từ việc giải quyết bài toán Tháp Hà Nội!

Hãy cùng nhau bắt đầu cuộc hành trình này và tận hưởng mỗi khoảnh khắc vui vẻ nào!

1. Bài Toán Tháp Hà Nội là gì?

Hãy cùng nhau quay lại thời kỳ năm 1880, khi nhà toán học người Pháp, Édouard Lucas, đặt ra một câu hỏi thú vị:

“Làm sao để di chuyển một tháp gồm các đĩa từ cột A sang cột C, với điều kiện chỉ được di chuyển một đĩa một lần và đĩa lớn không bao giờ được đặt lên trên đĩa nhỏ?”

Ban đầu, bài toán được trình bày như một trò chơi và sau đó nó được xuất bản dưới dạng một cuốn sách nhỏ vào năm 1889 và trong một tập sách được xuất bản sau cái chết của Lucas.

Kèm theo trò chơi là một cuốn sách hướng dẫn, mô tả nguồn gốc được cho là của trò chơi ở Tonkin. Theo truyền thuyết, các giáo sĩ tại một ngôi đền ở Benares đã thực hiện việc di chuyển “Tháp Thánh của Brahma”, gồm sáu mươi bốn đĩa vàng, theo cùng các quy tắc như trong trò chơi. Điều thú vị là, theo truyền thuyết, hoàn thành tháp này sẽ dẫn đến sự kết thúc của thế giới!

Nếu truyền thuyết này là sự thật và các linh mục có thể di chuyển đĩa với tốc độ một đĩa mỗi giây, thì để hoàn thành tháp sẽ mất họ khoảng 585 tỷ năm – gần 42 lần tuổi của vũ trụ hiện tại!

Có nhiều biến thể của truyền thuyết này, nhưng dù là ở đâu và bằng cách nào, bí ẩn của Tháp Hà Nội vẫn là một cuộc phiêu lưu thú vị và hấp dẫn, đầy tò mò và đầy vui vẻ!

Bài toán Tháp Hà Nội không chỉ là một thử thách toán học, mà còn là một trò chơi logic đầy thú vị! Nó giúp chúng ta rèn luyện tư duy logic, khả năng lập luận và sự kiên nhẫn.

2. Hướng giải quyết bài toán

Hãy tưởng tượng bạn đang xếp các đĩa từ lớn đến nhỏ trên một trong ba cái cột. Mục tiêu của bạn là chuyển toàn bộ đống đĩa đó từ cột bên trái sang cột bên phải, nhưng bạn chỉ được phép di chuyển một đĩa một lần và bạn không thể đặt một đĩa lớn lên trên một đĩa nhỏ hơn.

Để giải quyết bài toán này, bạn có thể làm như sau:

  • Đầu tiên, hãy xem xét trường hợp đơn giản nhất: nếu bạn chỉ có một đĩa, bạn chỉ cần di chuyển đĩa đó từ cột bên trái sang cột bên phải.
  • Nếu bạn có nhiều hơn một đĩa, hãy thực hiện các bước sau:
    • Bước đầu tiên, di chuyển n – 1 đĩa từ cột bên trái sang một cột trung gian (chúng ta sẽ gọi là “cột giữa”).
    • Tiếp theo, di chuyển đĩa lớn nhất từ cột bên trái sang cột bên phải.
    • Cuối cùng, di chuyển n – 1 đĩa từ cột giữa sang cột bên phải, sử dụng cột bên trái như một “trạm dừng”.

Bằng cách này, bạn có thể dễ dàng chuyển toàn bộ đống đĩa từ cột bên trái sang cột bên phải mà không vi phạm quy tắc nào cả. Đó là bí quyết đằng sau bài toán Tháp Hà Nội! Hãy thử và xem bạn có thể hoàn thành nó trong bao lâu!

3. Vậy độ khó của bài toán là bao nhiêu

Hãy thử tưởng tượng nhân vật Tấm của chúng ta thay vì phải nhặt một rổ thóc ra thóc, gạo ra gạomới được đi lễ hỗi mà phải sắp xếp tháp đĩa 20 tầng, thì đó chắc chắn sẽ là một nhiệm vụ đầy thách thức mà cố bé không thể tưởng tượng ra được!

Hãy cùng nhìn vào tính toán này: giả sử mỗi bước di chuyển mất 1 giây, và Tấm chỉ được phép di chuyển một đĩa mỗi giây, vậy sẽ mất bao nhiêu năm để hoàn thành nhiệm vụ này?

Đầu tiên, chúng ta cần tính toán số bước di chuyển tối thiểu cần thiết để giải quyết bài toán Tháp Hà Nội với 20 cái đĩa. Sử dụng công thức 2^n – 1, với n là số đĩa, ta có:

2^20 – 1 = 1,048,575 bước di chuyển cần thiết.

Điều này có nghĩa là cần tối thiểu 1,048,575 giây để hoàn thành bài toán.

Bây giờ, chúng ta chuyển đổi số giây này thành năm. Số giây trong một năm là 365 ngày * 24 giờ * 60 phút * 60 giây = 31,536,000 giây/năm. Vì vậy, để tính số năm cần thiết, ta sẽ chia tổng số giây cho số giây trong một năm:

1,048,575 giây ÷ 31,536,000 giây/năm ≈ 0.033 năm.

Vậy là sẽ mất khoảng 0.033 năm (hoặc khoảng 12 ngày) để Tấm hoàn thành bài toán Tháp Hà Nội với 20 cái đĩa, giả sử cô di chuyển mỗi đĩa mất 1 giây một lần.

Nếu như vậy, bé Tấm sẽ mất tới 12 ngày để hoàn thành nhiệm vụ này và ôi thôi cô bé hoàn toàn có thể quên luôn cơ hội có thể được đi dự tiệc như trong chuyện!

4. Giải quyết bài toán bằng Javascript

Hàm hanoi() trong đoạn mã Javascript dưới đây được sử dụng để giải bài toán Tháp Hà Nội với n đĩa. Dưới đây là mô tả chi tiết của cách giải quyết bài toán:

// Hàm giải bài toán Tháp Hà Nội với n đĩa
function hanoi(n, source, auxiliary, destination) {
// Nếu chỉ có một đĩa, di chuyển đĩa từ nguồn đến đích
if (n === 1) {
moveDisc(source, destination);
} else {
// Di chuyển n - 1 đĩa từ nguồn đến trung gian
hanoi(n - 1, source, destination, auxiliary);
// Di chuyển đĩa cuối cùng từ nguồn đến đích
moveDisc(source, destination);
// Di chuyển n - 1 đĩa từ trung gian đến đích
hanoi(n - 1, auxiliary, source, destination);
}
}

Tham số:

  • n: Số lượng đĩa trong bài toán.
  • source: Cột nguồn, nơi các đĩa bắt đầu.
  • auxiliary: Cột trung gian, được sử dụng để di chuyển các đĩa qua.
  • destination: Cột đích, nơi mà tất cả các đĩa cần được sắp xếp.

Ý tưởng thuật toán:

  • Nếu chỉ có một đĩa (n = 1), di chuyển đĩa đó từ cột nguồn (source) sang cột đích (destination) bằng cách gọi hàm moveDisc(source, destination). Nếu có nhiều hơn một đĩa (n > 1), thực hiện các bước sau:
    • Di chuyển (n – 1) đĩa từ cột nguồn (source) sang cột trung gian (auxiliary) bằng cách gọi đệ quy hàm hanoi(n - 1, source, destination, auxiliary). Điều này đưa đĩa lớn nhất ra khỏi cột nguồn.
    • Di chuyển đĩa còn lại từ cột nguồn (source) sang cột đích (destination) bằng cách gọi hàm moveDisc(source, destination).
    • Cuối cùng, di chuyển (n – 1) đĩa từ cột trung gian (auxiliary) sang cột đích (destination) bằng cách gọi đệ quy hàm hanoi(n - 1, auxiliary, source, destination). Điều này đảm bảo rằng tất cả các đĩa nhỏ hơn đã được chuyển vào cột đích, qua cột nguồn làm trung gian.

    5. Minh họa bài toán tháp Hà Nội bằng Jquery

    Dưới đây, chúng ta sẽ sử dụng HTML, JavaScript và jQuery để tạo ra một phiên bản minh họa sự chi chuyển của các đĩa trong bài toán Tháp Hà Nội:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Tower of Hanoi</title>
    <style>
    .tower {
    width: 150px;
    height: 200px;
    border: 1px solid black;
    display: inline-block;
    vertical-align: top;
    position: relative;
    }
    .disc {
    position: absolute;
    border: 1px solid black;
    text-align: center;
    color: white;
    }
    .disc1 {
    background-color: #3498db;
    width: 60px;
    height: 20px;
    line-height: 20px;
    }
    .disc2 {
    background-color: #2ecc71;
    width: 80px;
    height: 20px;
    line-height: 20px;
    }
    .disc3 {
    background-color: #e74c3c;
    width: 100px;
    height: 20px;
    line-height: 20px;
    }
    </style>
    </head>
    <body>

    <div class="tower" id="tower1"></div>
    <div class="tower" id="tower2"></div>
    <div class="tower" id="tower3"></div>
    <br>
    <button id="reset">Reset</button>
    <button id="solve">Solve</button>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script>
    // Khởi tạo trạng thái ban đầu với 3 đĩa ở cột 1
    var towers = {
    1: [3, 2, 1],
    2: [],
    3: []
    };

    // Hàm di chuyển đĩa từ cột nguồn đến cột đích
    function moveDisc(source, destination) {
    var disc = towers[source].pop();
    towers[destination].push(disc);
    updateTowerView();
    }

    // Hàm giải bài toán Tháp Hà Nội với n đĩa
    function hanoi(n, source, auxiliary, destination) {
    if (n === 1) {
    moveDisc(source, destination);
    } else {
    hanoi(n - 1, source, destination, auxiliary);
    moveDisc(source, destination);
    hanoi(n - 1, auxiliary, source, destination);
    }
    }

    // Hàm cập nhật hiển thị tháp và đĩa
    function updateTowerView() {
    $('.disc').remove();
    $.each(towers, function(towerIndex, discs) {
    var tower = $('#tower' + towerIndex);
    var numDiscs = discs.length;
    var towerHeight = tower.height();
    for (var i = 0; i < numDiscs; i++) {
    var discSize = discs[i];
    var discWidth = (discSize + 1) * 25; // Tính toán độ rộng của đĩa dựa trên kích thước
    var towerWidth = tower.width();
    var leftPosition = (towerWidth - discWidth) / 2; // Tính toán vị trí trái của đĩa để đặt giữa tower
    var bottomPosition = i * 24;
    disc = $('<div class="disc disc' + discSize + '">' + discSize + '</div>');
    disc.css({
    'bottom': bottomPosition + 'px',
    'left': leftPosition + 'px'
    });
    tower.append(disc);
    }
    // Add additional discs at the bottom of the tower if needed
    for (var j = numDiscs; j < 3; j++) {
    var disc = $('<div class="disc"></div>');
    var bottomPosition = j * 24;
    disc.css('bottom', bottomPosition + 'px');
    tower.append(disc);
    }
    });
    }

    // Bắt đầu giải bài toán khi trang web được tải
    $(document).ready(function() {
    $('#reset').click(function() {
    // Reset lại trạng thái ban đầu
    towers = {
    1: [3, 2, 1],
    2: [],
    3: []
    };
    updateTowerView();
    });

    $('#solve').click(function() {
    // Giải bài toán
    solveWithDelay(3, 1, 2, 3);
    });

    // Cập nhật hiển thị ban đầu
    updateTowerView();
    });

    // Hàm giải bài toán với độ trễ mỗi bước
    function solveWithDelay(n, source, auxiliary, destination) {
    var moves = [];
    generateMoves(n, source, auxiliary, destination, moves);

    // Thực hiện di chuyển từng bước mỗi giây
    moveOneByOne(moves);
    }

    // Hàm tạo danh sách các bước di chuyển
    function generateMoves(n, source, auxiliary, destination, moves) {
    if (n === 1) {
    moves.push([source, destination]);
    } else {
    generateMoves(n - 1, source, destination, auxiliary, moves);
    moves.push([source, destination]);
    generateMoves(n - 1, auxiliary, source, destination, moves);
    }
    }

    // Hàm di chuyển từng đĩa một mỗi giây
    function moveOneByOne(moves) {
    var i = 0;
    var interval = setInterval(function() {
    if (i < moves.length) {
    moveDisc(moves[i][0], moves[i][1]);
    i++;
    } else {
    clearInterval(interval);
    }
    }, 1000); // Mỗi giây thực hiện một bước di chuyển
    }
    </script>

    </body>
    </html>

    Bạn có thể tải file html tại đây.