- Published on
Kata - Practice Problems
- Authors
- Name
- Curtis Warcup
Table of Contents
- What is a Kata?
- Check Air Quality
- Conditional Sums
- Longest Name
- Percent Encoded String
- Sum of Largest Numbers
- Count Number of Vowels
- Where can I park?
- Repeating Numbers
- Talking Calender
- Change Calculator
- Case Maker
- Case Maker II
- Multiplication Table
- Square Code
- Queen Threat Detector
- Bouncy Castle
- The Great Codeville Bake-off
- Organizing Instructors
- JS Object From URL Encoded String
- Taxicab Geometry
What is a Kata?
According to Wikipedia, "Kata (型 or 形 literally: "form"), a Japanese word, are detailed choreographed patterns of movements practiced either solo or in pairs."
We will be using Katas to practice different programming patterns.
Check Air Quality
For this challenge we will implement a function called checkAir()
, which will check a collection of air samples.
The function will take in two arguments.
- The first argument is an array of strings, where each string represents a small air sample that is either
clean
ordirty
. - The second argument is a number representing the highest acceptable amount of dirty samples. For example, a threshold of 0.4 means that there must be less than 40% of total samples classified as dirty for our air to be considered clean.
Our function must return Polluted
if there are too many dirty air samples, or Clean
if the proportion of dirty samples is below the threshold.
const checkAir = function (samples, threshold) {
const numOfSamples = samples.length
const dirtySamples = counter(samples, 'dirty')
return dirtySamples / numOfSamples > threshold ? 'Polluted' : 'Clean'
}
function counter(samples, result) {
let count = 0
for (let char of samples) {
if (char === result) {
count++
}
}
return count
}
console.log(
checkAir(
// should return 'Polluted'
['clean', 'clean', 'dirty', 'clean', 'dirty', 'clean', 'clean', 'dirty', 'clean', 'dirty'],
0.3
)
)
console.log(
checkAir(
// should return 'Polluted'
['dirty', 'dirty', 'dirty', 'dirty', 'clean'],
0.25
)
)
console.log(
checkAir(
// should return 'Clean'
['clean', 'dirty', 'clean', 'dirty', 'clean', 'dirty', 'clean'],
0.9
)
)
Conditional Sums
Adding only the numbers in the array which match the given condition.
const conditionalSum = function (values, condition) {
let result = []
values.map((item) => {
if (condition === 'even') {
if (item % 2 === 0) {
result.push(item)
}
} else if (condition === 'odd') {
if (item % 2 !== 0) {
result.push(item)
}
}
})
return result.reduce((partialSum, item) => partialSum + item, 0)
}
// or
const conditionalSum = function (values, condition) {
let sum = 0
for (let i = 0; i < values.length; i++) {
if (condition === 'even' && values[i] % 2 === 0) {
sum += values[i]
} else if (condition === 'odd' && values[i] % 2 !== 0) {
sum += values[i]
}
}
return sum
}
console.log(conditionalSum([1, 2, 3, 4, 5], 'even')) // 6
console.log(conditionalSum([1, 2, 3, 4, 5], 'odd')) // 9
console.log(conditionalSum([13, 88, 12, 44, 99], 'even')) // 144
console.log(conditionalSum([], 'odd')) // 0
Longest Name
Given a list of names, return which instructor has the longest name.
const instructorWithLongestName = function (instructors) {
let maxIndex = 0
for (let i = 0; i < instructors.length; i++) {
if (instructors[i].name.length > instructors[maxIndex].name.length) {
maxIndex = i
}
}
return instructors[maxIndex]
}
console.log(
instructorWithLongestName([
// {name: "Jeremiah", course: "Web"}
{ name: 'Samuel', course: 'iOS' },
{ name: 'Jeremiah', course: 'Web' },
{ name: 'Ophilia', course: 'Web' },
{ name: 'Donald', course: 'Web' },
])
)
console.log(
instructorWithLongestName([
// {name: "Domascus", course: "Web"}
{ name: 'Matthew', course: 'Web' },
{ name: 'David', course: 'iOS' },
{ name: 'Domascus', course: 'Web' },
])
)
Percent Encoded String
Given a normal string of words, turn it into a percent-encoded string by replacing all whitespace with %20. Take a look at the following URL, specifically the last part:
https://www.google.com/search?q=javascript+string+replace+whitespace
This URL will perform a google search for the term "javascript string replace whitespace". Notice that when the string "javascript string replace whitespace" is part of a URL, the space is replaced with %20
For this exercise, focusing on replacing the spaces with %20
.
const urlEncode = function (text) {
return text.replace(/[\s]/g, '%20')
}
// without replace
const urlEncode = function (text) {
let result = ''
for (let char of text.trim().split('')) {
if (char === ' ') {
char = '%20'
result = result + char
} else {
result = result + char
}
}
return result
}
console.log(urlEncode('Curtis Warcup')) // "Curtis%20Warcup"
console.log(urlEncode(' Curtis Warcup ')) // "%20Curtis%20Warcup%20"
console.log(urlEncode('dogs are super cool')) // "dogs%20are%20super%20cool"
Sum of Largest Numbers
Given an array of 2 or more numbers. Find the two largest numbers in that array, and sum them together.
const sumLargestNumbers = function (data) {
let num1 = data
.sort((a, b) => {
return a - b
})
.pop()
let num2 = data
.sort((a, b) => {
return a - b
})
.pop()
return num1 + num2
}
console.log(sumLargestNumbers([1, 10])) // 11
console.log(sumLargestNumbers([1, 2, 3])) // 5
console.log(sumLargestNumbers([10, 4, 34, 6, 92, 2])) // 126
Count Number of Vowels
Counting the number of vowels that appear in a given string.
const numberOfVowels = function (data) {
let result = data.match(/[aeiou]/gi)
return (result = result ? result.length : 0)
}
console.log(numberOfVowels('orange')) // 2
console.log(numberOfVowels('Curtis Warcup')) // 4
console.log(numberOfVowels('aeiou')) // 5
console.log(numberOfVowels('')) // 0
Where can I park?
We need to write a function called whereCanIPark()
that returns the coordinates of an available parking spot for the vehicle, or returns false if there is no available spot. Our function receives an array of arrays representing parking spots, and a string with type of the vehicle that is looking for a parking spot.
There are three kinds of possible vehicles: regular cars, small cars, and motorcycles.
- Regular cars can only park in R spots.
- Small cars can park in R or S spots.
- Motorcycles can park in R, S, or M spots.
In the array of parking spots, spots are written in both lower-case and upper-case. An upper-case letter means that the particular spot is AVAILABLE, while lower-case letters mean that the spot is UNAVAILABLE.
Our function must return an array with the coordinates of the spot as an [X, Y]
pair. See the example input and output below for an illustration.
console.log(
whereCanIPark(
// [4, 0]
[
// COLUMNS ARE X
// 0 1 2 3 4 5
['s', 's', 's', 'S', 'R', 'M'], // 0 ROWS ARE Y
['s', 'M', 's', 'S', 'r', 'M'], // 1
['s', 'M', 's', 'S', 'r', 'm'], // 2
['S', 'r', 's', 'm', 'r', 'M'], // 3
['S', 'r', 's', 'm', 'r', 'M'], // 4
['S', 'r', 'S', 'M', 'M', 'S'], // 5
],
'regular'
)
)
Possible solution:
const whereCanIPark = function (spots, vehicle) {
const avail = vehicleSpots(vehicle)
for (let row = 0; row < spots.length; row++) {
for (let col = 0; col < spots.length; col++) {
let char = spots[row][col]
if (avail.indexOf(char) > -1) {
return new Array(col, row)
}
}
}
return false
}
function vehicleSpots(vehicle) {
let avail
if (vehicle === 'regular') {
return (avail = 'R')
} else if (vehicle === 'small') {
return (avail = 'RS')
} else if (vehicle === 'motorcycle') {
return (avail = 'RSM')
} else {
return 'Need to add type of vehicle'
}
}
console.log(vehicleSpots('regular'))
console.log(vehicleSpots('small'))
console.log(vehicleSpots('motorcycle'))
console.log(
whereCanIPark(
// [3, 1]
[
['s', 's', 's', 's', 's', 's'],
['s', 'm', 's', 'S', 'r', 's'],
['s', 'm', 's', 'S', 'r', 's'],
['S', 'r', 's', 'm', 'r', 's'],
['S', 'r', 's', 'm', 'R', 's'],
['S', 'r', 'S', 'M', 'm', 'S'],
],
'motorcycle'
)
)
console.log(
whereCanIPark(
// [4, 0]
[
// COLUMNS ARE X
// 0 1 2 3 4 5
['s', 's', 's', 'S', 'R', 'M'], // 0 ROWS ARE Y
['s', 'M', 's', 'S', 'r', 'M'], // 1
['s', 'M', 's', 'S', 'r', 'm'], // 2
['S', 'r', 's', 'm', 'r', 'M'], // 3
['S', 'r', 's', 'm', 'r', 'M'], // 4
['S', 'r', 'S', 'M', 'M', 'S'], // 5
],
'regular'
)
)
console.log(
whereCanIPark(
// false
[
['M', 'M', 'M', 'M'],
['M', 's', 'M', 'M'],
['M', 'M', 'M', 'M'],
['M', 'M', 'r', 'M'],
],
'small'
)
)
Repeating Numbers
The input data for this exercise will be two dimensional array (an array of arrays), where each sub-array will have two numeric values. For example:
;[
[1, 2],
[2, 3],
]
The first will be the value to repeat, the second will be the amount of times to repeat that value.
const repeatNumbers = function (data) {
let values = []
for (let i = 0; i < data.length; i++) {
let result = ''
for (let repeats = 0; repeats < data[i][1]; repeats++) {
result += data[i][0]
}
values.push(result)
}
return values.join(', ')
}
console.log(repeatNumbers([[1, 10]])) // 1111111111
console.log(
repeatNumbers([
[1, 2],
[2, 3],
])
) // 11, 222
console.log(
repeatNumbers([
[10, 4],
[34, 6],
[92, 2],
])
) // 10101010, 343434343434, 9292
Talking Calender
In this activity, we will be converting date strings like "2017/12/02", into more English friendly date strings like "December 2nd, 2017".
We will be given a date as a string (not a Date
object). The date will always be formatted as YYYY/MM/DD
. We will have to parse the given string and produce a human readable date.
const talkingCalendar = function (date) {
const monthNames = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
]
let monthIndex = new Date(date).getMonth()
let year = new Date(date).getFullYear()
let month = monthNames[monthIndex]
let day = parseInt(date.slice(8, 10))
const nth = function (day) {
if (day > 3 && day < 21) return `${day}th`
switch (day % 10) {
case 1:
return `${day}st`
case 2:
return `${day}nd`
case 3:
return `${day}rd`
default:
return `${day}th`
}
}
return `${month} ${nth(day)}, ${year}`
}
console.log(talkingCalendar('2017/12/02')) // December 2nd, 2017
console.log(talkingCalendar('2007/11/11')) // November 11th, 2007
console.log(talkingCalendar('1987/08/24')) // August 24th, 1987
Change Calculator
Create a function that can calculate which coins we should use when we need to give change.
We will be given two numbers, the total of a transaction, and the amount of cash given to the cashier. Both of these numbers will be represented as whole numbers in cents. Therefore $10 will be represented as 1000
.
Our function calculateChange
should return an object which describes the total amount of change for the cashier to give back. Although pennies are not used in circulation, we will still calculate the amount of pennies to give back.
Valid denominations are as follows:
- Twenty dollars
- Ten dollars
- Five dollars
- Two dollars
- One dollar
- Quarter (25¢)
- Dime (10¢)
- Nickel (5¢)
- Penny (1¢)
Create a function named calculateChange
that takes in a total amount of a bill and the total cash given to pay that bill. Return a new object that describes the total amount of change for the cashier to give back. Omit any types of change that you shouldn't give back, i.e. if you don't give back a twenty dollar bill, don't include it in the results.
const calculateChange = function (total, cash) {
const getDollarCents = (total, cash) => {
const amountOwed = cash - total
const centString = amountOwed.toString()
const totalCents = centString.slice(centString.length - 2, centString.length)
const totalDollars = centString.slice(0, centString.length - 2)
return [totalDollars, totalCents]
}
let dollarsOwed = getDollarCents(total, cash)[0]
let dollarsBack = 0
let changeObj = {}
while (dollarsBack < dollarsOwed) {
if (dollarsBack + 20 <= dollarsOwed) {
changeObj['twentyDollar'] = Math.floor((dollarsOwed - dollarsBack) / 20)
dollarsBack += 20 * changeObj['twentyDollar']
} else if (dollarsBack + 10 <= dollarsOwed) {
changeObj['tenDollar'] = Math.floor((dollarsOwed - dollarsBack) / 10)
dollarsBack += 10 * changeObj['tenDollar']
} else if (dollarsBack + 5 <= dollarsOwed) {
changeObj['fiveDollar'] = Math.floor((dollarsOwed - dollarsBack) / 5)
dollarsBack += 5 * changeObj['fiveDollar']
} else if (dollarsBack + 2 <= dollarsOwed) {
changeObj['twoDollar'] = Math.floor((dollarsOwed - dollarsBack) / 2)
dollarsBack += 2 * changeObj['twoDollar']
} else if (dollarsBack + 1 <= dollarsOwed) {
changeObj['oneDollar'] = Math.floor((dollarsOwed - dollarsBack) / 1)
dollarsBack += 1 * changeObj['oneDollar']
} else {
break
}
}
let centsOwed = getDollarCents(total, cash)[1]
let centsBack = 0
while (centsBack < centsOwed) {
if (centsBack + 25 <= centsOwed) {
changeObj['quarter'] = Math.floor((centsOwed - centsBack) / 25)
centsBack += 25 * changeObj['quarter']
} else if (centsBack + 10 <= centsOwed) {
changeObj['dime'] = Math.floor((centsOwed - centsBack) / 10)
centsBack += 10 * changeObj['dime']
} else if (centsBack + 5 <= centsOwed) {
changeObj['nickle'] = Math.floor((centsOwed - centsBack) / 5)
centsBack += 5 * changeObj['nickle']
} else if (centsBack + 1 <= centsOwed) {
changeObj['penny'] = Math.floor(centsOwed - centsBack)
centsBack += 1 * changeObj['penny']
} else {
break
}
}
return changeObj
}
console.log(calculateChange(1787, 2000)) // { twoDollar: 1, dime: 1, penny: 3 }
console.log(calculateChange(2623, 4000))
// { tenDollar: 1, twoDollar: 1, oneDollar: 1, quarter: 3, penny: 2 }
console.log(calculateChange(501, 1000))
// { twoDollar: 2, quarter: 3, dime: 2, penny: 4 }
Case Maker
We will receive a normal string of words separated with spaces as the input. Our job is to convert these strings into camel cased strings.
const camelCase = function (input) {
// Your code here
}
console.log(camelCase('this is a string')) // thisIsAString
console.log(camelCase('loopy lighthouse')) // loopyLighthouse
console.log(camelCase('supercalifragalisticexpialidocious')) // supercalifragalisticexpialidocious
Possible Solution:
const camelCase = function (input) {
const lowers = input.toLowerCase().split(' ') // in case any letters are already uppercase
const result = [lowers.shift()]
for (let word of lowers) {
result.push(word[0].toUpperCase() + word.slice(1))
}
return result.join('')
}
console.log(camelCase('this is a string')) // thisIsAString
console.log(camelCase('loopy lighthouse')) // loopyLighthouse
console.log(camelCase('supercalifragalisticexpialidocious')) // supercalifragalisticexpialidocious
Case Maker II
We will still be given an input string to convert. However, this time, we'll also be given a casing style to work with. The following code block will describe all the casing styles to support. We may also receive an array of casing styles, and each of these should be applied.
Example:
const makeCase = function(input, case) {
// Put your solution here
}
console.log(makeCase("this is a string", "camel")); // thisIsAString
console.log(makeCase("this is a string", "pascal")); // ThisIsAString
console.log(makeCase("this is a string", "snake")); // this_is_a_string
console.log(makeCase("this is a string", "kebab")); // this-is-a-string
console.log(makeCase("this is a string", "title")); // This Is A String
console.log(makeCase("this is a string", "vowel")); // thIs Is A strIng
console.log(makeCase("this is a string", "consonant")); // THiS iS a STRiNG
console.log(makeCase("this is a string", ["upper", "snake"])); // THIS_IS_A_STRING
Precedence of each of the casing styles are as follows, values higher in the list should be processed first:
camel
,pascal
,snake
,kebab
,title
vowel
,consonant
upper
,lower
Our function should be able to handle all of these cases.
For more information on casing styles, read Wikipedia's Special Case Styles for a list of various casing examples.
const makeCase = function (input, cases) {
function handleCase(input) {
if (cases.includes('camel')) {
const lowers = input.toLowerCase().split(' ') // in case any letters are already uppercase
const result = [lowers.shift()]
for (let word of lowers) {
result.push(word[0].toUpperCase() + word.slice(1))
}
return result.join('')
} else if (cases.includes('pascal')) {
const lowers = input.toLowerCase().split(' ') // in case any letters are already uppercase
const result = []
for (let word of lowers) {
result.push(word[0].toUpperCase() + word.slice(1))
}
return result.join('')
} else if (cases.includes('snake')) {
return input.toLowerCase().replace(/\s/g, '_')
} else if (cases.includes('kebab')) {
return input.toLowerCase().replace(/\s/g, '-')
} else if (cases.includes('title')) {
let result = []
for (let word of input.split(' ')) {
result.push(word[0].toUpperCase() + word.slice(1))
}
return result.join(' ')
} else {
return input
}
}
function handleChars(input) {
if (cases.includes('upper')) {
return input.toUpperCase()
} else if (cases.includes('lower')) {
return input.toLowerCase()
} else {
return input
}
}
function handleType(input) {
if (cases.includes('vowel')) {
let newWords = ''
for (let char of input) {
if (char.match(/[aeiou]/)) {
newWords += char.toUpperCase()
} else {
newWords += char
}
}
return newWords
} else if (cases.includes('consonant')) {
let newWords = ''
for (let char of input) {
if (char.match(/[bcdfghjklmnpqrstvwxys]/)) {
newWords += char.toUpperCase()
} else {
newWords += char
}
}
return newWords
} else {
return input
}
}
let inputCase = handleCase(input)
let inputType = handleType(inputCase)
return handleChars(inputType)
}
console.log(makeCase('this is a string', 'camel')) // thisIsAString
console.log(makeCase('this is a string', 'pascal')) // ThisIsAString
console.log(makeCase('this is a string', 'snake')) // this_is_a_string
console.log(makeCase('this is a string', 'kebab')) // this-is-a-string
console.log(makeCase('this is a string', 'title')) // This Is A String
console.log(makeCase('this is a string', 'vowel')) // thIs Is A strIng
console.log(makeCase('this is a string', 'consonant')) // THiS iS a STRiNG
console.log(makeCase('this is a string', ['upper', 'snake'])) // THIS_IS_A_STRING
Multiplication Table
We will be given a number as our input data. This number is the highest value of our multiplication table.
Our job is to generate a multiplication table for the values from 1 to the provided number.
For example:
console.log(multiplicationTable(1))
// expect to return
// 1
console.log(multiplicationTable(5))
// expect to return
// 1 2 3 4 5
// 2 4 6 8 10
// 3 6 9 12 15
// 4 8 12 16 20
// 5 10 15 20 25
console.log(multiplicationTable(10))
// expect to return
// 1 2 3 4 5 6 7 8 9 10
// 2 4 6 8 10 12 14 16 18 20
// 3 6 9 12 15 18 21 24 27 30
// 4 8 12 16 20 24 28 32 36 40
// 5 10 15 20 25 30 35 40 45 50
// 6 12 18 24 30 36 42 48 54 60
// 7 14 21 28 35 42 49 56 63 70
// 8 16 24 32 40 48 56 64 72 80
// 9 18 27 36 45 54 63 72 81 90
// 10 20 30 40 50 60 70 80 90 100
Possible Solution:
const multiplicationTable = function (maxValue) {
// make array of maxValue number of empty arrays
let result = []
for (let i = 0; i < maxValue; i++) {
result.push([])
}
let counter = 1
let colStart = 0
let colEnd = maxValue - 1
let rowStart = 0
let rowEnd = maxValue - 1
// top row
for (let i = colStart; i < maxValue; i++) {
result[rowStart][i] = counter
counter++
}
rowStart++
counter = 2
// left col
for (let i = rowStart; i < maxValue; i++) {
result[i][colStart] = counter
counter++
}
colStart++
// fill the array positions
while (colStart <= colEnd && rowStart <= rowEnd) {
if (result[rowStart].length <= maxValue) {
for (let i = colStart; i <= colEnd; i++) {
result[rowStart][i] = result[rowStart][0] * result[0][colStart]
colStart++
}
}
rowStart++
colStart = 1
}
return result
}
console.log(multiplicationTable(1))
// expect to return
// 1
console.log(multiplicationTable(5))
// expect to return
// 1 2 3 4 5
// 2 4 6 8 10
// 3 6 9 12 15
// 4 8 12 16 20
// 5 10 15 20 25
console.log(multiplicationTable(10))
// expect to return
// 1 2 3 4 5 6 7 8 9 10
// 2 4 6 8 10 12 14 16 18 20
// 3 6 9 12 15 18 21 24 27 30
// 4 8 12 16 20 24 28 32 36 40
// 5 10 15 20 25 30 35 40 45 50
// 6 12 18 24 30 36 42 48 54 60
// 7 14 21 28 35 42 49 56 63 70
// 8 16 24 32 40 48 56 64 72 80
// 9 18 27 36 45 54 63 72 81 90
// 10 20 30 40 50 60 70 80 90 100
Square Code
In Square Code, the spaces are removed from the english text and the characters are written into a square (or rectangle). For example, the sentence "If man was meant to stay on the ground god would have given us roots" is 54 characters long, once the spaces are removed, so it is written into a rectangle with 7 rows and 8 columns.
ifmanwas
meanttos
tayonthe
groundgo
dwouldha
vegivenu
sroots
The square root of 54 (Math.sqrt(54))
is 7.3484692283495345
. If we round this number up (Math.ceil(Math.sqrt(54)))
, we get 8
. If we use that for the number of characters on each line (the number of columns), then our text will be close to a square shape.
The message is then coded by reading down the columns going left to right. For example, the message above is coded as:
imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau
And that's the output of the algorithm. We can then reverse the process to decrypt the text and read the original message.
const squareCode = (message) => {
let result = ''
message = message.replace(/\s/g, '')
let messArr = []
let stringLength = Math.ceil(Math.sqrt(message.length))
while (message !== '') {
messArr.push(message.slice(0, stringLength))
message = message.slice(stringLength, message.length)
}
for (let i = 0; i < messArr[0].length; i++) {
result += messArr[0][i]
for (let j = 1; j < messArr.length; j++) {
if (messArr[j][i]) {
result += messArr[j][i]
}
}
result += ' '
}
return result
}
// console.log(squareCode('chill out')); // clu hlt io
// console.log(squareCode("feed the dog")); // fto ehg ee dd
// console.log(squareCode("have a nice day")); // hae and via ecy
// console.log(squareCode("if man was meant to stay on the ground god would have given us roots")); // imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau
Queen Threat Detector
In this exercise we will be writing an algorithm, to detect if two queens on a chess board can attack each other.
A game of chess is played on an 8 column by 8 row board. In the game of chess, a queen can attack pieces which are on the same row, column, or diagonal.
In JavaScript, we can represent a chessboard using an 8 by 8 array (8 arrays within an array). For this exercise, our chess board will have 2 queens, and nothing else. A 1 in the array represents a queen on the corresponding square, and a O in the array represents an unoccupied square.
So the following chess board:
Would be represented in JavaScript like this:
;[
[0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
]
Our first challenge will be to write a function that generates a chess board like this.
We will then write a function to detect weather or not the two queens are positioned so that they attack each other.
let whiteQueen = [0, 5]
let blackQueen = [5, 0]
let generatedBoard = generateBoard(whiteQueen, blackQueen)
console.log(generatedBoard)
console.log(queenThreat(generatedBoard))
//returns
;[
[0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
]
true
Possible Solution:
const generateBoard = function (whiteQueen, blackQueen) {
let result = []
// empty arrays
for (let i = 0; i < 8; i++) {
result.push([])
}
// blank board, insert 0's
for (let i = 0; i < 8; i++) {
while (result[i].length < 8) {
result[i].push(0)
}
}
// add queen positions
result[whiteQueen[0]][whiteQueen[1]] = 1
result[blackQueen[0]][blackQueen[1]] = 1
return result
}
const queenThreat = function (board) {
let queenMoves = []
// find the queens
for (let i = 0; i < 8; i++) {
for (let j = 0; j < 8; j++) {
if (board[i][j] === 1) queenMoves.push([i, j])
}
}
// detect a threat
if (queenMoves[0][0] - queenMoves[1][0] || queenMoves[0][1] - queenMoves[1][1]) {
// diagonal if any equal 0
return true
} else if (queenMoves[0][0] === queenMoves[1][0] || queenMoves[0][1] === queenMoves[1][1]) {
// horizontal and vertical
return true
} else {
return false
}
}
let whiteQueen = [0, 5]
let blackQueen = [5, 0]
let generatedBoard = generateBoard(whiteQueen, blackQueen)
console.log(generatedBoard) // see below
console.log(queenThreat(generatedBoard)) // false
// [ 0 1 2 3 4 5 6 7
// 0 [0, 0, 0, 0, 0, 1, 0, 0],
// 1 [0, 0, 0, 0, 0, 0, 0, 0],
// 2 [0, 0, 0, 0, 0, 0, 0, 0],
// 3 [0, 0, 0, 0, 0, 0, 0, 0],
// 4 [0, 0, 0, 0, 0, 0, 0, 0],
// 5 [1, 0, 0, 0, 0, 0, 0, 0],
// 6 [0, 0, 0, 0, 0, 0, 0, 0],
// 7 [0, 0, 0, 0, 0, 0, 0, 0]
// ]
Bouncy Castle
There's a new attraction at this year's Codeville festival. The organizers have decided to bring in several inflatable attractions, but they have no clue how to much blow them up. Each attraction needs to be pumped to a precise volume to achieve maximum festival fun!
The attractions are each made up of a combination of several different shapes: cones, spheres and prisms. For example, the giant inflatable duck is made up of two spheres (the body and head) and a cone (the beak) 🦆..
Each shape has a different calculation for determining volume, so we'll need to create a few functions that will help us figure out the volume of the various inflatable attractions.
In this challenge, we'll need to implement four functions.
The first three will calculate the volume of the individual shapes:
sphereVolume()
will calculate the volume of a sphere given a radiusconeVolume()
will calculate the volume of a cone given a radius and a heightprismVolume()
will calculate the volume of a prism given a height, a width, and a depth
The fourth function, totalVolume()
, will receive an array containing the different shapes that make up a single attraction. The totalVolume function should use the previous three functions to calculate the total volume of an attraction.
const PI = 3.14159
const sphereVolume = function (radius) {
return (4 / 3) * PI * radius ** 3
}
const coneVolume = function (radius, height) {
let base = PI * radius * radius
return (1 / 3) * base * height
}
const prismVolume = function (height, width, depth) {
return height * width * depth
}
const volumes = function (solid) {
switch (solid.type) {
case 'sphere':
return sphereVolume(solid.radius)
case 'cone':
return coneVolume(solid.radius, solid.height)
case 'prism':
return prismVolume(solid.height, solid.width, solid.depth)
default:
return 'Invalid solid type'
}
}
const totalVolume = function (solids) {
return solids.reduce((lastVolume, solid) => {
return lastVolume + volumes(solid)
}, 0)
}
const largeSphere = {
type: 'sphere',
radius: 40,
}
const smallSphere = {
type: 'sphere',
radius: 10,
}
const cone = {
type: 'cone',
radius: 3,
height: 5,
}
const duck = [largeSphere, smallSphere, cone]
console.log(sphereVolume(1))
console.log(4186 < sphereVolume(10) && sphereVolume(10) < 4189) // true
console.log(coneVolume(8, 18))
console.log(45 < coneVolume(3, 5) && coneVolume(3, 5) < 49) // true
console.log(prismVolume(9, 7, 13))
console.log(prismVolume(3, 4, 5) === 60) // true
console.log(272000 < totalVolume(duck) && totalVolume(duck) < 275000) // true
The Great Codeville Bake-off
The town festival is tomorrow and the organizers have only just realized that they've booked two bakeries to cater desserts, but only have one kitchen available. Instead of just choosing one bakery, let's help them figure out a way to work together.
Both of the bakeries have a specialty, so they each have a stock of specific ingredients.
Lucky for the festival organizers, we've found a recipe book in the town library with TONS of fusion recipes, unfortunately it's thousands of pages long and we don't have much time. Let's write a function that helps determine which recipes match the ingredients that both bakeries have in stock.
We need to complete a function called chooseRecipe()
, which will receive three parameters:
- An array of ingredients in stock at Bakery A
- An array of ingredients in stock at Bakery B
- An array of recipe objects.
Each recipe has a name
property(string) and an ingredient
property(array).
We are limiting our search to two ingredient recipes. We want to find a recipe that utilizes one ingredient from Bakery A and one from Bakery B.
Our chooseRecipe()
function should return the name of the correct recipe.
There will always be a single correct answer, and you will NOT need to consider special cases. For example, you do NOT need to worry about cases where one bakery has BOTH the ingredients for a recipe.
Example:
const chooseRecipe = function (bakeryA, bakeryB, recipes) {
// Code here!
}
let bakeryA = ['saffron', 'eggs', 'tomato paste', 'coconut', 'custard']
let bakeryB = ['milk', 'butter', 'cream cheese']
let recipes = [
{
name: 'Coconut Sponge Cake',
ingredients: ['coconut', 'cake base'],
},
{
name: 'Persian Cheesecake',
ingredients: ['saffron', 'cream cheese'],
},
{
name: 'Custard Surprise',
ingredients: ['custard', 'ground beef'],
},
]
console.log(chooseRecipe(bakeryA, bakeryB, recipes)) // outputs 'Persian Cheesecake'
bakeryA = ['potatoes', 'bay leaf', 'raisins']
bakeryB = ['red bean', 'dijon mustard', 'apples']
recipes = [
{
name: 'Potato Ganache',
ingredients: ['potatoes', 'chocolate'],
},
{
name: 'Sweet Fish',
ingredients: ['anchovies', 'honey'],
},
{
name: "Nima's Famous Dijon Raisins",
ingredients: ['dijon mustard', 'raisins'],
},
]
console.log(chooseRecipe(bakeryA, bakeryB, recipes)) // outputs 'Nima's Famous Dijon Raisins'
Possible Solution:
const chooseRecipe = function (bakeryA, bakeryB, recipes) {
let listA = ingredientCheck(bakeryA, recipes)
let listB = ingredientCheck(bakeryB, recipes)
return listA.filter((recipe) => recipe.includes(listB))
}
const ingredientCheck = function (bakery, recipes) {
let recipeList = []
for (let i = 0; i < recipes.length; i++) {
for (let j = 0; j < bakery.length; j++) {
if (recipes[i].ingredients.includes(bakery[j])) {
recipeList.push(recipes[i].name)
}
}
}
return recipeList
}
let bakeryA = ['saffron', 'eggs', 'tomato paste', 'coconut', 'custard']
let bakeryB = ['milk', 'butter', 'cream cheese']
let recipes = [
{
name: 'Coconut Sponge Cake',
ingredients: ['coconut', 'cake base'],
},
{
name: 'Persian Cheesecake',
ingredients: ['saffron', 'cream cheese'],
},
{
name: 'Custard Surprise',
ingredients: ['custard', 'ground beef'],
},
]
console.log(chooseRecipe(bakeryA, bakeryB, recipes)) // outputs 'Persian Cheesecake'
bakeryA = ['potatoes', 'bay leaf', 'raisins']
bakeryB = ['red bean', 'dijon mustard', 'apples']
recipes = [
{
name: 'Potato Ganache',
ingredients: ['potatoes', 'chocolate'],
},
{
name: 'Sweet Fish',
ingredients: ['anchovies', 'honey'],
},
{
name: "Nima's Famous Dijon Raisins",
ingredients: ['dijon mustard', 'raisins'],
},
]
console.log(chooseRecipe(bakeryA, bakeryB, recipes)) // outputs 'Nima's Famous Dijon Raisins'
Organizing Instructors
In this exercise, we will be given a list of instructors and we will create a single object to organize them based on their course.
Example:
const organizeInstructors = function (instructors) {
// Put your solution here
}
console.log(
organizeInstructors([
{ name: 'Samuel', course: 'iOS' },
{ name: 'Victoria', course: 'Web' },
{ name: 'Karim', course: 'Web' },
{ name: 'Donald', course: 'Web' },
])
)
// outcome
// {
// iOS: ["Samuel"],
// Web: ["Victoria", "Karim", "Donald"]
// }
console.log(
organizeInstructors([
{ name: 'Brendan', course: 'Blockchain' },
{ name: 'David', course: 'Web' },
{ name: 'Martha', course: 'iOS' },
{ name: 'Carlos', course: 'Web' },
])
)
// oputcome
// {
// Blockchain: ["Brendan"],
// Web: ["David", "Carlos"],
// iOS: ["Martha"]
// }
Create a function named organizeInstructors()
that will receive an array of instructor objects, and will return a new object that has the following format:
{
CourseName: [instructors]
}
Possible Solution:
const organizeInstructors = function (instructors) {
let result = {}
for (let item of instructors) {
let course = item.course
if (!result[course]) {
result[course] = [item.name]
} else {
result[course].push(item.name)
}
}
return result
}
console.log(
organizeInstructors([
{ name: 'Samuel', course: 'iOS' },
{ name: 'Victoria', course: 'Web' },
{ name: 'Karim', course: 'Web' },
{ name: 'Donald', course: 'Web' },
])
)
// outcome
// {
// iOS: ["Samuel"],
// Web: ["Victoria", "Karim", "Donald"]
// }
console.log(
organizeInstructors([
{ name: 'Brendan', course: 'Blockchain' },
{ name: 'David', course: 'Web' },
{ name: 'Martha', course: 'iOS' },
{ name: 'Carlos', course: 'Web' },
])
)
// oputcome
// {
// Blockchain: ["Brendan"],
// Web: ["David", "Carlos"],
// iOS: ["Martha"]
// }
JS Object From URL Encoded String
In this exercise, we will be given a url encoded string of key-value pairs, and we will have to turn it into a JavaScript object.
To safely send data in a URL, the data first has to be encoded to convert any special characters to URL safe characters. For this assignment we will only focus on the following URL encoding rules:
%20
represents a space character.- Key-value pairs are represented using an
=
character:key=value
- Multiple key-value pairs are separated using a
&
character:key1=value1&key2=value2
So the following URL encoded string:
city=Vancouver&weather=lots%20of%20rain
Could be converted to the following JavaScript object:
{
city: "Vancouver",
weather: "lots of rain"
}
Example:
const urlDecode = function (text) {
// Put your solution here
}
console.log(urlDecode('duck=rubber')) // { duck: "rubber" }
console.log(urlDecode('breed=cattle%20dog')) // { breed: "cattle dog" }
console.log(urlDecode('city=Vancouver&weather=lots%20of%20rain')) // { city: "Vancouver", weather: "lots of rain" }
console.log(urlDecode('city=Vancouver&weather=lots%20of%20rain').weather) // "lots of rain"
Possible Solution:
const urlDecode = function (text) {
let result = {}
let arrOfKeys = text.split('&')
for (let message of arrOfKeys) {
result[message.substr(0, message.indexOf('='))] = message
.substr(message.indexOf('=') + 1)
.replace(/[%20]/g, ' ')
}
return result
}
console.log(urlDecode('duck=rubber')) // { duck: "rubber" }
console.log(urlDecode('breed=cattle%20dog')) // { breed: "cattle dog" }
console.log(urlDecode('city=Vancouver&weather=lots%20of%20rain')) // { city: "Vancouver", weather: "lots of rain" }
console.log(urlDecode('city=Vancouver&weather=lots%20of%20rain').weather) // "lots of rain"
Taxicab Geometry
In this exercise, we will write an algorithm to help taxicabs determine how far away a destination is based on the directions given.
The following grid represents the streets of a city and the blue dot represents a taxi cab before it leaves for its destination.
The taxi driver is given a list of directions that tell her whether to turn left or right, and how many blocks to drive for. Every time the taxi driver has to turn left, she will make a 90° turn anticlockwise, and every time the taxi driver has to turn right, she will make a 90° turn clockwise.
Let's take a look at some example directions: ["right", 2, "left", 3, "left", 1]
.
First the taxi driver must turn "right"
, then drive for 2
blocks.
Then the taxi driver must turn "left"
, and drive for 3
blocks.
Finally, the taxi driver must turn "left"
again, and drive for 1
block.
Now that the taxi driver is at her final destination, we can determine that she is 1 block east
and 3 blocks north
of where she started.
Examples:
const blocksAway = function (directions) {
// Put your solution here
}
console.log(blocksAway(['right', 2, 'left', 3, 'left', 1])) // {east: 1, north: 3}
console.log(blocksAway(['left', 1, 'right', 1, 'left', 1, 'right', 1, 'left', 1, 'right', 1])) // {east: 3, north: 3}
console.log(blocksAway(['left', 3, 'right', 1, 'right', 3, 'right', 1])) // {east: 0, north: 0}
Create a function named blocksAway()
that will receive an array of directions, and return an object that calculates how far north and east those directions will take someone.
The taxi driver will always start at the same position, in the most south west position on the grid. This means that the output will only need to specify an east and north position, since the taxi driver can only end up in these East and North of the starting point.
Possible Solution:
const blocksAway = function (directions) {
let finalLocation = {
east: 0,
north: 0,
}
let degrees = 0
for (let i = 0; i < directions.length; i += 2) {
if (directions[i] === 'right') {
if (degrees === 0 && i === 0) {
degrees += 0
finalLocation.east += directions[i + 1]
} else if (degrees === 0) {
degrees += 270
finalLocation.north -= directions[i + 1]
} else if (degrees === 90) {
degrees -= 90
finalLocation.east += directions[i + 1]
} else if (degrees === 180) {
degrees -= 90
finalLocation.north += directions[i + 1]
} else if (degrees === 270) {
degrees -= 90
finalLocation.east -= directions[i + 1]
}
}
if (directions[i] === 'left') {
if (degrees === 0) {
degrees += 90
finalLocation.north += directions[i + 1]
} else if (degrees === 90) {
degrees += 90
finalLocation.east -= directions[i + 1]
} else if (degrees === 180) {
degrees += 90
finalLocation.north -= directions[i + 1]
} else if (degrees === 270) {
degrees -= 270
finalLocation.north += directions[i + 1]
}
}
}
return finalLocation
}
console.log(blocksAway(['right', 2, 'left', 3, 'left', 1])) // {east: 1, north: 3}
console.log(blocksAway(['left', 1, 'right', 1, 'left', 1, 'right', 1, 'left', 1, 'right', 1])) // {east: 3, north: 3}
console.log(blocksAway(['left', 3, 'right', 1, 'right', 3, 'right', 1])) // {east: 0, north: 0}