diff --git a/src/assets/obviousAnswerSampleData.ts b/src/assets/obviousAnswerSampleData.ts new file mode 100644 index 0000000..3405f62 --- /dev/null +++ b/src/assets/obviousAnswerSampleData.ts @@ -0,0 +1,40 @@ +import { EventStream } from '../types'; + +export const obviousAnswerData: EventStream = [ + { + timestamp: 123123123, + eventType: 'newMessage', + }, + { + timestamp: 123123124, + eventType: 'newMessage', + }, + { + timestamp: 123123125, + eventType: 'screenshot', + }, + { + timestamp: 123123126, + eventType: 'screenshot', + }, + { + timestamp: 123123127, + eventType: 'screenshot', + }, + { + timestamp: 123123128, + eventType: 'screenshot', + }, + { + timestamp: 123123129, + eventType: 'screenshot', + }, + { + timestamp: 123123130, + eventType: 'newMessage', + }, + { + timestamp: 123123131, + eventType: 'newMessage', + } +] \ No newline at end of file diff --git a/src/index.test.ts b/src/index.test.ts index 9ad7234..14a71a8 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1,24 +1,22 @@ import { AppEvent } from './types' import { Region } from './models/region' import { retrieveScoreByEventType } from './utils/utils' +import { obviousAnswerData } from './assets/obviousAnswerSampleData' +import { HighestRegionLocator } from './models/highestRegionLocator' describe('Region', () => { - const appEvent: AppEvent = - { - timestamp: 123123123, - eventType: 'newMessage', - } - - it('adds an AppEvent to a region', () => { - const region = new Region() - region.addAppEvent(appEvent) - expect(region.regionEvents.length).toEqual(1) - }) + const appEvent: AppEvent[] = + [ + { + timestamp: 123123123, + eventType: 'newMessage', + } + ] it('totals up the score of a region', () => { const region = new Region() - region.addAppEvent(appEvent) + region.regionEvents = appEvent expect(region.getScore()).toEqual(1) }) }) @@ -36,4 +34,20 @@ describe('RetrieveScoreByEventType', () => { it('provides the correct score for event type: screenshot', () => { expect(retrieveScoreByEventType('screenshot')).toEqual(3) }) +}) + +describe('End-to-end EventStream Puzzler', () => { + it('the program should successfully locate the highest scoring region', () => { + // obviousAnswerData is sample data with an obvious answer if the region size is 5 + const highestRegionLocator = new HighestRegionLocator(obviousAnswerData) + const regionSize = 5 + const highestRegion = highestRegionLocator.locateHighestRegion(regionSize) + expect(highestRegion.getScore()).toEqual(15) + expect(highestRegion.regionEvents.length).toEqual(regionSize) + expect(highestRegion.regionEvents[0].timestamp).toEqual(123123125) + expect(highestRegion.regionEvents[1].timestamp).toEqual(123123126) + expect(highestRegion.regionEvents[2].timestamp).toEqual(123123127) + expect(highestRegion.regionEvents[3].timestamp).toEqual(123123128) + expect(highestRegion.regionEvents[4].timestamp).toEqual(123123129) + }) }) \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 41c166a..c49f4ee 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,17 @@ +import { sampleData } from './assets/sampleData' +import { HighestRegionLocator } from './models/highestRegionLocator' + const main = () => { - console.log('main is running') + const regionSize = 5 + + if (sampleData.length < regionSize) { + console.log(`EventStream must contain >= ${regionSize} events`) + } else { + const highestRegionLocator = new HighestRegionLocator(sampleData) + const highestRegion = highestRegionLocator.locateHighestRegion(regionSize) + console.log(`Highest scoring region found with score: ${highestRegion.getScore()}`) + console.log(highestRegion); + } } main() \ No newline at end of file diff --git a/src/models/highestRegionLocator.ts b/src/models/highestRegionLocator.ts index e4823c3..a40724f 100644 --- a/src/models/highestRegionLocator.ts +++ b/src/models/highestRegionLocator.ts @@ -8,8 +8,71 @@ export class HighestRegionLocator { this.eventStream = eventStream } - locateHighestRegion(): Region { - throw console.error('This is not implemented yet') - return new Region() + /* locateHighestRegion() Description: + * + * Given an EventStream, locateHighestRegion locates the highest scoring region + * of the EventStream, with the given size of regionSize. + * + * The region represents the highest scoring 'consecutive' events in the given EventStream. + * See src/utils/utils.ts for the scoring associated with each event type. + * + * The algorithm uses a 'sliding window' of size regionSize to calculate the + * score of the events in that region. Each time a higher scoring region, the + * that region is stored in the maxRegion variable. Once the end of the EventStream + * is reached, the highest scoring region is returned. + * + * For example, let 'e' be an event in the EventStream: + * + * e1 | + * e2 | + * e3 | <- first loop looks at these + * e4 | and updates the maxRegion + * e5 | if this region is higher + * e6 than the previous region + * e7 + * + * e1 + * e2 | + * e3 | <- second loop looks at these + * e4 | and updates the maxRegion + * e5 | if this region is higher + * e6 | than the previous region + * e7 + * + */ + locateHighestRegion(regionSize: number): Region { + let streamLength = this.eventStream.length + + // The first index to slice off of the eventSream + let startingIndex = 0; + + // The highest score calculated so far + let maxScore = 0; + + // A temporary region variable used to calculate the current region + let currentRegion = new Region(); + + // The highest scoring region so far + let maxRegion = new Region(); + + // Loop over the stream, moving the 'window' by one index each time + while (startingIndex + regionSize < streamLength) { + + // slice a subarray from the eventStream + // The current window is determined by the startingIndex + the region size + currentRegion.regionEvents = this.eventStream.slice(startingIndex, startingIndex + regionSize); + + // Get the score of the current region and compare it against the max score + let currentScore = currentRegion.getScore(); + if (currentScore > maxScore) { + maxScore = currentScore; + maxRegion = currentRegion; + } + // Reset the current region for the next loop + currentRegion = new Region(); + // Increment the startingIndex + startingIndex += 1; + } + return maxRegion; } } \ No newline at end of file diff --git a/src/models/region.ts b/src/models/region.ts index 1749eed..5d523f0 100644 --- a/src/models/region.ts +++ b/src/models/region.ts @@ -4,10 +4,9 @@ import { AppEvent } from '../types' export class Region { regionEvents: AppEvent[] = [] - addAppEvent(appEvent: AppEvent): void { - this.regionEvents.push(appEvent) - } - + /* getScore() Description: + * Totals the score for each event in this region + */ getScore(): number { let totalScore = 0 for (let appEvent of this.regionEvents) { @@ -15,4 +14,4 @@ export class Region { } return totalScore } -} \ No newline at end of file +}