Skip to content

Commit dfffb43

Browse files
feat(2018 day-03): rewrite to use iterators over nested array storage
1 parent 3b78527 commit dfffb43

File tree

5 files changed

+139
-102
lines changed

5 files changed

+139
-102
lines changed

2018/day-03/claims.js

Lines changed: 53 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,75 @@
11
var _conflicts = []
22
var _claims = []
3+
var _cloth = []
34

45
/**
5-
* Check if a value is within the designated range (inclusive)
6-
* @param {number} s1 start of first range
7-
* @param {number} e1 end of first range
8-
* @param {number} s2 start of first range
9-
* @param {number} e2 end of first range
6+
* Generates an empty matrix of X columns and Y rows
107
*/
11-
const _isOverlap = (s1, e1, s2, e2) => {
12-
return Math.max(s1, e1) <= Math.min(s2, e2)
8+
const emptyMatrix = (x, y) => {
9+
return Array(x).fill().map(() => Array(y).fill())
10+
}
11+
12+
const resetState = () => {
13+
_cloth = emptyMatrix(1000, 1000)
14+
_conflicts = []
15+
_claims = []
1316
}
1417

1518
/**
16-
* Compares claims to see if they overlap
17-
* @param {Object} c1 claim to compare
18-
* @param {Object*} c2 claim to compare
19+
* Iterates through the cloth and tallies the conflicing points
1920
*/
20-
const _isOverlappingClaim = (c1, c2) => {
21-
// x range overlaps
22-
const x = _isOverlap(
23-
c1.x,
24-
c1.x + c1.width,
25-
c2.x,
26-
c2.x + c2.width
27-
)
28-
// y range overlaps
29-
const y = _isOverlap(
30-
c1.y,
31-
c1.y + c1.height,
32-
c2.y,
33-
c2.y + c2.height
34-
)
35-
return (x && y)
21+
const countConflicts = () => {
22+
let conflicts = 0
23+
for (let x = 0; x < _cloth.length; x++) {
24+
for (let y = 0; y < _cloth[x].length; y++) {
25+
if (isConflict(x, y)) {
26+
conflicts += 1
27+
}
28+
}
29+
}
30+
return conflicts
3631
}
3732

3833
/**
39-
* Iterates through the list of claims and checks to see if any cover the specified point
34+
* Checks a point in the cloth to see if it's already claimed
4035
* @param {number} x point x value
4136
* @param {number} y point y value
4237
* @returns {Boolean}
4338
*/
4439
const isClaimed = (x, y) => {
45-
const matches = _claims.filter((claim) =>
46-
x >= claim.x &&
47-
x <= claim.x + claim.width &&
48-
y >= claim.y &&
49-
y <= claim.y + claim.height
50-
)
51-
return (matches.length > 0)
40+
return (typeof _cloth[x][y] === 'object' && _cloth[x][y].length > 0)
5241
}
5342

54-
/**
55-
* Logs a conflict about multiple claims for a singel point
56-
* @param {number} x
57-
* @param {number} y
58-
* @param {Array} claims list of claim IDs
59-
*/
60-
const logConflict = (x, y, claims) => {
61-
let existing = _conflicts.find((c) => c.x === x && c.y === y)
62-
if (existing) {
63-
// Append new claims to existing list for this coordiante
64-
existing.claims = existing.claims.concat(claims)
65-
} else {
66-
// Record a new claim conflict
67-
_conflicts.push({ x: x, y: y, claims: claims })
43+
const isConflict = (x, y) => {
44+
return (isClaimed(x, y) && _cloth[x][y].length > 1)
45+
}
46+
47+
const claimPoint = (x, y, id) => {
48+
// Point doesn't have a claim yet
49+
if (typeof _cloth[x][y] === 'undefined') {
50+
_cloth[x][y] = [id]
51+
return
52+
}
53+
// Point has claims already
54+
if (typeof _cloth[x][y] === 'object') {
55+
_cloth[x][y].push(id)
56+
return
6857
}
58+
throw new Error('Tried to set a point with an unknown type')
6959
}
7060

61+
/**
62+
* Marks claimed points on the cloth
63+
* @param {Object} claim
64+
*/
7165
const makeClaim = (claim) => {
72-
// Check if there's any overlap with an exisiting claim
73-
const overlaps = _claims.filter((existing) => _isOverlappingClaim(existing, claim))
74-
if (overlaps.length > 0) {
75-
console.log(`Claim ${claim.id} overlaps ${overlaps.length} already existing claims.`)
76-
// step through individual points to log conflicts
77-
for (let x = claim.x; x < claim.x + claim.width; x++) {
78-
for (let y = claim.y; y < claim.y + claim.height; y++) {
79-
if (isClaimed(x, y)) {
80-
logConflict(x, y, [claim.id])
81-
}
82-
}
66+
for (let x = claim.x; x < claim.x + claim.width; x++) {
67+
for (let y = claim.y; y < claim.y + claim.height; y++) {
68+
claimPoint(x, y, claim.id)
8369
}
8470
}
85-
_claims.push(claim)
71+
72+
return _cloth
8673
}
8774

8875
/**
@@ -109,11 +96,15 @@ const parseClaim = (str) => {
10996
return claim
11097
}
11198

99+
resetState()
100+
112101
module.exports = {
113102
_conflicts,
114103
_claims,
104+
_cloth,
105+
countConflicts,
115106
isClaimed,
116-
logConflict,
117107
makeClaim,
118-
parseClaim
108+
parseClaim,
109+
resetState
119110
}

2018/day-03/claims.test.js

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
/* eslint-env mocha */
22
const expect = require('chai').expect
3-
let {
4-
_conflicts,
5-
_claims,
3+
var {
4+
_cloth,
5+
countConflicts,
66
isClaimed,
7-
logConflict,
87
makeClaim,
8+
resetState,
99
parseClaim
1010
} = require('./claims')
1111

12-
function _randomInt (min, max) {
13-
return Math.floor(Math.random() * (max - min + 1)) + min
14-
}
15-
1612
describe('--- Day 3: No Matter How You Slice It ---', () => {
1713
const claims = [
1814
'#123 @ 3,2: 5x4',
@@ -21,6 +17,14 @@ describe('--- Day 3: No Matter How You Slice It ---', () => {
2117
'#3 @ 5,5: 2x2'
2218
]
2319

20+
beforeEach(() => {
21+
resetState()
22+
})
23+
24+
afterEach(() => {
25+
resetState()
26+
})
27+
2428
describe('parseClaim()', () => {
2529
it('converts a claim into a readable object', () => {
2630
const claim = claims[0]
@@ -37,29 +41,27 @@ describe('--- Day 3: No Matter How You Slice It ---', () => {
3741
})
3842

3943
describe('makeClaim(claim)', () => {
40-
it('claims a piece of cloth for the specified elf', () => {
44+
it('marks the points on the cloth with the claim ID', () => {
4145
const claim = parseClaim(claims[0])
42-
makeClaim(claim)
43-
const actual = _claims.find((el) => el.x === claim.x && el.y === claim.y)
44-
expect(actual).to.deep.equal(claim)
46+
let result = makeClaim(claim)
47+
expect(result[1][1]).to.equal(undefined)
48+
expect(result[3][2]).to.deep.equal([123])
49+
expect(result[7][5]).to.deep.equal([123])
4550
})
4651

47-
it('logs an overlap when one is encountered', () => {
48-
const claim1 = claims[1]
49-
const claim2 = claims[2]
50-
makeClaim(claim1)
51-
makeClaim(claim2)
52-
expect(_conflicts)
53-
})
52+
it('marks the points that are overlapped', () => {
53+
let testClaims = claims.map(parseClaim)
54+
let result = _cloth
55+
for (let x = 1; x < claims.length; x++) {
56+
result = makeClaim(testClaims[x])
57+
}
5458

55-
// it('does not claim points outside the region', () => {
56-
// const claim = parseClaim(claims[0])
57-
// makeClaim(claim)
58-
// expect(_cloth.length).to.equal(claim.width)
59-
// _cloth.forEach((col) => {
60-
// expect(col.length).to.equal(claim.height)
61-
// })
62-
// })
59+
expect(result[0][0]).to.equal(undefined)
60+
expect(result[3][1]).to.deep.equal([2])
61+
expect(result[2][3]).to.deep.equal([1])
62+
expect(result[3][3]).to.deep.equal([1, 2])
63+
expect(result[5][5]).to.deep.equal([3])
64+
})
6365
})
6466

6567
describe('isClaimed(x,y)', () => {
@@ -76,19 +78,15 @@ describe('--- Day 3: No Matter How You Slice It ---', () => {
7678
})
7779
})
7880

79-
describe('logConflict(x,y,claims)', () => {
80-
it('records claim conflicts', () => {
81-
const x = _randomInt(0, 500)
82-
const y = _randomInt(0, 500)
83-
const id = _randomInt(0, 500)
84-
const expected = {
85-
x: x,
86-
y: y,
87-
claims: [id]
81+
describe('countConflicts()', () => {
82+
it('counts the number of points with conflicting claims', () => {
83+
let testClaims = claims.map(parseClaim)
84+
for (let x = 1; x < claims.length; x++) {
85+
makeClaim(testClaims[x])
8886
}
89-
logConflict(x, y, [id])
90-
const actual = _conflicts.find((c) => c.x === x && c.y === y)
91-
expect(actual).to.deep.equal(expected)
87+
const expected = 4
88+
const actual = countConflicts()
89+
expect(actual).to.equal(expected)
9290
})
9391
})
9492
})

2018/day-03/solution.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const claims = require('./claims')
2+
const fs = require('fs')
3+
const path = require('path')
4+
const filePath = path.join(__dirname, 'input.txt')
5+
const inputParser = require('../inputParser')
6+
7+
fs.readFile(filePath, { encoding: 'utf8' }, (err, data) => {
8+
if (err) throw err
9+
10+
const claimsList = inputParser.linesToArray(data)
11+
claimsList.forEach((claim) => claims.makeClaim(claims.parseClaim(claim)))
12+
const answer = claims.countConflicts()
13+
console.log(`-- Part 1 --`)
14+
console.log(`Answer: ${answer}`)
15+
})

2018/inputParser.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ function inputToArray (input) {
1010
return list
1111
}
1212

13+
function linesToArray (input) {
14+
// convert list into array of strings split by lines
15+
let list = input.split(/[\n]+/)
16+
// drop the empty entries created by extraneous whitespace
17+
list = list.filter((item) => item !== '')
18+
return list
19+
}
20+
1321
/**
1422
* Takes an input string and parses it into an array of integers
1523
* list can be newline or comma delineated
@@ -28,5 +36,6 @@ function parseData (input) {
2836

2937
module.exports = {
3038
inputToArray,
39+
linesToArray,
3140
parseData
3241
}

2018/inputParser.test.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-env mocha */
22
const expect = require('chai').expect
3-
const { inputToArray } = require('./inputParser')
3+
const { inputToArray, linesToArray } = require('./inputParser')
44

55
describe('inputParser', () => {
66
describe('inputToArray()', () => {
@@ -26,4 +26,28 @@ describe('inputParser', () => {
2626
expect(actual).to.deep.equal(expected)
2727
})
2828
})
29+
30+
describe('linesToArray()', () => {
31+
it('converts the contents of an input file to an array of strings, breaking on new lines', () => {
32+
const input = `
33+
abcdef
34+
bababc
35+
abbcde
36+
abcccd
37+
aabcdd
38+
abcdee
39+
ababab`
40+
const expected = [
41+
'abcdef',
42+
'bababc',
43+
'abbcde',
44+
'abcccd',
45+
'aabcdd',
46+
'abcdee',
47+
'ababab'
48+
]
49+
const actual = linesToArray(input)
50+
expect(actual).to.deep.equal(expected)
51+
})
52+
})
2953
})

0 commit comments

Comments
 (0)