aboutsummaryrefslogtreecommitdiff
path: root/challenge-127/iangoodnight/javascript/ch-2.js
blob: 0a5012f346604b456756bef31e336e9f370eeeb2 (plain)
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#!/usr/bin/env node

/**
 * Task #2 > Conflict Intervals
 * ============================
 *
 * You are given a list of intervals.
 * Write a script to find out if the current interval conflicts with any of the
 * previous intervals.
 *
 * EXAMPLE
 * Input: const intervals = [[1, 4], [3, 5], [6, 8], [12, 13], [3, 20]];
 * Output: [[3, 5], [3, 20]]
 *
 *   - The 1st interval [1, 4] does not have any previous intervals to compare
 *     with, so skip it.
 *   - The 2nd interval [3, 5] does conflict with previous interval [1, 4].
 *   - The 3rd interval [6, 8] does not conflict with any of the previous
 *     intervals [1, 4] and [3, 5], so skip it.
 *   - The 4th interval [12, 13] again does not conflict with any previous
 *     intervals [1, 4], [3, 5], or [6, 8] so skip it.
 *   - The 5th interval [3, 20] conflicts with the first interval [1, 4].
 *
 * Input: const intervals = [[3, 4], [5, 7], [6, 9], [10, 12], [13, 15]];
 * Output: [[6, 9]];
 **/

'use strict';

/**
 * Built-in Node dependencies
 **/

const fs = require('fs');

const path = require('path');

/**
 * Here, the function to test our intervals (PWC solution)
 **/

function findConflictIntervals(intervals = [[]]) {
  if (!Array.isArray(intervals)) return 'Input must be an 2-dimensional array';
  const [conflicts, ] = intervals.reduce(([conflicts, passed], [ a1, a2 ]) => {
    const start = a1 < a2 ? a1: a2;

    const end = start === a1 ? a2: a1;

    if (passed.length === 0) {
      passed.push([start, end]);
      return [conflicts, passed];
    }
    const conflict = passed.reduce((isConflict, [ b1, b2 ]) => {
      if (
        (start >= b1 && start <= b2) ||
        (end >= b1 && end <= b2) ||
        (start <= b1 && end >= b2)
      ) {
        return true;
      };
      return isConflict;
    }, false);
    if (conflict) {
      conflicts.push([start, end]);
    } else {
      passed.push([start, end]);
    }
    return [conflicts, passed]
  }, [[], []]);
  return conflicts;
}

/**
 * Followed by some utilities to test our solution
 **/


const isFile = (filePath) => fs.lstatSync(filePath).isFile();

const isDirectory = (filePath) => fs.lstatSync(filePath).isDirectory();

function parseTestCase(filePath = '') {
  try {
    const data = fs.readFileSync(filePath, 'utf8');

    const { input, output } = JSON.parse(data);

    return { input, output };
  } catch (err) {
    console.log(
      'Problems parsing text files. Is the JSON properly formatted?',
      err
    );
  }
}

function sortIntervals(intervalsArr = [[]]) {
  const intervalsSorted = intervalsArr.map(([x, y]) => {
    return x > y ? [x, y]: [y, x];
  });
  intervalsSorted.sort(([a1, a2], [b1, b2]) => {
    if (a1 === b1) return b1 < b2 ? -1: b1 === b2 ? 0: 1;
    if (a1 < b1) return -1;
    return 1;
  });
  return intervalsSorted;
}

function compareIntervalSets(set1 = [[]], set2 = [[]]) {
  if (!Array.isArray(set1) || !Array.isArray(set2)) return false;
  if (set1.length !== set2.length) return false;
  const set1Sorted = sortIntervals(set1);

  const set2Sorted = sortIntervals(set2);

  return set1Sorted.reduce((equal, [a1, a2], idx) => {
    const [ b1, b2 ] = set2Sorted[idx];

    return equal && a1 === b1 && a2 === b2;
  }, true);
}

function assertConflictIntervals(input = [[]], output = [[]], filePath = '') {
  const conflicts = findConflictIntervals(input);

  const passed = compareIntervalSets(conflicts, output);

  const testPath = filePath === '' ? '' : `${filePath}: `;

  if (passed) {
    return console.log(`${testPath}\x1b[32m%s\x1b[0m`, 'Passed \u2690');
  }
  return console.log(`${testPath}\x1b[31m%s\x1b[0m`, 'Failed \u2715');
}

/**
 * And, our test runner
 **/

(function main() {
  const testPath = process.argv[2] || '../test_cases/ch2';

  try {
    if (isFile(testPath)) {
      const { input, output } = parseTestCase(testPath);

      return assertConflictIntervals(input, output, testPath);
    }
    if (isDirectory(testPath)) {
      fs.readdirSync(testPath).map(fileName => {
        const filePath = path.join(testPath, fileName);

        const { input, output } = parseTestCase(filePath);

        assertConflictIntervals(input, output, filePath);
      });
      return;
    }
    return 'No tests found';
  } catch (error) {
    console.log('Something went wrong: ', error);
  }
})();