diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..687440b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version, created by Stagehand diff --git a/README.md b/README.md index 396bf9b..2c1b8d2 100644 --- a/README.md +++ b/README.md @@ -1 +1,6 @@ -rules-of-living +# rules_of_living + +An absolute bare-bones web app. + +Created from templates made available by Stagehand under a BSD-style +[license](https://github.com/dart-lang/stagehand/blob/master/LICENSE). diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..97f0908 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,15 @@ +analyzer: + strong-mode: true +# exclude: +# - path/to/excluded/files/** + +# Lint rules and documentation, see http://dart-lang.github.io/linter/lints +linter: + rules: + - cancel_subscriptions + - hash_and_equals + - iterable_contains_unrelated_type + - list_remove_unrelated_type + - test_types_in_equals + - unrelated_type_equality_checks + - valid_regexps diff --git a/lib/App.dart b/lib/App.dart new file mode 100644 index 0000000..1705823 --- /dev/null +++ b/lib/App.dart @@ -0,0 +1,70 @@ +import 'dart:html' as html; + +import 'package:rules_of_living/Cell.dart'; +import 'package:rules_of_living/Grid.dart'; + +class App { + // Elapsed Time Counter - useful for Safety Timeout + Stopwatch _elapsed = new Stopwatch(); + + // Game Tick Rate - *does* impact game speed + final int _MS_PER_STEP = 1000 ~/ 1; + + // Max Frame (i.e. Rendering) rate - does *not* impact game speed + final int _MS_PER_FRAME = 1000 ~/ 1; + + // ms stuck in updateloop after which game will declare itself unresponsive + final int SAFETY_TIMEOUT = 1000; + + num _updateLag = 0.0; + num _drawLag = 0.0; + + + final html.CanvasElement canvas; + final Grid grid = new Grid(20,20); + final List> map = new Grid(20, 20).map; + + App(this.canvas); + + void process(num now) { + _drawLag = now; + _updateLag += _drawLag; + _elapsed.reset(); + + while (_updateLag >= _MS_PER_STEP) { + if (_elapsed.elapsedMilliseconds > SAFETY_TIMEOUT) { + // TODO stub - give warning etc when this occurs + break; + } + update(); + _updateLag -= _MS_PER_STEP; + } + + if (_drawLag >= _MS_PER_FRAME) { + render(_updateLag / _MS_PER_STEP); + _drawLag = 0; + } + } + + void update() { + grid.update(); + } + + + void render([num interp]) { + html.CanvasRenderingContext2D ctx = canvas.getContext('2d'); + int brickW = (canvas.width ~/ map[0].length); + int brickH = (canvas.height ~/ map.length); + ctx.clearRect(0, 0, canvas.width, canvas.height); + for (int y = 0; y < map.length; y++) { + for (int x = 0; x < map[y].length; x++) { + Cell c = map[y][x]; + if (c.state == true) + ctx.setFillColorRgb(155, 155, 255); + else + ctx.setFillColorRgb(0, 0, 0); + ctx.fillRect(x * brickW, y * brickH, brickW, brickH); + } + } + } +} \ No newline at end of file diff --git a/lib/Cell.dart b/lib/Cell.dart new file mode 100644 index 0000000..2509733 --- /dev/null +++ b/lib/Cell.dart @@ -0,0 +1,23 @@ +import 'package:rules_of_living/Rule.dart'; + +class Cell { + bool state; + List surviveRules = new List(); + List birthRules = new List(); + + Cell([bool state = false]) : this.state = state; + + void update(int neighbors) { + bool newState = false; + if (state == true) { + surviveRules.forEach((Rule rule) { + if (rule.evaluate(neighbors) == true) newState = true; + }); + } else { + birthRules.forEach((Rule rule) { + if (rule.evaluate(neighbors) == true) newState = true; + }); + } + state = newState; + } +} diff --git a/lib/Grid.dart b/lib/Grid.dart new file mode 100644 index 0000000..cd47a83 --- /dev/null +++ b/lib/Grid.dart @@ -0,0 +1,63 @@ +import 'package:rules_of_living/Cell.dart'; +import 'package:rules_of_living/Rule.dart'; + +class Grid { + final int w; + final int h; + final List> map; + + Grid(int w, int h) + : this.w = w, + this.h = h, + this.map = new List() { + map.addAll(_buildGrid(w, h)); + + map[5][5].state = true; + } + + List> _buildGrid(int w, int h) { + List> grid = new List(h); + Rule threeTrue = new Rule((int n) { + if(n==3) return true; + else return false; + }); + Rule twoTrue = new Rule((int n) { + if(n==2) return true; + else return false; + }); + + for (int y = 0; y < h; y++) { + grid[y] = new List(w); + for (int x = 0; x < w; x++) { + // GIVES RULES FOR CONWAY GAME OF LIFE BY DEFAULT S23/B3 + Cell cell = new Cell(); + cell.surviveRules.add(twoTrue); + cell.surviveRules.add(threeTrue); + cell.birthRules.add(twoTrue); + + grid[y][x] = new Cell(); + } + } + return grid; + } + + void update() { + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + // DEFAULTS TO CONWAY GAME OF LIFE RANGE OF ONE + map[y][x].update( getNeighbors(x, y, 1) ); + } + } + } + + int getNeighbors(int x, int y, int range) { + int count = 0; + for (int iy = y - range ~/ 2; iy < iy + range / 2; iy++) { + for (int ix = x - range ~/ 2; ix < ix + range / 2; ix++) { + if (iy > 0 && iy < map.length && ix > 0 && ix < map[iy].length && + map[iy][ix].state == true) count++; + } + } + return count; + } +} diff --git a/lib/Rule.dart b/lib/Rule.dart new file mode 100644 index 0000000..3a5eb1a --- /dev/null +++ b/lib/Rule.dart @@ -0,0 +1,5 @@ +class Rule { + final Function evaluate; + + Rule(this.evaluate); +} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..0bffd9e --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,16 @@ +name: rules_of_living +description: An absolute bare-bones web app. +# version: 1.0.0 +#homepage: https://www.example.com +#author: marty + +environment: + sdk: '>=2.0.0-dev.66.0 <2.0.0' + +#dependencies: +# path: ^1.4.1 + +dev_dependencies: + build_runner: ^0.9.0 + build_web_compilers: ^0.4.0 + test: ^1.2.0 diff --git a/test/dart_test.dart b/test/dart_test.dart new file mode 100644 index 0000000..c4ff6af --- /dev/null +++ b/test/dart_test.dart @@ -0,0 +1,12 @@ +import 'package:test/test.dart'; +import 'dart:html' as html; + +void main() { + test("dart_test works", () { + expect(4+4, equals(8)); + }); + + test("dart_test works with the browser", () { + expect(html.Document, equals(isNotNull)); + }); +} \ No newline at end of file diff --git a/web/favicon.ico b/web/favicon.ico new file mode 100644 index 0000000..7ba349b Binary files /dev/null and b/web/favicon.ico differ diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..b0bc65e --- /dev/null +++ b/web/index.html @@ -0,0 +1,22 @@ + + + + + + + + + rules_of_living + + + + + + + +
+ +
+ + + diff --git a/web/main.dart b/web/main.dart new file mode 100644 index 0000000..8d236aa --- /dev/null +++ b/web/main.dart @@ -0,0 +1,19 @@ +import 'dart:html' as html; + +import 'package:rules_of_living/App.dart'; + + +html.CanvasElement el; +App engine; + +void main() { + el = new html.CanvasElement(width: 500, height: 500); + html.querySelector('#output').append(el); + engine = new App(el); + html.window.animationFrame.then(animFrame); +} + +void animFrame(num now) { + engine.process(now); + html.window.animationFrame.then(animFrame); +} diff --git a/web/styles.css b/web/styles.css new file mode 100644 index 0000000..cc035c9 --- /dev/null +++ b/web/styles.css @@ -0,0 +1,14 @@ +@import url(https://fonts.googleapis.com/css?family=Roboto); + +html, body { + width: 100%; + height: 100%; + margin: 0; + padding: 0; + font-family: 'Roboto', sans-serif; +} + +#output { + padding: 20px; + text-align: center; +}