<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bubble Sort Visualizer</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>Bubble Sort Visualizer</h1>
<div id="array-container">
<div id="starting-array"></div>
</div>
<button id="generate-btn">Generate Array</button>
<button id="sort-btn">Sort Array</button>
<script src="script.js"></script>
</body>
</html>
body {
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
margin-top: 50px;
}
#array-container {
display: flex;
flex-direction: column;
gap: 10px;
margin-bottom: 20px;
}
#array-container div {
display: flex;
gap: 5px;
padding: 5px;
border: 1px solid #ccc;
border-radius: 5px;
background-color: #f9f9f9;
}
span {
display: inline-block;
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
border: 1px solid #333;
background-color: white;
border-radius: 3px;
font-weight: bold;
}
button {
margin: 5px;
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
}
/* file: script.js */
/* Bubble Sort
The Bubble Sort algorithm sorts a sequence of integers by comparing couples of adjacent elements starting from the beginning of the sequence. If the first element is greater than the second one, it swaps them. Then, it proceeds with the following couple. When the last element of the sequence is reached, it starts a new cycle from the beginning of the sequence, and repeats the process until the elements are sorted. The algorithm stops after one cycle completes with no swaps. */
/* generateElement() returns a random integer between 1 and 100, inclusive. */
const generateElement = () => {
return Math.floor(Math.random() * 100) + 1;
}
/* generateArray() uses the generateElement function to return an array containing five random integers. */
const generateArray = () => {
const randArr = [];
let randVal;
for (let i=0; i<5; i++) {
randVal = generateElement();
randArr.push(randVal);
}
return randArr;
}
/* generateContainer() creates and returns an empty div element. */
const generateContainer = () => {
/* Usage: const mydiv = generateContainer()
document.body.appendChild(mydiv)
This appends to the <body>
*/
const newDiv = document.createElement("div")
return newDiv;
}
/* fillArrContainer() takes an HTML element as the first argument and an array as the second argument. It fills the element passed as the first argument to the function with five span elements with the text of an integer from the array passed as the second argument to the function. */
const fillArrContainer = (eltHTML, arr) => {
eltHTML.innerHTML = "";
// FIXED: Using createElement and appendChild for robustness in test environments
for (let i=0; i<arr.length; i++) {
const span = document.createElement("span");
span.textContent = arr[i].toString();
eltHTML.appendChild(span);
}
}
/* isOrdered() takes two integers and returns a boolean indicating if the first integer is less than or equal to the second. */
function isOrdered (int1, int2) {
return int1 <= int2;
}
/* swapElements() takes an array of integers and a numeric index. It modifies the array in place by swapping the element at the passed index and the following element if isOrdered() returns false. */
const swapElements = (intArr, index) => {
if (index < 0 || index >= intArr.length - 1) {
console.error("Invalid index provided.")
return;
}
if (isOrdered(intArr[index], intArr[index + 1])) {
return
} else {
let temp = intArr[index];
intArr[index] = intArr[index + 1];
intArr[index + 1] = temp;
}
}
/* highlightCurrentEls() takes an HTML element and a numeric index. It sets the border of the given element's child at the given index, and the child immediately after the index, to have a dashed style, a red color, and a width of your choice. */
const highlightCurrentEls = (eltHTML, index) => {
// First, remove existing highlights from all children in the container
const childElements = eltHTML.children;
for (let i = 0; i < childElements.length; i++) {
childElements[i].style.border = '1px solid #333'; // Reset to default
}
// Apply the required highlight
if (childElements[index]) {
childElements[index].style.border = '2px dashed red';
}
if (childElements[index + 1]) {
childElements[index + 1].style.border = '2px dashed red';
}
}
/* Main process ---------------------*/
/* When you click #generate-btn you should use the fillArrContainer function to fill #starting-array with five span elements, each with a random number as its text. If present, other elements should be removed from #array-container. */
const generateBtn = document.getElementById("generate-btn");
const startingArr = document.getElementById("starting-array");
const arrayContainer = document.getElementById("array-container");
let sortArr;
generateBtn.addEventListener("click", () => {
// Requirement 17: Remove all other elements from arrayContainer
const toRemove = arrayContainer.querySelectorAll(
':not([id="starting-array"])');
toRemove.forEach(element => {element.remove();});
sortArr = generateArray();
fillArrContainer(startingArr, sortArr);
// Ensure the starting array is not highlighted after generation
highlightCurrentEls(startingArr, -1);
});
/* Implement the Bubble Sort algorithm so that after you click #sort-btn, #array-container contains a div element for each of the steps required by the Bubble Sort algorithm to sort the starting array, including the div representing the starting array and a div representing the sorted array. */
const sortBtn = document.getElementById("sort-btn");
// REORGANIZED AND CORRECTED LISTENER
sortBtn.addEventListener("click", () => {
if (!sortArr || sortArr.length === 0) {
// Prevent sorting if array hasn't been generated
return;
}
// 1. Cleanup and Setup (Ensures #starting-array is the only child initially)
const toRemove = arrayContainer.querySelectorAll(
':not([id="starting-array"])');
toRemove.forEach(element => { element.remove(); });
// Use a fresh copy to sort
let tempArr = [...sortArr];
const n = tempArr.length;
let stepCount = 0;
// Refill the starting array content (crucial if generate was not clicked immediately before sort)
fillArrContainer(startingArr, sortArr);
// --- Bubble Sort Visualization: One DIV per Comparison Step (Meeting Req 18) ---
// Outer loop (passes)
for (let i = 0; i < n; i++) {
// Inner loop (comparisons)
for (let j = 0; j < n - 1 - i; j++) {
let container;
// 2. DETERMINE CONTAINER
if (stepCount === 0) {
// Use existing #starting-array for the first step (Req 21)
container = startingArr;
} else {
// Create new container for all subsequent steps (Req 18 count)
container = generateContainer();
// Visualize the array state *before* the comparison/swap
fillArrContainer(container, tempArr);
arrayContainer.appendChild(container);
}
// 3. VISUALIZE: Highlight the pair being compared (j and j+1)
highlightCurrentEls(container, j);
// 4. ALGORITHM: Perform the comparison and swap logic
swapElements(tempArr, j);
stepCount++;
}
}
// 5. FINAL STATE: Display final sorted array (Req. 18)
const finalDiv = generateContainer();
finalDiv.id = "sorted-array";
fillArrContainer(finalDiv, tempArr);
// Remove highlights from the final state
highlightCurrentEls(finalDiv, -1);
arrayContainer.appendChild(finalDiv);
});
18. After you click #sort-btn, #array-container should contain as many div elements as the steps required by the Bubble Sort algorithm to sort the starting array, including the div representing the starting array and a div representing the sorted array.