Tidy project

This commit is contained in:
Joshua Seigler 2020-12-07 22:46:02 -05:00
parent 20b8d44de1
commit abca4965a3
26 changed files with 2315 additions and 465 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
node_modules/

14
README.md Normal file
View file

@ -0,0 +1,14 @@
# Rockstar Playground
## Purpose
To make it easy to develop Rockstar solutions to Advent of Code style problems (with an input file and no interactivity).
## Setup
`npm install`
## Usage
`node start <trackname>`
Rock source code named `<trackname>.rock` will be used first from the `lyrics` folder, or else from the `contracts` folder (intended for un-poetic works in progress). File input is expected as `<trackname>.txt` in the `music` folder.
### Development
`npx nodemon start <trackname>` will re-run the program whenever it is altered.

6
contracts/2020-02.rock Normal file
View file

@ -0,0 +1,6 @@
Rock Input
Listen to Line
Until Line is gone
Rock Input with Line
Listen to Line
(end until)

3
music/2020-02.txt Normal file
View file

@ -0,0 +1,3 @@
1-3 a: abcde
1-3 b: cdefg
2-9 c: ccccccccc

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

@ -1,16 +0,0 @@
{
"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"
}
}
}
}

View file

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

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

@ -1,20 +0,0 @@
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
View file

@ -1,53 +0,0 @@
[![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
View file

@ -1,14 +0,0 @@
'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');

View file

@ -1,34 +0,0 @@
{
"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
View file

@ -1,159 +0,0 @@
'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

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

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

View file

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

View file

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

View file

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

Binary file not shown.

View file

@ -1,132 +0,0 @@
'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();
})

2264
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -10,5 +10,8 @@
"license": "MIT",
"dependencies": {
"n-readlines": "^1.0.1"
},
"devDependencies": {
"nodemon": "^2.0.6"
}
}

View file

@ -1,26 +1,36 @@
const trackNum = process.argv[2];
if (!trackNum) { console.error('Usage: node start <daynumber>'); process.exit(1); }
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 satriani = require('./rockstar/satriani/satriani.js')
const path = require('path')
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 rockstar = new satriani.Interpreter()
const source = path.normalize(
`${
fs.existsSync(path.normalize(`lyrics/${trackNum}.rock`))
? 'lyrics'
: 'contracts'
}/${trackNum}.rock`)
const program = fs.readFileSync(source, { encoding: 'utf8', flag: 'r' })
const inputByLine = new lineByLine(
path.normalize(`music/${trackNum}.txt`),
{ encoding: 'utf8', flag: 'r' }
)
const getNextInputLineAscii = () => {
const next = inputByLine.next();
const next = inputByLine.next()
if (next === false) {
return null;
return null
} else {
return next.toString('ascii');
return next.toString('ascii')
}
}
const ast = rockstar.parse(program);
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))
// console.log(JSON.stringify(ast, null, 2))
const output = console.log
const result = rockstar.run(ast, getNextInputLineAscii, output)
if (result) console.log(result);
if (result) console.log(result)