-
Notifications
You must be signed in to change notification settings - Fork 0
/
urinal-selection.js
109 lines (92 loc) · 3.17 KB
/
urinal-selection.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// See "Proper Urinal Etiquette" video to understand this algorithm.
const urinalToUse = whetherEachUrinalIsOccupied => {
const numberOfUrinals = whetherEachUrinalIsOccupied.length
if ( numberOfUrinals === 0) {
return []
}
const maxUrinalsForThisFunction = 35 // due to internal representation
if (numberOfUrinals > maxUrinalsForThisFunction) {
throw new TooManyUrinals()
}
const urinalSituation = whetherEachUrinalIsOccupied.map(urinalDigit).join("")
return urinalChoice(urinalSituation)
}
function TooManyUrinals() {
this.message = "There are too many urinals in the situation.";
this.name = "TooManyUrinals";
}
const urinalDigit = (isTaken, index) => {
const unoccupiedDigit = "."
const oneBasedIndex = index + 1
const baseThirtySixDigitForOccupied =
oneBasedIndex <= 9 ? oneBasedIndex : String.fromCharCode(oneBasedIndex + 87)
return isTaken ? baseThirtySixDigitForOccupied : unoccupiedDigit
}
const urinalChoice = urinalSituation => {
const allUrinalsAreOpen = [].every.call(urinalSituation, digit => digit === ".")
if (allUrinalsAreOpen) {
const oneLessThanNumberOfUrinals = urinalSituation.length - 1
const anyUrinalButLast = oneThrough(oneLessThanNumberOfUrinals)
return anyUrinalButLast
}
if (urinalSituation.length = 5) {
return urinalChoiceFromVideo(urinalSituation)
}
return urinalChoiceInOtherCases(urinalSituation)
}
const oneThrough = max => {
let tempArray = new Array(max)
tempArray.fill(1)
return tempArray.map((_, index) => index + 1)
}
const urinalChoiceFromVideo = situation => {
if (matchesPattern("1*.4.", situation)
|| matchesPattern("*2..5", situation)) {
return [3]
}
if (matchesPattern("1.3.5", situation)
|| matchesPattern("...4*", situation)) {
return [2]
}
if (matchesPattern(".23..", situation)) {
return [1, 5]
}
return urinalChoiceInOtherCases(situation)
}
const matchesPattern = (pattern, situation) => {
for (let i = 1; i <= pattern.length; i++) {
if (pattern.charAt(i-1) === "*") {
continue
}
if (pattern.charAt(i-1) === situation.charAt(i-1)) {
continue
}
return false
}
return true
}
const urinalChoiceInOtherCases = situation => {
const urinalFreeOfNeighbors = firstOpenSlotWithoutNeighbors(situation)
if (urinalFreeOfNeighbors != -1) {
return [urinalFreeOfNeighbors]
}
const firstOpenUrinal = situation.indexOf(".") + 1
return [firstOpenUrinal]
}
const firstOpenSlotWithoutNeighbors = urinalSituation => {
for (let slot = 0; slot < urinalSituation.length; slot++) {
let leftSide = slot - 1
let rightSide = slot + 1
if (urinalSituation.charAt(slot) !== ".") {
continue
} else if (leftSide >= 0 && urinalSituation.charAt(leftSide) !== ".") {
continue
} else if (rightSide < urinalSituation.length && urinalSituation.charAt(rightSide) !== ".") {
continue
} else {
return slot + 1
}
}
const noOpenSlotCode = -1
return noOpenSlotCode
}