running rockstar on input

This commit is contained in:
Joshua Seigler 2020-12-06 15:26:29 -05:00
commit 0f5c35af68
24 changed files with 536 additions and 0 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "rockstar"]
path = rockstar
url = https://github.com/RockstarLang/rockstar

6
inputs/01.txt Normal file
View file

@ -0,0 +1,6 @@
1721
979
366
299
675
1456

5
lyrics/01.rock Normal file
View file

@ -0,0 +1,5 @@
Listen to Input
Until Input is wrong
Say Input
Listen to Input

16
node_modules/.package-lock.json generated vendored Normal file
View file

@ -0,0 +1,16 @@
{
"name": "advent-of-code-2020-rockstar",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"node_modules/n-readlines": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/n-readlines/-/n-readlines-1.0.1.tgz",
"integrity": "sha512-z4SyAIVgMy7CkgsoNw7YVz40v0g4+WWvvqy8+ZdHrCtgevcEO758WQyrYcw3XPxcLxF+//RszTz/rO48nzD0wQ==",
"engines": {
"node": ">=6.x.x"
}
}
}
}

6
node_modules/n-readlines/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,6 @@
language: node_js
os:
- linux
- osx
node_js:
- "6"

20
node_modules/n-readlines/LICENSE generated vendored Normal file
View file

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013 Liucw
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

53
node_modules/n-readlines/README.md generated vendored Normal file
View file

@ -0,0 +1,53 @@
[![Build Status](https://travis-ci.org/nacholibre/node-readlines.svg)](https://travis-ci.org/nacholibre/node-readlines)
# node-readlines
Reading file line by line may seem like a trivial problem, but in node, there is no straightforward way to do it. There are a lot of libraries using Transform Streams to achieve it, but it seems like a overkill, so I've wrote simple version using only the `filesystem` module of node. Note that this is *synchronous* library.
Install with
`npm install n-readlines`
---------------------------------------
## Documentation
### new readlines(filename, [options]);
### new readlines(fd, [options]);
**Arguments**
* `filename` - String path to the file you want to read from
* `fd` - File descriptor
* `options` - Object
* `readChunk` - Integer number of bytes to read at once. Default: 1024
* `newLineCharacter` - String new line character, only works with one byte characters for now. Default: `\n` which is `0x0a` hex encoded
`node-readlines` can handle files without newLineCharacter after the last line
---------------------------------------
### readlines.next()
Returns `buffer` with the line data without the `newLineCharacter` or `false` if end of file is reached.
---------------------------------------
### readlines.reset()
Resets the pointer and starts from the beginning of the file. This works only if the end is not reached.
---------------------------------------
### readlines.close()
Manually close the open file, subsequent `next()` calls will return false. This works only if the end is not reached.
---------------------------------------
## Example
```javascript
const lineByLine = require('n-readlines');
const liner = new lineByLine('./test/fixtures/normalFile.txt');
let line;
let lineNumber = 0;
while (line = liner.next()) {
console.log('Line ' + lineNumber + ': ' + line.toString('ascii'));
lineNumber++;
}
console.log('end of line reached');
```

14
node_modules/n-readlines/example.js generated vendored Normal file
View file

@ -0,0 +1,14 @@
'use strict';
const lineByLine = require('./readlines.js');
const liner = new lineByLine('./test/fixtures/normalFile.txt');
let line;
let lineNumber = 0;
while (line = liner.next()) {
console.log('Line ' + lineNumber + ': ' + line.toString('ascii'));
lineNumber++;
}
console.log('end of line reached');

34
node_modules/n-readlines/package.json generated vendored Normal file
View file

@ -0,0 +1,34 @@
{
"name": "n-readlines",
"version": "1.0.1",
"description": "Read file line by line without buffering the whole file in memory.",
"main": "./readlines.js",
"dependencies": {},
"repository": {
"type": "git",
"url": "http://github.com/nacholibre/node-readlines.git"
},
"keywords": [
"read",
"line",
"reader",
"linereader",
"readfile",
"linebyline",
"synchronous",
"sync",
"readline",
"readlines"
],
"engines": {
"node": ">=6.x.x"
},
"devDependencies": {
"tape": "^4.9.0"
},
"scripts": {
"test": "tape test/*.test.js"
},
"author": "Yoan Arnaudov <jonidev@gmail.com>",
"license": "MIT"
}

159
node_modules/n-readlines/readlines.js generated vendored Normal file
View file

@ -0,0 +1,159 @@
'use strict';
const fs = require('fs');
/**
* @class
*/
class LineByLine {
constructor(file, options) {
options = options || {};
if (!options.readChunk) options.readChunk = 1024;
if (!options.newLineCharacter) {
options.newLineCharacter = 0x0a; //linux line ending
} else {
options.newLineCharacter = options.newLineCharacter.charCodeAt(0);
}
if (typeof file === 'number') {
this.fd = file;
} else {
this.fd = fs.openSync(file, 'r');
}
this.options = options;
this.newLineCharacter = options.newLineCharacter;
this.reset();
}
_searchInBuffer(buffer, hexNeedle) {
let found = -1;
for (let i = 0; i <= buffer.length; i++) {
let b_byte = buffer[i];
if (b_byte === hexNeedle) {
found = i;
break;
}
}
return found;
}
reset() {
this.eofReached = false;
this.linesCache = [];
this.fdPosition = 0;
}
close() {
fs.closeSync(this.fd);
this.fd = null;
}
_extractLines(buffer) {
let line;
const lines = [];
let bufferPosition = 0;
let lastNewLineBufferPosition = 0;
while (true) {
let bufferPositionValue = buffer[bufferPosition++];
if (bufferPositionValue === this.newLineCharacter) {
line = buffer.slice(lastNewLineBufferPosition, bufferPosition);
lines.push(line);
lastNewLineBufferPosition = bufferPosition;
} else if (bufferPositionValue === undefined) {
break;
}
}
let leftovers = buffer.slice(lastNewLineBufferPosition, bufferPosition);
if (leftovers.length) {
lines.push(leftovers);
}
return lines;
};
_readChunk(lineLeftovers) {
let totalBytesRead = 0;
let bytesRead;
const buffers = [];
do {
const readBuffer = new Buffer(this.options.readChunk);
bytesRead = fs.readSync(this.fd, readBuffer, 0, this.options.readChunk, this.fdPosition);
totalBytesRead = totalBytesRead + bytesRead;
this.fdPosition = this.fdPosition + bytesRead;
buffers.push(readBuffer);
} while (bytesRead && this._searchInBuffer(buffers[buffers.length-1], this.options.newLineCharacter) === -1);
let bufferData = Buffer.concat(buffers);
if (bytesRead < this.options.readChunk) {
this.eofReached = true;
bufferData = bufferData.slice(0, totalBytesRead);
}
if (totalBytesRead) {
this.linesCache = this._extractLines(bufferData);
if (lineLeftovers) {
this.linesCache[0] = Buffer.concat([lineLeftovers, this.linesCache[0]]);
}
}
return totalBytesRead;
}
next() {
if (!this.fd) return false;
let line = false;
if (this.eofReached && this.linesCache.length === 0) {
return line;
}
let bytesRead;
if (!this.linesCache.length) {
bytesRead = this._readChunk();
}
if (this.linesCache.length) {
line = this.linesCache.shift();
const lastLineCharacter = line[line.length-1];
if (lastLineCharacter !== this.newLineCharacter) {
bytesRead = this._readChunk(line);
if (bytesRead) {
line = this.linesCache.shift();
}
}
}
if (this.eofReached && this.linesCache.length === 0) {
this.close();
}
if (line && line[line.length-1] === this.newLineCharacter) {
line = line.slice(0, line.length-1);
}
return line;
}
}
module.exports = LineByLine;

View file

@ -0,0 +1,2 @@
google.com
yahoo.com

3
node_modules/n-readlines/test/fixtures/bigLines.json generated vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

0
node_modules/n-readlines/test/fixtures/emptyFile.txt generated vendored Normal file
View file

View file

@ -0,0 +1 @@
no new line

View file

@ -0,0 +1,3 @@
google.com
yahoo.com
yandex.ru

View file

@ -0,0 +1,2 @@
hello
hello2

View file

@ -0,0 +1,5 @@
hello
hello4
hello2
hello3

BIN
node_modules/n-readlines/test/fixtures/withNULL.txt generated vendored Normal file

Binary file not shown.

132
node_modules/n-readlines/test/readlines.test.js generated vendored Normal file
View file

@ -0,0 +1,132 @@
'use strict';
const lineByLine = require('../readlines.js');
const path = require('path');
const test = require('tape');
test('should get all lines', (t) => {
const liner = new lineByLine(path.resolve(__dirname, 'fixtures/twoLineFile.txt'));
t.equals(liner.next().toString('ascii'), 'hello', 'line 0: hello');
t.equals(liner.next().toString('ascii'), 'hello2', 'line 1: hello2');
t.equals(liner.next(), false, 'line 3: false');
t.equals(liner.next(), false, 'line 4: false');
t.equals(liner.fd, null, 'fd null');
t.end();
});
test('should get all lines even if the file doesnt end with new line', (t) => {
const liner = new lineByLine(path.resolve(__dirname, 'fixtures/badEndFile.txt'));
t.equals(liner.next().toString('ascii'), 'google.com', 'line 0: google.com');
t.equals(liner.next().toString('ascii'), 'yahoo.com', 'line 1: yahoo.com');
t.equals(liner.next(), false, 'line 3: false');
t.equals(liner.fd, null, 'fd is null');
t.end();
});
test('should get all lines if there is no new lines', (t) => {
const liner = new lineByLine(path.resolve(__dirname, 'fixtures/noNewLinesFile.txt'));
t.equals(liner.next().toString('ascii'), 'no new line', 'line 0: no new line');
t.equals(liner.next(), false, 'line 1: false');
t.equals(liner.fd, null, 'fd is null');
t.end();
});
test('should handle empty files', (t) => {
const liner = new lineByLine(path.resolve(__dirname, 'fixtures/emptyFile.txt'));
t.equals(liner.next(), false, 'line 0: false');
t.equals(liner.fd, null, 'line 0: false');
t.end();
});
test('should read right between two chunks', (t) => {
const liner = new lineByLine(path.resolve(__dirname, 'fixtures/normalFile.txt'), {
readChunk: 16
});
t.equals(liner.next().toString('ascii'), 'google.com', 'line 0: google.com');
t.equals(liner.next().toString('ascii'), 'yahoo.com', 'line 1: yahoo.com');
t.equals(liner.next().toString('ascii'), 'yandex.ru', 'line 2: yandex.ru');
t.equals(liner.next(), false, 'line 3: false');
t.equals(liner.fd, null, 'fs is null');
t.end();
});
test('should read empty lines', (t) => {
const liner = new lineByLine(path.resolve(__dirname, 'fixtures/withEmptyLines.txt'));
t.equals(liner.next().toString('ascii'), 'hello', 'line 0: hello');
t.equals(liner.next().toString('ascii'), 'hello4', 'line 1: hello4');
t.equals(liner.next().toString('ascii'), '', 'line 2: ');
t.equals(liner.next().toString('ascii'), 'hello2', 'line 3: hello2');
t.equals(liner.next().toString('ascii'), 'hello3', 'line 4: hello3');
t.equals(liner.next(), false, 'line 5: false');
t.equals(liner.fd, null, 'fs is null');
t.end();
});
test('should reset and start from the beggining', (t) => {
const liner = new lineByLine(path.resolve(__dirname, 'fixtures/normalFile.txt'), {
readChunk: 16
});
t.equals(liner.next().toString('ascii'), 'google.com', 'line 0: google.com');
t.equals(liner.next().toString('ascii'), 'yahoo.com', 'line 1: yahoo.com');
liner.reset()
t.equals(liner.next().toString('ascii'), 'google.com', 'line 0: google.com');
t.equals(liner.next().toString('ascii'), 'yahoo.com', 'line 1: yahoo.com');
t.equals(liner.next().toString('ascii'), 'yandex.ru', 'line 2: yandex.ru');
t.equals(liner.next(), false, 'line 3: false');
t.equals(liner.fd, null, 'fd is null');
t.end();
});
test('should read big lines', (t) => {
const liner = new lineByLine(path.resolve(__dirname, 'fixtures/bigLines.json'));
t.ok(JSON.parse(liner.next()), 'line 0: valid JSON');
t.ok(JSON.parse(liner.next()), 'line 1: valid JSON');
t.ok(JSON.parse(liner.next()), 'line 2: valid JSON');
t.equals(liner.next(), false, 'line 3: false');
t.equals(liner.fd, null, 'fd is null');
t.end();
});
test('Non-Latin Char JSON', (t) => {
const liner = new lineByLine(path.resolve(__dirname, 'fixtures/eiffel.geojson'));
t.ok(JSON.parse(liner.next().toString()), 'line 0: valid JSON');
t.equals(liner.fd, null, 'fd is null');
t.end();
});
test('Manually Close', (t) => {
const liner = new lineByLine(path.resolve(__dirname, 'fixtures/normalFile.txt'));
t.equals(liner.next().toString(), 'google.com', 'line 0: google.com');
liner.close();
t.equals(liner.fd, null, 'fd is null');
t.equals(liner.next(), false, 'line after close: false');
t.end();
});
test('should correctly processes NULL character in lines', (t) => {
const liner = new lineByLine(path.resolve(__dirname, 'fixtures/withNULL.txt'));
t.equals(liner.next().toString(), 'line without null', 'line 0: line without null');
t.equals(liner.next().toString(), 'line wi'+String.fromCharCode(0)+'th null', 'line 1: line with null');
t.equals(liner.next().toString(), 'another line without null', 'line 2: another line without null');
t.equals(liner.fd, null, 'fd is null');
t.end();
})

30
package-lock.json generated Normal file
View file

@ -0,0 +1,30 @@
{
"name": "advent-of-code-2020-rockstar",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"n-readlines": "^1.0.1"
}
},
"node_modules/n-readlines": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/n-readlines/-/n-readlines-1.0.1.tgz",
"integrity": "sha512-z4SyAIVgMy7CkgsoNw7YVz40v0g4+WWvvqy8+ZdHrCtgevcEO758WQyrYcw3XPxcLxF+//RszTz/rO48nzD0wQ==",
"engines": {
"node": ">=6.x.x"
}
}
},
"dependencies": {
"n-readlines": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/n-readlines/-/n-readlines-1.0.1.tgz",
"integrity": "sha512-z4SyAIVgMy7CkgsoNw7YVz40v0g4+WWvvqy8+ZdHrCtgevcEO758WQyrYcw3XPxcLxF+//RszTz/rO48nzD0wQ=="
}
}
}

14
package.json Normal file
View file

@ -0,0 +1,14 @@
{
"name": "advent-of-code-2020-rockstar",
"version": "1.0.0",
"description": "Rockstar solutions to the 2020 Advent of Code",
"main": "start.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Joshua Seigler",
"license": "MIT",
"dependencies": {
"n-readlines": "^1.0.1"
}
}

1
rockstar Submodule

@ -0,0 +1 @@
Subproject commit 6d768a40e243801ac5350bcc8fe7124b7b402a87

26
start.js Normal file
View file

@ -0,0 +1,26 @@
const trackNum = process.argv[2];
if (!trackNum) { console.error('Usage: node start <daynumber>'); process.exit(1); }
const satriani = require('./rockstar/satriani/satriani.js');
const fs = require('fs');
const lineByLine = require('n-readlines');
const rockstar = new satriani.Interpreter();
const program = fs.readFileSync(`lyrics/${trackNum}.rock`, {encoding:'utf8', flag:'r'});
const inputByLine = new lineByLine(`inputs/${trackNum}.txt`, {encoding:'utf8', flag:'r'});
const getNextInputLineAscii = () => {
const next = inputByLine.next();
if (next === false) {
return null;
} else {
return next.toString('ascii');
}
}
const ast = rockstar.parse(program);
// Draw the abstract syntax tree (AST) to the console as a JSON object
//console.log(JSON.stringify(ast, null, 2))
const output = console.log
const result = rockstar.run(ast, getNextInputLineAscii, output)
if (result) console.log(result);