h1 Linear vs Binary

input(type="text" maxLength="1")#random-letter
.controls
  button#random-btn Random
  button#search-btn Search

.searches
  - var alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')

  .linear-search
    h2 Linear
    p.info#linear-info  
    ul.data
      for char in alpha
        - var id = char + '-linear'
        li(id=id)= char

  .binary-search
    h2 Binary
    p.info#binary-info  
    ul.data
      for char in alpha
        - var id = char + '-binary'
        li(id=id)= char
View Compiled
// ## FONTS ##
@font-face("OperatorMono-Bold" "https://s3-us-west-2.amazonaws.com/s.cdpn.io/161040/OperatorMono-Bold")
@font-face("OperatorMono-Medium" "https://s3-us-west-2.amazonaws.com/s.cdpn.io/161040/OperatorMono-Medium")

// ## VARS ##
$white: white
$yellow: #FFF32B
$blue: #3BB0FF
$red: #FF014E
$green: #66FF00
$reg-stack: "OperatorMono-Medium", "Lucida Console", Monaco, monospace
$bold-stack: "OperatorMono-Bold", "Lucida Console", Monaco, monospace

// ## ANIMATIONS ##
@keyframes shake
  10%, 90%
    transform: translate3d(-1px, 0, 0)
  20%, 80%
    transform: translate3d(2px, 0, 0)
  30%, 50%, 70%
    transform: translate3d(-4px, 0, 0)
  40%, 60%
    transform: translate3d(4px, 0, 0)

body
  background: $blue
  text-align: center
  font-family: $reg-stack
  color: $white
  
h1, h2, h3, h4, h5, h6
  color: $yellow
  font-family: $bold-stack
  font-size: 2em
  
h1
  font-size: 3em
  
input#random-letter
  text-align: center
  width: 1em
  border: none
  border-bottom: 5px solid $white
  padding-bottom: .2em
  text-transform: uppercase
  background: $blue
  font-size: 3em
  font-family: $reg-stack
  color: white
  &.shake
    animation: shake 0.82s cubic-bezier(.36,.07,.19,.97) both
  &:focus
    outline: none
  
button
  text-align: center
  border: none
  background: $blue
  border: 5px solid $yellow
  color: $yellow
  font-size: 30px
  font-family: $bold-stack
  padding: .15em 1.3em
  margin: 1em
  transition: border-color .2s, color .2s
  -webkit-transition: border-color .2s, color .2s
  &:hover
    color: $white
    border-color: $white
    cursor: pointer

.searches
  .linear-search, .binary-search
    display: inline-block
  
ul.data
  padding: 0
  margin: 1em
  margin-top: 0
  li
    display: inline-block
    border-bottom: 2px solid rgba(0,0,0,0)
    &.exempt
      color: $red
      border-bottom: 2px solid $red
    &.found
      color: $green
      border-bottom: 2px solid $green
View Compiled
// ## Global Variables
const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')
const ARR_LENGTH = ALPHABET.LENGTH
const SEARCH_INTERVAL_TIME = 800
let linear_interval
let binary_interval

// ## Helper Functions
function getArgumentsAsArray() {
  let args = Array.from(arguments)
  if (typeof args[0] === "object") args = args[0]
  if (args[0] && args[0].length) args = args[0]
  return args
}
function sum() {
  let args = getArgumentsAsArray(arguments)
  return Array.from(args).reduce( (p, c) => p + c )
}
function avg() {
  let args = getArgumentsAsArray(arguments)
  return sum(args) / args.length
}
function randomIndex(array) {
  return Math.ceil(Math.random() * array.length) - 1
}
function randomElement(array) {
  return array[randomIndex(array)]
}

// ## Search Functions
function startLinearSearch(value, set) {
  let current_value
  let current_elm
  let current_index = 0
  let num_iterations = 0
  let info = document.getElementById('linear-info')
  linear_interval = setInterval( () => {
    current_value = set[current_index]
    current_elm = document.getElementById(`${current_value}-linear`)
    num_iterations += 1
    if (current_index >= set.length) { 
      clearInterval(linear_interval)
      info.innerHTML = `Index: -1, Value: none, Num Iterations: ${num_iterations}`
      return
    }
    if (current_value != value) {
      current_elm.className = "exempt"
      info.innerHTML = `Index: ${current_index}, Value: ${current_value}, Num Iterations: ${num_iterations}`
    }
    if (current_value == value) {
      clearInterval(linear_interval)
      current_elm.className = "found"
      info.innerHTML = `Index: ${current_index}, Value: ${current_value}, Num Iterations: ${num_iterations}`
      return
    }
    current_index += 1
  }, SEARCH_INTERVAL_TIME)
}
function startBinarySearch(value, set) {
  let current_value
  let current_elm
  let current_index
  let num_iterations = 0
  let min = 0
  let max = set.length - 1
  let info = document.getElementById('binary-info')
  binary_interval = setInterval( () => {
    num_iterations += 1
    if (min > max) {
      clearInterval(binary_interval)
      info.innerHTML = `Index: -1, Value: none, Num Iterations: ${num_iterations}`
      return
    }
    current_index = Math.floor(avg(min, max))
    current_value = set[current_index]
    current_elm = document.getElementById(`${current_value}-binary`)
    if (current_value < value) { 
      min = current_index + 1
      set.slice(0, min).forEach( (n) => { 
        document.getElementById(`${n}-binary`).className = "exempt"
      })
      // current_elm.className = "exempt"
      info.innerHTML = `Index: ${current_index}, Value: ${current_value}, Num Iterations: ${num_iterations}`
    }
    if (current_value > value ) {
      max = current_index - 1
      set.slice(current_index, set.length).forEach( (n) => { 
        document.getElementById(`${n}-binary`).className = "exempt"
      })
      info.innerHTML = `Index: ${current_index}, Value: ${current_value}, Num Iterations: ${num_iterations}`
    }
    if (current_value == value) {
      clearInterval(binary_interval)
      current_elm.className = "found"
      info.innerHTML = `Index: ${current_index}, Value: ${current_value}, Num Iterations: ${num_iterations}`
      return
    }
  }, SEARCH_INTERVAL_TIME)
}


// ## DOM triggered functions
function reset() {
  clearInterval(linear_interval)
  clearInterval(binary_interval)
  let exempt = document.querySelectorAll('.exempt')
  Array.prototype.forEach.call(exempt, (el) => { el.classList.remove('exempt') })
  let found = document.querySelectorAll('.found')
  Array.prototype.forEach.call(found, (el) => { el.classList.remove('found') })
  let info = document.querySelectorAll('.info')
  Array.prototype.forEach.call(info, (el) => { el.innerHTML = '&nbsp;' })
  enableButton('random-btn')
  enableButton('search-btn')
}
function getRandomLetter() {
  reset()
  const value = randomElement(ALPHABET)
  let input = document.getElementById('random-letter')
  input.value = value
  input.style.webkitAnimationName = 'shake'
  input.className = 'shake'
}
function disableButton(id) {
  document.getElementById(id).disabled = true
}
function enableButton(id) {
  document.getElementById(id).disabled = false
}

// ## Setup functions
function setupInputHandlers () {
  let input = document.getElementById('random-letter')
  input.onkeyup = function() {
    this.value = this.value.toUpperCase()
    reset()
  }
  input.addEventListener('webkitAnimationEnd', function() {
    this.style.webkitAnimationName = ''
    this.className = ''
  }, false)
  let random_btn = document.getElementById('random-btn')
  random_btn.onclick = function (e) {
    e.preventDefault()
    getRandomLetter()
  }
  let search_btn = document.getElementById('search-btn')
  search_btn.onclick = function (e) {
    e.preventDefault()
    if (input.value.length) {
      startLinearSearch(input.value, ALPHABET)
      startBinarySearch(input.value, ALPHABET)
    }
  }
}
function inputFocus() {
  let input = document.getElementById('random-letter')
  input.focus()
}

// Let's roll
window.onload = () => {
  setupInputHandlers()
  inputFocus()
}
View Compiled
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.