<body class="antialiased sans-serif text-slate-800 bg-opacity-50">
<div class="fixed top-0 h-screen w-screen bg-[url('https://images.unsplash.com/photo-1579783901586-d88db74b4fe4?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1048&q=80')] bg-center"></div>
<div x-data="state" x-cloak>
<div class="max-w-md mx-auto my-6 p-6 bg-white rounded drop-shadow-md">
<h1 class="text-2xl font-bold mb-6 flex items-center">
<div class="flex justify-center items-center rounded-full h-8 w-8 mr-2 bg-amber-100">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 fill-amber-600" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 2a1 1 0 011 1v1.323l3.954 1.582 1.599-.8a1 1 0 01.894 1.79l-1.233.616 1.738 5.42a1 1 0 01-.285 1.05A3.989 3.989 0 0115 15a3.989 3.989 0 01-2.667-1.019 1 1 0 01-.285-1.05l1.715-5.349L11 6.477V16h2a1 1 0 110 2H7a1 1 0 110-2h2V6.477L6.237 7.582l1.715 5.349a1 1 0 01-.285 1.05A3.989 3.989 0 015 15a3.989 3.989 0 01-2.667-1.019 1 1 0 01-.285-1.05l1.738-5.42-1.233-.617a1 1 0 01.894-1.788l1.599.799L9 4.323V3a1 1 0 011-1zm-5 8.274l-.818 2.552c.25.112.526.174.818.174.292 0 .569-.062.818-.174L5 10.274zm10 0l-.818 2.552c.25.112.526.174.818.174.292 0 .569-.062.818-.174L15 10.274z" clip-rule="evenodd" />
</svg>
</div>
Interactive Binary Search
</h1>
<div class="flex items-center">
<div class="w-full">
<label for="array" class="block mb-1 text-gray-600">Sorted list of integers</label>
<textarea x-model="array" x-bind:disabled="!!iterator" x-on:change="validationErrors.array = array.length && !array.match(/^\d+(,\s*\d+)*$/)" x-bind:class="{ 'border-red-400': validationErrors.array }" id="array" placeholder="A sorted comma-separated list of positive integers" class="font-mono text-sm border border-gray-200 shadow-sm w-full px-4 py-2 mb-3 h-24 leading-normal bg-white rounded outline-none focus:ring-2 ring-amber-300 ring-offset-1 disabled:opacity-70 disabled:bg-gray-100 transition-all">
</textarea>
<label for="number" class="block mb-1 text-gray-600">Integer to search</label>
<input x-model="number" x-bind:disabled="!!iterator" x-on:change="validationErrors.number = number.length && !number.match(/^\d+$/)" x-bind:class="{ 'border-red-400': validationErrors.number }" id="number" type="text" placeholder="Integer to search in the input array" class="font-mono text-sm border border-gray-200 shadow-sm w-full px-4 py-2 leading-normal bg-white rounded outline-none focus:ring-2 ring-amber-300 ring-offset-1 disabled:opacity-70 disabled:bg-gray-100 transition-all" />
</div>
</div>
<div class="mt-6">
<button x-on:click="handleStart()" x-bind:disabled="!!iterator || !array.length || !number.length || validationErrors.array || validationErrors.number" class="rounded px-4 py-2 mr-2 bg-green-600 text-white font-semibold shadow disabled:bg-gray-100 disabled:text-slate-500 hover:bg-green-700 transition-all">Start</button>
<button x-on:click="handleStep()" x-bind:disabled="!iterator" class="rounded px-4 py-2 mr-2 bg-sky-600 text-white font-semibold shadow disabled:bg-slate-200 disabled:text-slate-500 hover:bg-sky-700 transition-all">Step</button>
<button x-on:click="iterator = null" x-bind:disabled="!iterator" class="rounded px-4 py-2 mr-2 bg-amber-600 text-white font-semibold shadow disabled:bg-slate-200 disabled:text-slate-500 hover:bg-amber-700 transition-all">Stop</button>
</div>
<div x-show="parsedArray.length" class="my-6">
<label for="number" class="block font-bold mb-1">Execution</label>
<template x-for="(number, index) in parsedArray">
<span x-bind:class="{ 'bg-amber-100': index === middle, 'bg-green-400': true && (index === result), 'bg-red-100': result === null, 'opacity-40': !(index >= start && index <= end) }" class="px-2 mx-0.5 relative text-center inline-block border-2 rounded border-slate-500 text-slate-800 transition-all">
<span x-text="index" class="absolute top-7 text-xs left-1/2 -translate-x-1/2"></span>
<span x-text="number" class="font-semibold"></span>
</span>
</template>
</div>
<div x-show="parsedArray.length" class="pt-4">
<label for="number" class="block font-bold mb-1">Execution log</label>
<template x-for="(message, index) in log">
<div x-text="message" x-bind:class="{ 'opacity-40': index > 0 }"></span>
</template>
</div>
</div>
</div>
</body>
function* binarySearch(array, value, start, end) {
yield {
type: "step",
data: { start, end, middle: null },
log:
end < start
? "No elements left to check"
: end === start
? `Checking array at position ${start}`
: `Checking array from ${start} to ${end}`
};
if (end < start) {
yield {
type: "done",
data: null,
log: "Element not found"
};
}
const middle = start + Math.floor((end - start) / 2);
yield {
type: "step",
data: { middle },
log:
start !== end
? `Element in the middle is ${array[middle]}`
: middle < array.length
? `The only element left is ${array[middle]}`
: "Middle index out of bounds"
};
if (value === array[middle]) {
yield {
type: "done",
data: middle,
log: `Found element at index ${middle}`
};
} else if (value < array[middle]) {
yield* binarySearch(array, value, start, middle - 1);
} else {
yield* binarySearch(array, value, middle + 1, end);
}
}
function search(array, value) {
return binarySearch(array, parseInt(value), 0, array.length);
}
document.addEventListener("alpine:init", function init() {
Alpine.data("state", () => ({
array: "1, 3, 4, 5, 8, 16, 23, 29",
number: "16",
parsedArray: [],
iterator: null,
validationErrors: {
array: false,
number: false
},
log: [],
handleStart: function start() {
this.result = undefined;
this.log = [];
this.parsedArray = this.array.split(/,\s?/).map((el) => parseInt(el));
this.iterator = search(this.parsedArray, this.number);
this.handleStep();
},
handleStep: function step() {
const next = this.iterator.next();
const action = this.interactive[next.value.type].bind(this);
action(next.value.data);
this.log.unshift(next.value.log);
},
interactive: {
step: function step(data) {
const { start, end, middle } = data;
if (middle) {
this.middle = middle;
} else {
this.start = start;
this.end = end;
this.middle = null;
}
},
done: function done(data) {
this.result = data;
this.iterator = null;
}
}
}));
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.