From 7b02834b54803cc6775998f343323cb5beef004b Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 7 Jul 2018 15:51:43 +0200 Subject: [PATCH 001/120] Add MIT License --- LICENSE.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index 86a595d..2246719 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,2 +1,21 @@ - -Copyright (C) 2018 +The MIT License (MIT) + +Copyright (c) 2018 Marty Oehme + +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. \ No newline at end of file From 964ba69c2e4e459cfc3a1046f559b49ab5002535 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 7 Jul 2018 20:02:13 +0200 Subject: [PATCH 002/120] Add Grid Starting Patterns can be common forms and random --- lib/src/Grid.dart | 61 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index b0d7e9f..72152d0 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -1,8 +1,14 @@ import 'dart:html' as html; +import 'dart:math' as math; import 'package:rules_of_living/src/Cell.dart'; import 'package:rules_of_living/src/Rule.dart'; +enum Pattern { + SpaceShip, + Blinker +} + class Grid { final int w; final int h; @@ -28,16 +34,54 @@ class Grid { // map[8][8].state = true; // SPACESHIP - setState(1 + 5, 0 + 5, true); - setState(2 + 5, 1 + 5, true); - setState(2 + 5, 2 + 5, true); - setState(1 + 5, 2 + 5, true); - setState(0 + 5, 2 + 5, true); +// setCellState(1 + 5, 0 + 5, true); +// setCellState(2 + 5, 1 + 5, true); +// setCellState(2 + 5, 2 + 5, true); +// setCellState(1 + 5, 2 + 5, true); +// setCellState(0 + 5, 2 + 5, true); + startingPattern(); print("Grid creation finished"); } - void setState(int x, int y, bool state) { + void startingPattern([Pattern pattern]) { + math.Random rng = new math.Random(); + var x = rng.nextInt(w~/3) + (w~/3); + var y = rng.nextInt(h~/3) + (h~/3); + switch (pattern) { + // Two blocks, offset + // ## + // ## + case Pattern.Blinker: + setCellState(x, y, true); + setCellState(x+1, y, true); + setCellState(x, y+1, true); + setCellState(x+1, y+1, true); + + setCellState(x+2, y+2, true); + setCellState(x+3, y+2, true); + setCellState(x+2, y+3, true); + setCellState(x+3, y+3, true); + break; + // A 'gliding' Spaceship + // # + // # + // ### + case Pattern.SpaceShip: + setCellState(1 + x, 0 + y, true); + setCellState(2 + x, 1 + y, true); + setCellState(2 + x, 2 + y, true); + setCellState(1 + x, 2 + y, true); + setCellState(0 + x, 2 + y, true); + break; + default: + for (var i = 0; i < rng.nextInt(20); i++) { + setCellState(x + rng.nextInt(10), y + rng.nextInt(10), true); + } + break; + } + } + void setCellState(int x, int y, bool state) { if (y < map.length && x < map[y].length) map[y][x].state = state; } @@ -70,8 +114,9 @@ class Grid { // GIVES RULES FOR CONWAY GAME OF LIFE BY DEFAULT S23/B3 Cell cell = new Cell(); // cell.surviveRules.add(twoTrue); - cell.surviveRules.add(coagSurvive); - cell.birthRules.add(coagBirth); + cell.surviveRules.add(threeTrue); + cell.surviveRules.add(twoTrue); + cell.birthRules.add(threeTrue); grid[y][x] = cell; } From 9816778d4bdf0cda7ed63bbd01f7f933f1e4b339 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 7 Jul 2018 20:35:04 +0200 Subject: [PATCH 003/120] Allow Defining x and y for Patterns --- lib/src/App.dart | 1 + lib/src/Grid.dart | 54 ++++++++++++++++------------------------------- 2 files changed, 19 insertions(+), 36 deletions(-) diff --git a/lib/src/App.dart b/lib/src/App.dart index a571dba..64bfde9 100644 --- a/lib/src/App.dart +++ b/lib/src/App.dart @@ -25,6 +25,7 @@ class App { App(this.canvas) { _elapsed.start(); + grid.startingPattern(); } void reset () { diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index 72152d0..f188ae9 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -22,65 +22,47 @@ class Grid { this.map = new List() { map.addAll(_buildGrid(w, h)); - // BLINKER -// map[5][5].state = true; -// map[5][6].state = true; -// map[6][5].state = true; -// map[6][6].state = true; -// -// map[7][7].state = true; -// map[7][8].state = true; -// map[8][7].state = true; -// map[8][8].state = true; - - // SPACESHIP -// setCellState(1 + 5, 0 + 5, true); -// setCellState(2 + 5, 1 + 5, true); -// setCellState(2 + 5, 2 + 5, true); -// setCellState(1 + 5, 2 + 5, true); -// setCellState(0 + 5, 2 + 5, true); - startingPattern(); - print("Grid creation finished"); } - void startingPattern([Pattern pattern]) { + void startingPattern({Pattern pattern, int x, int y}) { math.Random rng = new math.Random(); - var x = rng.nextInt(w~/3) + (w~/3); - var y = rng.nextInt(h~/3) + (h~/3); + int cx = x ?? rng.nextInt(w~/3) + (w~/3); + int cy = y ?? rng.nextInt(h~/3) + (h~/3); switch (pattern) { // Two blocks, offset // ## // ## case Pattern.Blinker: - setCellState(x, y, true); - setCellState(x+1, y, true); - setCellState(x, y+1, true); - setCellState(x+1, y+1, true); + setCellState(cx, cy, true); + setCellState(cx+1, cy, true); + setCellState(cx, cy+1, true); + setCellState(cx+1, cy+1, true); - setCellState(x+2, y+2, true); - setCellState(x+3, y+2, true); - setCellState(x+2, y+3, true); - setCellState(x+3, y+3, true); + setCellState(cx+2, cy+2, true); + setCellState(cx+3, cy+2, true); + setCellState(cx+2, cy+3, true); + setCellState(cx+3, cy+3, true); break; // A 'gliding' Spaceship // # // # // ### case Pattern.SpaceShip: - setCellState(1 + x, 0 + y, true); - setCellState(2 + x, 1 + y, true); - setCellState(2 + x, 2 + y, true); - setCellState(1 + x, 2 + y, true); - setCellState(0 + x, 2 + y, true); + setCellState(1 + cx, 0 + cy, true); + setCellState(2 + cx, 1 + cy, true); + setCellState(2 + cx, 2 + cy, true); + setCellState(1 + cx, 2 + cy, true); + setCellState(0 + cx, 2 + cy, true); break; default: for (var i = 0; i < rng.nextInt(20); i++) { - setCellState(x + rng.nextInt(10), y + rng.nextInt(10), true); + setCellState(cx + rng.nextInt(10), cy + rng.nextInt(10), true); } break; } } + void setCellState(int x, int y, bool state) { if (y < map.length && x < map[y].length) map[y][x].state = state; } From 4b35dbe5fc689c0401c0f846b062649cb5ac84fb Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 7 Jul 2018 20:47:23 +0200 Subject: [PATCH 004/120] Add Parameters for Dispersal and Amount of Cells --- lib/src/Grid.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index f188ae9..5649c6b 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -25,7 +25,7 @@ class Grid { print("Grid creation finished"); } - void startingPattern({Pattern pattern, int x, int y}) { + void startingPattern({Pattern pattern, int x, int y, int amount, int dispersal}) { math.Random rng = new math.Random(); int cx = x ?? rng.nextInt(w~/3) + (w~/3); int cy = y ?? rng.nextInt(h~/3) + (h~/3); @@ -56,8 +56,8 @@ class Grid { setCellState(0 + cx, 2 + cy, true); break; default: - for (var i = 0; i < rng.nextInt(20); i++) { - setCellState(cx + rng.nextInt(10), cy + rng.nextInt(10), true); + for (var i = 0; i < amount ?? rng.nextInt(20); i++) { + setCellState(cx + dispersal ?? rng.nextInt(10), cy + dispersal ?? rng.nextInt(10), true); } break; } From 34bdd1ae816f9bca3584b885e5c9aba4fe90e173 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 7 Jul 2018 20:49:02 +0200 Subject: [PATCH 005/120] Apply dartfmt --- lib/app_component.dart | 7 +++---- lib/src/App.dart | 10 ++++------ lib/src/Cell.dart | 4 ++-- lib/src/Grid.dart | 35 +++++++++++++++++------------------ lib/src/Rule.dart | 2 +- 5 files changed, 27 insertions(+), 31 deletions(-) diff --git a/lib/app_component.dart b/lib/app_component.dart index e5ece87..435b9aa 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -4,10 +4,9 @@ import 'dart:html' as html; import 'package:rules_of_living/src/App.dart'; @Component( - selector: 'my-app', - templateUrl: "app_component.html", - directives: [coreDirectives] -) + selector: 'my-app', + templateUrl: "app_component.html", + directives: [coreDirectives]) class AppComponent implements OnInit { var name = "World"; diff --git a/lib/src/App.dart b/lib/src/App.dart index 64bfde9..cfbc032 100644 --- a/lib/src/App.dart +++ b/lib/src/App.dart @@ -18,9 +18,8 @@ class App { num _updateLag = 0.0; num _drawLag = 0.0; - final html.CanvasElement canvas; - Grid grid = new Grid(100,100); + Grid grid = new Grid(100, 100); bool running = false; App(this.canvas) { @@ -28,13 +27,13 @@ class App { grid.startingPattern(); } - void reset () { + void reset() { grid = new Grid(100, 100); running = false; } void process(num now) { - _drawLag+= _elapsed.elapsedMilliseconds; + _drawLag += _elapsed.elapsedMilliseconds; _updateLag += _elapsed.elapsedMilliseconds; _elapsed.reset(); @@ -59,9 +58,8 @@ class App { grid.update(); } - void render([num interp]) { // print("rendering"); grid.render(canvas, interp); } -} \ No newline at end of file +} diff --git a/lib/src/Cell.dart b/lib/src/Cell.dart index 5301fb6..f472280 100644 --- a/lib/src/Cell.dart +++ b/lib/src/Cell.dart @@ -20,8 +20,8 @@ class Cell { void update(int neighbors) { if (state == true) { - surviveRules.forEach( (Rule rule) { - if(rule.evaluate(neighbors) == true) this.nextState = true; + surviveRules.forEach((Rule rule) { + if (rule.evaluate(neighbors) == true) this.nextState = true; }); } else { birthRules.forEach((Rule rule) { diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index 5649c6b..c03b413 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -4,10 +4,7 @@ import 'dart:math' as math; import 'package:rules_of_living/src/Cell.dart'; import 'package:rules_of_living/src/Rule.dart'; -enum Pattern { - SpaceShip, - Blinker -} +enum Pattern { SpaceShip, Blinker } class Grid { final int w; @@ -25,24 +22,25 @@ class Grid { print("Grid creation finished"); } - void startingPattern({Pattern pattern, int x, int y, int amount, int dispersal}) { + void startingPattern( + {Pattern pattern, int x, int y, int amount, int dispersal}) { math.Random rng = new math.Random(); - int cx = x ?? rng.nextInt(w~/3) + (w~/3); - int cy = y ?? rng.nextInt(h~/3) + (h~/3); + int cx = x ?? rng.nextInt(w ~/ 3) + (w ~/ 3); + int cy = y ?? rng.nextInt(h ~/ 3) + (h ~/ 3); switch (pattern) { // Two blocks, offset // ## // ## case Pattern.Blinker: setCellState(cx, cy, true); - setCellState(cx+1, cy, true); - setCellState(cx, cy+1, true); - setCellState(cx+1, cy+1, true); + setCellState(cx + 1, cy, true); + setCellState(cx, cy + 1, true); + setCellState(cx + 1, cy + 1, true); - setCellState(cx+2, cy+2, true); - setCellState(cx+3, cy+2, true); - setCellState(cx+2, cy+3, true); - setCellState(cx+3, cy+3, true); + setCellState(cx + 2, cy + 2, true); + setCellState(cx + 3, cy + 2, true); + setCellState(cx + 2, cy + 3, true); + setCellState(cx + 3, cy + 3, true); break; // A 'gliding' Spaceship // # @@ -57,12 +55,13 @@ class Grid { break; default: for (var i = 0; i < amount ?? rng.nextInt(20); i++) { - setCellState(cx + dispersal ?? rng.nextInt(10), cy + dispersal ?? rng.nextInt(10), true); + setCellState(cx + dispersal ?? rng.nextInt(10), + cy + dispersal ?? rng.nextInt(10), true); } break; } } - + void setCellState(int x, int y, bool state) { if (y < map.length && x < map[y].length) map[y][x].state = state; } @@ -82,11 +81,11 @@ class Grid { // DEBUG RULE TESTING FOR PATTERNS Rule coagSurvive = new Rule((int n) { - if (n==1) return true; + if (n == 1) return true; return false; }); Rule coagBirth = new Rule((int n) { - if (n==1) return true; + if (n == 1) return true; return false; }); diff --git a/lib/src/Rule.dart b/lib/src/Rule.dart index 3a5eb1a..723b4d0 100644 --- a/lib/src/Rule.dart +++ b/lib/src/Rule.dart @@ -2,4 +2,4 @@ class Rule { final Function evaluate; Rule(this.evaluate); -} \ No newline at end of file +} From bdc5dc1af14c0089fa2e3078c309432c5a9a83bb Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 7 Jul 2018 21:07:42 +0200 Subject: [PATCH 006/120] Add Message for App Failure --- lib/app_component.dart | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/app_component.dart b/lib/app_component.dart index 435b9aa..e559ab7 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -17,8 +17,13 @@ class AppComponent implements OnInit { @override void ngOnInit() { - canvas.context2D.setFillColorRgb(255, 0, 0); - canvas.context2D.fillRect(0, 0, 200, 150); + canvas.context2D.setFillColorRgb(200, 0, 0); + canvas.context2D.fillRect(0, 0, canvas.width, canvas.height); + canvas.context2D.setFillColorRgb(0, 255, 0); + canvas.context2D.fillText(''' + If you see this + the app is broken :( + ''', canvas.width/2, canvas.height/2); engine = new App(canvas); html.window.animationFrame.then(animFrame); From 2d2365e606c530bd113cb04b83465a5c0b9a537e Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 7 Jul 2018 21:42:07 +0200 Subject: [PATCH 007/120] Fix Simulation Reset not Replicating the Starting Pattern Now keeps the original parameters for the first pattern of a grid stored and can replicate them reliably. --- lib/src/Grid.dart | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index c03b413..c35bd16 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -12,6 +12,12 @@ class Grid { final List> map; bool _dirty = true; + int _startingSeed; + int _x; + int _y; + int _amount; + int _dispersal; + Pattern _pattern; Grid(int w, int h) : this.w = w, @@ -22,9 +28,21 @@ class Grid { print("Grid creation finished"); } - void startingPattern( - {Pattern pattern, int x, int y, int amount, int dispersal}) { - math.Random rng = new math.Random(); + void reset() { + map.setAll(0, _buildGrid(w, h)); + if(_startingSeed != null) addPattern(pattern: _pattern, dispersal: _dispersal,amount: _amount,seed: _startingSeed, x: _x, y: _y); + _dirty = true; + } + + void addPattern( + {Pattern pattern, int x, int y, int amount, int dispersal, int seed}) { + _startingSeed = seed ?? DateTime.now().millisecondsSinceEpoch; + math.Random rng = new math.Random(_startingSeed); + _x = x; + _y = y; + _amount = amount ?? rng.nextInt(20); + _dispersal = dispersal ?? 10; + _pattern = pattern; int cx = x ?? rng.nextInt(w ~/ 3) + (w ~/ 3); int cy = y ?? rng.nextInt(h ~/ 3) + (h ~/ 3); switch (pattern) { @@ -54,9 +72,14 @@ class Grid { setCellState(0 + cx, 2 + cy, true); break; default: - for (var i = 0; i < amount ?? rng.nextInt(20); i++) { - setCellState(cx + dispersal ?? rng.nextInt(10), - cy + dispersal ?? rng.nextInt(10), true); + int sanityCheck = 0; + for (var i = 0; i < (_amount); i++) { + sanityCheck++; + getCellState(cx, cy) + ? i-- + : setCellState(cx + rng.nextInt(_dispersal), + cy + rng.nextInt(_dispersal), true); + if (sanityCheck > 100 && sanityCheck > i*3) break; } break; } From c5b62e6c9f0369235791756dcb94f4c540f57dc2 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 7 Jul 2018 21:43:24 +0200 Subject: [PATCH 008/120] Fix Reset & Step not working on first click Rendering dirty flags were not updated accordingly, so the updates happened but were not pushed to be rendered. Added and moved additional dirty flag setters. --- lib/app_component.dart | 1 + lib/src/App.dart | 7 ++++--- lib/src/Grid.dart | 6 +++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/app_component.dart b/lib/app_component.dart index e559ab7..afce95f 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -44,6 +44,7 @@ class AppComponent implements OnInit { } void onResetClicked() { + engine.running = false; engine.reset(); } diff --git a/lib/src/App.dart b/lib/src/App.dart index cfbc032..8ab933a 100644 --- a/lib/src/App.dart +++ b/lib/src/App.dart @@ -24,12 +24,13 @@ class App { App(this.canvas) { _elapsed.start(); - grid.startingPattern(); + grid.addPattern(amount: 15, dispersal: 5); } void reset() { - grid = new Grid(100, 100); - running = false; +// grid = new Grid(100, 100); +// running = false; + grid.reset(); } void process(num now) { diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index c35bd16..5730461 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -89,6 +89,10 @@ class Grid { if (y < map.length && x < map[y].length) map[y][x].state = state; } + bool getCellState(int x, int y) { + if (y < map.length && x < map[y].length) return map[y][x].state; + } + List> _buildGrid(int w, int h) { print("grid being created"); List> grid = new List(h); @@ -133,13 +137,13 @@ class Grid { for (int x = 0; x < w; x++) { // DEFAULTS TO CONWAY GAME OF LIFE RANGE OF ONE map[y][x].update(getSurroundingNeighbors(x, y, 1)); - if (!_dirty && map[y][x].dirty) _dirty = true; } } 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].advanceState(); + if (!_dirty && map[y][x].dirty) _dirty = true; } } } From c5ed18f0adab03948df3f3ed43c43e7a6fb0a347 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 7 Jul 2018 22:02:04 +0200 Subject: [PATCH 009/120] Add Random Button Functionality Adds random pattern toward the center of the canvas. Does not delete anything. --- lib/app_component.dart | 5 ++++- lib/src/Grid.dart | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/app_component.dart b/lib/app_component.dart index afce95f..c23443e 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -48,5 +48,8 @@ class AppComponent implements OnInit { engine.reset(); } - void onRandomClicked() {} + void onRandomClicked() { + engine.running = false; + engine.grid.addPattern(); + } } diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index 5730461..062a78c 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -83,6 +83,7 @@ class Grid { } break; } + _dirty = true; } void setCellState(int x, int y, bool state) { From 8fc3f35321eaa1c56cc948da55aa106d4cdc8773 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sun, 8 Jul 2018 19:01:14 +0200 Subject: [PATCH 010/120] Add Edge Rendering with Toggle Button --- lib/app_component.dart | 4 ++++ lib/app_component.html | 1 + lib/src/Grid.dart | 13 +++++++++++++ 3 files changed, 18 insertions(+) diff --git a/lib/app_component.dart b/lib/app_component.dart index c23443e..2b54300 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -52,4 +52,8 @@ class AppComponent implements OnInit { engine.running = false; engine.grid.addPattern(); } + + void onEdgesClicked() { + engine.grid.switchEdgeRendering(); + } } diff --git a/lib/app_component.html b/lib/app_component.html index 366ce7b..d9e7dfa 100644 --- a/lib/app_component.html +++ b/lib/app_component.html @@ -17,4 +17,5 @@ Speed: + \ No newline at end of file diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index 062a78c..468d648 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -12,6 +12,8 @@ class Grid { final List> map; bool _dirty = true; + bool _renderEdges = true; + int _startingSeed; int _x; int _y; @@ -174,8 +176,14 @@ class Grid { 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++) { + if(_renderEdges) { + ctx.setStrokeColorRgb(100, 100, 100); + ctx.strokeRect(x * brickW, y * brickH, brickW, brickH); + } + Cell c = map[y][x]; if (c.state == true) ctx.setFillColorRgb(155, 155, 255); @@ -187,4 +195,9 @@ class Grid { _dirty = false; } + + void switchEdgeRendering([bool on]) { + _renderEdges = on ?? !_renderEdges; + _dirty = true; + } } From fb014ce5ac98dd74f412e734cc7c51b5b4715130 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sun, 8 Jul 2018 19:01:46 +0200 Subject: [PATCH 011/120] Shorten Heading --- lib/app_component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/app_component.html b/lib/app_component.html index d9e7dfa..d56c5d2 100644 --- a/lib/app_component.html +++ b/lib/app_component.html @@ -1,4 +1,4 @@ -

Cellular Automata - The Rules of Life

+

Cellular Automata

Ruleset: From 4074f49228a39aa0ef9fa4e6c2e0474de42ae5f1 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sun, 8 Jul 2018 19:03:48 +0200 Subject: [PATCH 012/120] Fix Missing return statement --- lib/src/Grid.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index 468d648..c8287f1 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -94,6 +94,7 @@ class Grid { bool getCellState(int x, int y) { if (y < map.length && x < map[y].length) return map[y][x].state; + return null; } List> _buildGrid(int w, int h) { From 3676264444178162bb7c514dafc6b516f6b74e70 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sun, 8 Jul 2018 19:05:11 +0200 Subject: [PATCH 013/120] dartfmt --- lib/src/Grid.dart | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index c8287f1..a25a50e 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -32,7 +32,14 @@ class Grid { void reset() { map.setAll(0, _buildGrid(w, h)); - if(_startingSeed != null) addPattern(pattern: _pattern, dispersal: _dispersal,amount: _amount,seed: _startingSeed, x: _x, y: _y); + if (_startingSeed != null) + addPattern( + pattern: _pattern, + dispersal: _dispersal, + amount: _amount, + seed: _startingSeed, + x: _x, + y: _y); _dirty = true; } @@ -81,7 +88,7 @@ class Grid { ? i-- : setCellState(cx + rng.nextInt(_dispersal), cy + rng.nextInt(_dispersal), true); - if (sanityCheck > 100 && sanityCheck > i*3) break; + if (sanityCheck > 100 && sanityCheck > i * 3) break; } break; } @@ -180,7 +187,7 @@ class Grid { for (int y = 0; y < map.length; y++) { for (int x = 0; x < map[y].length; x++) { - if(_renderEdges) { + if (_renderEdges) { ctx.setStrokeColorRgb(100, 100, 100); ctx.strokeRect(x * brickW, y * brickH, brickW, brickH); } From 9fb67d019437a489561a6c956fd6060c8b6ce9b9 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sun, 8 Jul 2018 19:08:40 +0200 Subject: [PATCH 014/120] Add return of new cell state to advanceState Function --- lib/src/Cell.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/src/Cell.dart b/lib/src/Cell.dart index f472280..b10142b 100644 --- a/lib/src/Cell.dart +++ b/lib/src/Cell.dart @@ -11,11 +11,15 @@ class Cell { Cell([bool state = false]) : this.state = state; - void advanceState() { + // Sets the actual state to what it should be next update + // Returns the newly assumed actual state of the cell. + bool advanceState() { this.state = this.nextState; this.nextState = false; this.dirty = true; + + return this.state; } void update(int neighbors) { From 1146c7d265838f2691b33fa5b00517c49e4ff3c8 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sun, 8 Jul 2018 19:32:43 +0200 Subject: [PATCH 015/120] Add Check for State Changes During Grid Update --- lib/src/App.dart | 2 +- lib/src/Grid.dart | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/src/App.dart b/lib/src/App.dart index 8ab933a..140e9a3 100644 --- a/lib/src/App.dart +++ b/lib/src/App.dart @@ -56,7 +56,7 @@ class App { void update() { // print("updating"); - grid.update(); + if(!grid.update()) running = false; } void render([num interp]) { diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index a25a50e..f47e5bf 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -143,7 +143,8 @@ class Grid { return grid; } - void update() { + bool update() { + bool stateChanges = false; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { // DEFAULTS TO CONWAY GAME OF LIFE RANGE OF ONE @@ -152,11 +153,14 @@ class Grid { } 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].advanceState(); + Cell c = map[y][x]; + if(c.state != c.nextState) stateChanges = true; + c.advanceState(); + if (!_dirty && map[y][x].dirty) _dirty = true; } } + return stateChanges; } int getSurroundingNeighbors(int x, int y, int range) { From 016b166d50d393e0f1a242e295a4dd15ff1217d0 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sun, 8 Jul 2018 19:45:04 +0200 Subject: [PATCH 016/120] Add Clear Board Function to Engine --- lib/src/App.dart | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/src/App.dart b/lib/src/App.dart index 140e9a3..21847ac 100644 --- a/lib/src/App.dart +++ b/lib/src/App.dart @@ -28,11 +28,14 @@ class App { } void reset() { -// grid = new Grid(100, 100); -// running = false; grid.reset(); } + void clear() { + grid = new Grid(100, 100); + running = false; + } + void process(num now) { _drawLag += _elapsed.elapsedMilliseconds; _updateLag += _elapsed.elapsedMilliseconds; From 1a43be14facb8d19de2d036a0a91cb3485827bb9 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sun, 8 Jul 2018 19:45:35 +0200 Subject: [PATCH 017/120] Add Clear Board Button to Interface --- lib/app_component.dart | 3 +++ lib/app_component.html | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/app_component.dart b/lib/app_component.dart index 2b54300..1e835e3 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -56,4 +56,7 @@ class AppComponent implements OnInit { void onEdgesClicked() { engine.grid.switchEdgeRendering(); } + + void onClearClicked() { + } } diff --git a/lib/app_component.html b/lib/app_component.html index d56c5d2..90606c7 100644 --- a/lib/app_component.html +++ b/lib/app_component.html @@ -14,8 +14,9 @@ - + + Speed:
\ No newline at end of file From 1c756bbda4ceacef84cadbbeefc9f7eefc372f34 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sun, 8 Jul 2018 19:45:47 +0200 Subject: [PATCH 018/120] Add Functionality to Clear Board Button --- lib/app_component.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/app_component.dart b/lib/app_component.dart index 1e835e3..6ac334e 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -58,5 +58,6 @@ class AppComponent implements OnInit { } void onClearClicked() { + engine.clear(); } } From e18de1d84c0b9a6baa631c657ec9cc90c29095b3 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 9 Jul 2018 15:16:28 +0200 Subject: [PATCH 019/120] Rename App to Engine --- lib/app_component.dart | 6 +++--- lib/src/{App.dart => Engine.dart} | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename lib/src/{App.dart => Engine.dart} (97%) diff --git a/lib/app_component.dart b/lib/app_component.dart index 6ac334e..4169c55 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -1,7 +1,7 @@ import 'package:angular/angular.dart'; import 'dart:html' as html; -import 'package:rules_of_living/src/App.dart'; +import 'package:rules_of_living/src/Engine.dart'; @Component( selector: 'my-app', @@ -10,7 +10,7 @@ import 'package:rules_of_living/src/App.dart'; class AppComponent implements OnInit { var name = "World"; - App engine; + Engine engine; @ViewChild("caCanvas") html.CanvasElement canvas; @@ -24,7 +24,7 @@ class AppComponent implements OnInit { If you see this the app is broken :( ''', canvas.width/2, canvas.height/2); - engine = new App(canvas); + engine = new Engine(canvas); html.window.animationFrame.then(animFrame); } diff --git a/lib/src/App.dart b/lib/src/Engine.dart similarity index 97% rename from lib/src/App.dart rename to lib/src/Engine.dart index 21847ac..04b4e95 100644 --- a/lib/src/App.dart +++ b/lib/src/Engine.dart @@ -2,7 +2,7 @@ import 'dart:html' as html; import 'package:rules_of_living/src/Grid.dart'; -class App { +class Engine { // Elapsed Time Counter - useful for Safety Timeout Stopwatch _elapsed = new Stopwatch(); @@ -22,7 +22,7 @@ class App { Grid grid = new Grid(100, 100); bool running = false; - App(this.canvas) { + Engine(this.canvas) { _elapsed.start(); grid.addPattern(amount: 15, dispersal: 5); } From 7c49531d0ecd04809c53ab87c6eb531f1444997f Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 9 Jul 2018 17:00:53 +0200 Subject: [PATCH 020/120] Expose Getter and Setter for Engine Running Variable --- lib/src/Engine.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index 04b4e95..a4043b7 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -20,7 +20,7 @@ class Engine { final html.CanvasElement canvas; Grid grid = new Grid(100, 100); - bool running = false; + bool _running = false; Engine(this.canvas) { _elapsed.start(); @@ -66,4 +66,7 @@ class Engine { // print("rendering"); grid.render(canvas, interp); } + + void set running(bool on) => _running = on; + bool get running => _running; } From 9030d31e972ad81b4fba83e99b7a02ba8a752ec6 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 9 Jul 2018 17:27:11 +0200 Subject: [PATCH 021/120] Hide Implementation of edge rendering in grid --- lib/app_component.dart | 2 +- lib/src/Engine.dart | 2 ++ lib/src/Grid.dart | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/app_component.dart b/lib/app_component.dart index 4169c55..9f97ef0 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -54,7 +54,7 @@ class AppComponent implements OnInit { } void onEdgesClicked() { - engine.grid.switchEdgeRendering(); + engine.toggleEdgeRendering(); } void onClearClicked() { diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index a4043b7..cc59f96 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -65,6 +65,8 @@ class Engine { void render([num interp]) { // print("rendering"); grid.render(canvas, interp); + void toggleEdgeRendering() { + _grid.renderEdges = !_grid.renderEdges; } void set running(bool on) => _running = on; diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index f47e5bf..7c4bcad 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -210,6 +210,9 @@ class Grid { void switchEdgeRendering([bool on]) { _renderEdges = on ?? !_renderEdges; + void set renderEdges(bool on) { + _renderEdges = on; _dirty = true; } + bool get renderEdges => _renderEdges; } From ac9a7c759193a1aa3ca01b9da61b61c148376970 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 9 Jul 2018 17:27:56 +0200 Subject: [PATCH 022/120] Implement Engine Step Method --- lib/app_component.dart | 3 +-- lib/src/Engine.dart | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/app_component.dart b/lib/app_component.dart index 9f97ef0..7c3d314 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -39,8 +39,7 @@ class AppComponent implements OnInit { } void onStepClicked() { - engine.running = false; - engine.update(); + engine.step(); } void onResetClicked() { diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index cc59f96..a737758 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -60,6 +60,10 @@ class Engine { void update() { // print("updating"); if(!grid.update()) running = false; + + void step() { + running = false; + _grid.update(); } void render([num interp]) { From dfcd55fe716f5ff5045cba2e4f09bbf0acde7e58 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 9 Jul 2018 17:29:09 +0200 Subject: [PATCH 023/120] Remove App Grid Access --- lib/app_component.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/app_component.dart b/lib/app_component.dart index 7c3d314..0539769 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -49,7 +49,6 @@ class AppComponent implements OnInit { void onRandomClicked() { engine.running = false; - engine.grid.addPattern(); } void onEdgesClicked() { From 6745f9c9d6cdf34d2973d83f2c6a3e8110b0e4c8 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 9 Jul 2018 17:31:46 +0200 Subject: [PATCH 024/120] Make grid Private to Engine --- lib/src/Engine.dart | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index a737758..d55f552 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -19,20 +19,20 @@ class Engine { num _drawLag = 0.0; final html.CanvasElement canvas; - Grid grid = new Grid(100, 100); + Grid _grid = new Grid(100, 100); bool _running = false; Engine(this.canvas) { _elapsed.start(); - grid.addPattern(amount: 15, dispersal: 5); + _grid.addPattern(amount: 15, dispersal: 5); } void reset() { - grid.reset(); + _grid.reset(); } void clear() { - grid = new Grid(100, 100); + _grid = new Grid(100, 100); running = false; } @@ -59,7 +59,8 @@ class Engine { void update() { // print("updating"); - if(!grid.update()) running = false; + if (!_grid.update()) running = false; + } void step() { running = false; @@ -68,7 +69,9 @@ class Engine { void render([num interp]) { // print("rendering"); - grid.render(canvas, interp); + _grid.render(canvas, interp); + } + void toggleEdgeRendering() { _grid.renderEdges = !_grid.renderEdges; } From 4c1c805f243f011c9e8088d16242c8d9d2b781e5 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 9 Jul 2018 17:32:35 +0200 Subject: [PATCH 025/120] Add addPattern Functionality to Engine --- lib/app_component.dart | 1 + lib/src/Engine.dart | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/lib/app_component.dart b/lib/app_component.dart index 0539769..458b080 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -49,6 +49,7 @@ class AppComponent implements OnInit { void onRandomClicked() { engine.running = false; + engine.addPattern(); } void onEdgesClicked() { diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index d55f552..3a8263a 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -72,6 +72,17 @@ class Engine { _grid.render(canvas, interp); } + void addPattern( + {CellPattern pattern, int x, int y, int amount, int dispersal, int seed}) { + _grid.addPattern( + pattern: pattern, + x: x, + y: y, + amount: amount, + dispersal: dispersal, + seed: seed); + } + void toggleEdgeRendering() { _grid.renderEdges = !_grid.renderEdges; } From 2d0e24bdf8f3a44bf1123de2aa418eab6d1ab8e2 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 9 Jul 2018 17:32:59 +0200 Subject: [PATCH 026/120] Move Reset Grid Implementation to Engine --- lib/app_component.dart | 1 - lib/src/Engine.dart | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/app_component.dart b/lib/app_component.dart index 458b080..8e726df 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -43,7 +43,6 @@ class AppComponent implements OnInit { } void onResetClicked() { - engine.running = false; engine.reset(); } diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index 3a8263a..80f16ed 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -29,6 +29,7 @@ class Engine { void reset() { _grid.reset(); + running = false; } void clear() { From 49803e7a6ad15267840a50ed9fcb63c877d82b4c Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 9 Jul 2018 17:33:48 +0200 Subject: [PATCH 027/120] Fix Remnants of EdgeRendering toggle compile Error --- lib/src/Grid.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index 7c4bcad..528e170 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -208,8 +208,6 @@ class Grid { _dirty = false; } - void switchEdgeRendering([bool on]) { - _renderEdges = on ?? !_renderEdges; void set renderEdges(bool on) { _renderEdges = on; _dirty = true; From 4b7051a5e14075e151bd06b82774735b4595cafa Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 9 Jul 2018 17:45:11 +0200 Subject: [PATCH 028/120] Fix implicit Overwrite of Dart Pattern Class --- lib/src/Grid.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index 528e170..22b9728 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -4,7 +4,7 @@ import 'dart:math' as math; import 'package:rules_of_living/src/Cell.dart'; import 'package:rules_of_living/src/Rule.dart'; -enum Pattern { SpaceShip, Blinker } +enum CellPattern { SpaceShip, Blinker } class Grid { final int w; @@ -19,7 +19,7 @@ class Grid { int _y; int _amount; int _dispersal; - Pattern _pattern; + CellPattern _pattern; Grid(int w, int h) : this.w = w, @@ -44,7 +44,7 @@ class Grid { } void addPattern( - {Pattern pattern, int x, int y, int amount, int dispersal, int seed}) { + {CellPattern pattern, int x, int y, int amount, int dispersal, int seed}) { _startingSeed = seed ?? DateTime.now().millisecondsSinceEpoch; math.Random rng = new math.Random(_startingSeed); _x = x; @@ -58,7 +58,7 @@ class Grid { // Two blocks, offset // ## // ## - case Pattern.Blinker: + case CellPattern.Blinker: setCellState(cx, cy, true); setCellState(cx + 1, cy, true); setCellState(cx, cy + 1, true); @@ -73,7 +73,7 @@ class Grid { // # // # // ### - case Pattern.SpaceShip: + case CellPattern.SpaceShip: setCellState(1 + cx, 0 + cy, true); setCellState(2 + cx, 1 + cy, true); setCellState(2 + cx, 2 + cy, true); From 8a1a050d81e4e071cb01d8906571cdbec1c2e306 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 9 Jul 2018 17:54:29 +0200 Subject: [PATCH 029/120] Add Angulard Material Dependency --- pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/pubspec.yaml b/pubspec.yaml index 9dc2faa..1e77191 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -9,6 +9,7 @@ environment: dependencies: angular: ^5.0.0-beta + angular_components: ^0.9.0-beta dev_dependencies: angular_test: ^2.0.0-beta From 8485a96aa3e99498ecd7d23586cd34a72dee3684 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 9 Jul 2018 18:11:34 +0200 Subject: [PATCH 030/120] Add Required Material Font --- web/index.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/index.html b/web/index.html index 35bd3cb..3b85bf1 100644 --- a/web/index.html +++ b/web/index.html @@ -20,6 +20,8 @@ + + From c5cd600cfc6daf39aa75d433458c5c884fafa051 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Tue, 10 Jul 2018 12:52:56 +0200 Subject: [PATCH 031/120] Add Sample Material Styling --- lib/app_component.dart | 6 +- lib/app_component.html | 15 ++- web/index.html | 4 +- web/styles.css | 233 +++++++++++++++++++++-------------------- 4 files changed, 142 insertions(+), 116 deletions(-) diff --git a/lib/app_component.dart b/lib/app_component.dart index 8e726df..458b205 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -1,4 +1,5 @@ import 'package:angular/angular.dart'; +import 'package:angular_components/angular_components.dart'; import 'dart:html' as html; import 'package:rules_of_living/src/Engine.dart'; @@ -6,7 +7,10 @@ import 'package:rules_of_living/src/Engine.dart'; @Component( selector: 'my-app', templateUrl: "app_component.html", - directives: [coreDirectives]) + directives: [coreDirectives, MaterialIconComponent], + styleUrls: const ['package:angular_components/app_layout/layout.scss.css'], + providers: const [materialProviders], +) class AppComponent implements OnInit { var name = "World"; diff --git a/lib/app_component.html b/lib/app_component.html index 90606c7..0532aea 100644 --- a/lib/app_component.html +++ b/lib/app_component.html @@ -1,4 +1,15 @@ -

Cellular Automata

+
+
+ + + + Cellular Automata +
+ +
+
Ruleset: @@ -19,4 +30,4 @@ Speed: -
\ No newline at end of file + diff --git a/web/index.html b/web/index.html index 3b85bf1..be2e05b 100644 --- a/web/index.html +++ b/web/index.html @@ -15,13 +15,15 @@ + + - + diff --git a/web/styles.css b/web/styles.css index ef7a186..e0b0d35 100644 --- a/web/styles.css +++ b/web/styles.css @@ -1,117 +1,126 @@ @import url(https://fonts.googleapis.com/css?family=Roboto); @import url(https://fonts.googleapis.com/css?family=Material+Icons); -/* Master Styles */ -h1 { - color: #369; - font-family: Arial, Helvetica, sans-serif; - font-size: 250%; -} -h2, h3 { - color: #444; - font-family: Arial, Helvetica, sans-serif; - font-weight: lighter; -} -body { - margin: 2em; -} -body, input[text], button { - color: #888; - font-family: Cambria, Georgia; -} -a { - cursor: pointer; - cursor: hand; -} -button { - font-family: Arial; - background-color: #eee; - border: none; - padding: 5px 10px; - border-radius: 4px; - cursor: pointer; - cursor: hand; -} -button:hover { - background-color: #cfd8dc; -} -button:disabled { - background-color: #eee; - color: #aaa; - cursor: auto; -} -label { - padding-right: 0.5em; -} -/* Navigation link styles */ -nav a { - padding: 5px 10px; - text-decoration: none; - margin-right: 10px; - margin-top: 10px; - display: inline-block; - background-color: #eee; - border-radius: 4px; -} -nav a:visited, a:link { - color: #607D8B; -} -nav a:hover { - color: #039be5; - background-color: #CFD8DC; -} -nav a.active { - color: #039be5; +html, body { + height: 100%; + margin: 0; + padding: 0; + width: 100%; + font-family: 'Roboto', sans-serif; + } -/* items class */ -.items { - margin: 0 0 2em 0; - list-style-type: none; - padding: 0; - width: 24em; -} -.items li { - cursor: pointer; - position: relative; - left: 0; - background-color: #EEE; - margin: .5em; - padding: .3em 0; - height: 1.6em; - border-radius: 4px; -} -.items li:hover { - color: #607D8B; - background-color: #DDD; - left: .1em; -} -.items li.selected { - background-color: #CFD8DC; - color: white; -} -.items li.selected:hover { - background-color: #BBD8DC; -} -.items .text { - position: relative; - top: -3px; -} -.items .badge { - display: inline-block; - font-size: small; - color: white; - padding: 0.8em 0.7em 0 0.7em; - background-color: #607D8B; - line-height: 1em; - position: relative; - left: -1px; - top: -4px; - height: 1.8em; - margin-right: .8em; - border-radius: 4px 0 0 4px; -} -/* everywhere else */ -* { - font-family: Arial, Helvetica, sans-serif; -} +/*!* Master Styles *!*/ +/*h1 {*/ + /*color: #369;*/ + /*font-family: Arial, Helvetica, sans-serif;*/ + /*font-size: 250%;*/ +/*}*/ +/*h2, h3 {*/ + /*color: #444;*/ + /*font-family: Arial, Helvetica, sans-serif;*/ + /*font-weight: lighter;*/ +/*}*/ +/*body {*/ + /*margin: 2em;*/ +/*}*/ +/*body, input[text], button {*/ + /*color: #888;*/ + /*font-family: Cambria, Georgia;*/ +/*}*/ +/*a {*/ + /*cursor: pointer;*/ + /*cursor: hand;*/ +/*}*/ +/*button {*/ + /*font-family: Arial;*/ + /*background-color: #eee;*/ + /*border: none;*/ + /*padding: 5px 10px;*/ + /*border-radius: 4px;*/ + /*cursor: pointer;*/ + /*cursor: hand;*/ +/*}*/ +/*button:hover {*/ + /*background-color: #cfd8dc;*/ +/*}*/ +/*button:disabled {*/ + /*background-color: #eee;*/ + /*color: #aaa;*/ + /*cursor: auto;*/ +/*}*/ +/*label {*/ + /*padding-right: 0.5em;*/ +/*}*/ +/*!* Navigation link styles *!*/ +/*nav a {*/ + /*padding: 5px 10px;*/ + /*text-decoration: none;*/ + /*margin-right: 10px;*/ + /*margin-top: 10px;*/ + /*display: inline-block;*/ + /*background-color: #eee;*/ + /*border-radius: 4px;*/ +/*}*/ +/*nav a:visited, a:link {*/ + /*color: #607D8B;*/ +/*}*/ +/*nav a:hover {*/ + /*color: #039be5;*/ + /*background-color: #CFD8DC;*/ +/*}*/ +/*nav a.active {*/ + /*color: #039be5;*/ +/*}*/ + +/*!* items class *!*/ +/*.items {*/ + /*margin: 0 0 2em 0;*/ + /*list-style-type: none;*/ + /*padding: 0;*/ + /*width: 24em;*/ +/*}*/ +/*.items li {*/ + /*cursor: pointer;*/ + /*position: relative;*/ + /*left: 0;*/ + /*background-color: #EEE;*/ + /*margin: .5em;*/ + /*padding: .3em 0;*/ + /*height: 1.6em;*/ + /*border-radius: 4px;*/ +/*}*/ +/*.items li:hover {*/ + /*color: #607D8B;*/ + /*background-color: #DDD;*/ + /*left: .1em;*/ +/*}*/ +/*.items li.selected {*/ + /*background-color: #CFD8DC;*/ + /*color: white;*/ +/*}*/ +/*.items li.selected:hover {*/ + /*background-color: #BBD8DC;*/ +/*}*/ +/*.items .text {*/ + /*position: relative;*/ + /*top: -3px;*/ +/*}*/ +/*.items .badge {*/ + /*display: inline-block;*/ + /*font-size: small;*/ + /*color: white;*/ + /*padding: 0.8em 0.7em 0 0.7em;*/ + /*background-color: #607D8B;*/ + /*line-height: 1em;*/ + /*position: relative;*/ + /*left: -1px;*/ + /*top: -4px;*/ + /*height: 1.8em;*/ + /*margin-right: .8em;*/ + /*border-radius: 4px 0 0 4px;*/ +/*}*/ +/*!* everywhere else *!*/ +/** {*/ + /*font-family: Arial, Helvetica, sans-serif;*/ +/*}*/ From b5413530918974eb74f02bc61bee07ab9cb00a36 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Tue, 10 Jul 2018 14:28:41 +0200 Subject: [PATCH 032/120] Fix Material directives import statement --- lib/app_component.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/app_component.dart b/lib/app_component.dart index 458b205..10c8575 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -7,9 +7,8 @@ import 'package:rules_of_living/src/Engine.dart'; @Component( selector: 'my-app', templateUrl: "app_component.html", - directives: [coreDirectives, MaterialIconComponent], + directives: [coreDirectives, materialDirectives], styleUrls: const ['package:angular_components/app_layout/layout.scss.css'], - providers: const [materialProviders], ) class AppComponent implements OnInit { var name = "World"; From 917d1c3fabc5ea5e2337771b357e52523709785b Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Wed, 22 Aug 2018 13:00:41 +0200 Subject: [PATCH 033/120] Split App Header into Component --- lib/app_component.dart | 4 +++- lib/app_component.html | 15 ++------------- lib/components/header_component.dart | 13 +++++++++++++ lib/components/header_component.html | 12 ++++++++++++ 4 files changed, 30 insertions(+), 14 deletions(-) create mode 100644 lib/components/header_component.dart create mode 100644 lib/components/header_component.html diff --git a/lib/app_component.dart b/lib/app_component.dart index 10c8575..ee605b1 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -1,5 +1,6 @@ import 'package:angular/angular.dart'; import 'package:angular_components/angular_components.dart'; +import 'package:rules_of_living/components/header_component.dart'; import 'dart:html' as html; import 'package:rules_of_living/src/Engine.dart'; @@ -7,7 +8,8 @@ import 'package:rules_of_living/src/Engine.dart'; @Component( selector: 'my-app', templateUrl: "app_component.html", - directives: [coreDirectives, materialDirectives], + directives: [coreDirectives, MaterialButtonComponent, MaterialIconComponent, MaterialSliderComponent, HeaderComponent], + providers: [materialProviders], styleUrls: const ['package:angular_components/app_layout/layout.scss.css'], ) class AppComponent implements OnInit { diff --git a/lib/app_component.html b/lib/app_component.html index 0532aea..9406daa 100644 --- a/lib/app_component.html +++ b/lib/app_component.html @@ -1,15 +1,4 @@ -
-
- - - - Cellular Automata -
- -
-
+
Ruleset: @@ -28,6 +17,6 @@ - Speed: + Speed:
diff --git a/lib/components/header_component.dart b/lib/components/header_component.dart new file mode 100644 index 0000000..94e9a9b --- /dev/null +++ b/lib/components/header_component.dart @@ -0,0 +1,13 @@ +import 'package:angular/angular.dart'; +import 'package:angular_components/angular_components.dart'; + +@Component( + selector: 'app_header', + templateUrl: "header_component.html", + directives: [coreDirectives, MaterialButtonComponent, MaterialIconComponent, MaterialSliderComponent], + providers: [], + styleUrls: const ['package:angular_components/app_layout/layout.scss.css'], +) +class HeaderComponent { + +} diff --git a/lib/components/header_component.html b/lib/components/header_component.html new file mode 100644 index 0000000..2f87a66 --- /dev/null +++ b/lib/components/header_component.html @@ -0,0 +1,12 @@ +
+
+ + + + Cellular Automata +
+ +
+
\ No newline at end of file From c86d8d8b59c338641892994620c1eae08c46b103 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Wed, 22 Aug 2018 20:16:31 +0200 Subject: [PATCH 034/120] Split Simulation & Controls into Components --- lib/app_component.dart | 61 +++--------------------- lib/app_component.html | 21 ++------ lib/components/controls_component.css | 4 ++ lib/components/controls_component.dart | 42 ++++++++++++++++ lib/components/controls_component.html | 14 ++++++ lib/components/simulation_component.dart | 41 ++++++++++++++++ lib/components/simulation_component.html | 1 + lib/service/engine_service.dart | 11 +++++ 8 files changed, 123 insertions(+), 72 deletions(-) create mode 100644 lib/components/controls_component.css create mode 100644 lib/components/controls_component.dart create mode 100644 lib/components/controls_component.html create mode 100644 lib/components/simulation_component.dart create mode 100644 lib/components/simulation_component.html create mode 100644 lib/service/engine_service.dart diff --git a/lib/app_component.dart b/lib/app_component.dart index ee605b1..bfdd949 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -1,66 +1,17 @@ import 'package:angular/angular.dart'; import 'package:angular_components/angular_components.dart'; +import 'package:rules_of_living/components/controls_component.dart'; import 'package:rules_of_living/components/header_component.dart'; - -import 'dart:html' as html; -import 'package:rules_of_living/src/Engine.dart'; +import 'package:rules_of_living/components/simulation_component.dart'; +import 'package:rules_of_living/service/engine_service.dart'; @Component( selector: 'my-app', templateUrl: "app_component.html", - directives: [coreDirectives, MaterialButtonComponent, MaterialIconComponent, MaterialSliderComponent, HeaderComponent], - providers: [materialProviders], + directives: [coreDirectives, MaterialButtonComponent, MaterialIconComponent, MaterialSliderComponent, HeaderComponent, SimulationComponent, ControlsComponent], + providers: [materialProviders, ClassProvider(EngineService)], styleUrls: const ['package:angular_components/app_layout/layout.scss.css'], ) -class AppComponent implements OnInit { +class AppComponent { var name = "World"; - - Engine engine; - - @ViewChild("caCanvas") - html.CanvasElement canvas; - - @override - void ngOnInit() { - canvas.context2D.setFillColorRgb(200, 0, 0); - canvas.context2D.fillRect(0, 0, canvas.width, canvas.height); - canvas.context2D.setFillColorRgb(0, 255, 0); - canvas.context2D.fillText(''' - If you see this - the app is broken :( - ''', canvas.width/2, canvas.height/2); - engine = new Engine(canvas); - - html.window.animationFrame.then(animFrame); - } - - void animFrame(num now) { - engine.process(now); - html.window.animationFrame.then(animFrame); - } - - void onStartClicked() { - engine.running = !engine.running; - } - - void onStepClicked() { - engine.step(); - } - - void onResetClicked() { - engine.reset(); - } - - void onRandomClicked() { - engine.running = false; - engine.addPattern(); - } - - void onEdgesClicked() { - engine.toggleEdgeRendering(); - } - - void onClearClicked() { - engine.clear(); - } } diff --git a/lib/app_component.html b/lib/app_component.html index 9406daa..f4dc816 100644 --- a/lib/app_component.html +++ b/lib/app_component.html @@ -3,20 +3,7 @@ Ruleset: -
- -
-
- - - - - - Speed: - -
+
+ + +
\ No newline at end of file diff --git a/lib/components/controls_component.css b/lib/components/controls_component.css new file mode 100644 index 0000000..580e03c --- /dev/null +++ b/lib/components/controls_component.css @@ -0,0 +1,4 @@ +material-slider { + display: inline-block; + width: 50px; +} \ No newline at end of file diff --git a/lib/components/controls_component.dart b/lib/components/controls_component.dart new file mode 100644 index 0000000..3f0fa1b --- /dev/null +++ b/lib/components/controls_component.dart @@ -0,0 +1,42 @@ +import 'package:angular/angular.dart'; +import 'package:angular_components/angular_components.dart'; +import 'package:rules_of_living/service/engine_service.dart'; +import 'package:rules_of_living/src/Engine.dart'; + +@Component( + selector: 'sim-controls', + templateUrl: "controls_component.html", + directives: [coreDirectives, MaterialButtonComponent, MaterialIconComponent, MaterialSliderComponent], + providers: [], + styleUrls: const ["controls_component.css"], +) +class ControlsComponent { + final EngineService engineService; + Engine get engine => engineService.engine; + ControlsComponent(this.engineService); + + void onStartClicked() { + engine.running = !engine.running; + } + + void onStepClicked() { + engine.step(); + } + + void onResetClicked() { + engine.reset(); + } + + void onRandomClicked() { + engine.running = false; + engine.addPattern(); + } + + void onEdgesClicked() { + engine.toggleEdgeRendering(); + } + + void onClearClicked() { + engine.clear(); + } +} diff --git a/lib/components/controls_component.html b/lib/components/controls_component.html new file mode 100644 index 0000000..cc6f600 --- /dev/null +++ b/lib/components/controls_component.html @@ -0,0 +1,14 @@ +
+ + + + + + + + + + + Speed: + +
\ No newline at end of file diff --git a/lib/components/simulation_component.dart b/lib/components/simulation_component.dart new file mode 100644 index 0000000..47567d5 --- /dev/null +++ b/lib/components/simulation_component.dart @@ -0,0 +1,41 @@ +import 'dart:html' as html; + +import 'package:angular/angular.dart'; +import 'package:rules_of_living/service/engine_service.dart'; + +@Component( + selector: 'gol-simulation', + templateUrl: "simulation_component.html", + directives: [coreDirectives], + providers: [], +// styleUrls: const ['package:angular_components/app_layout/layout.scss.css'], +) +class SimulationComponent implements OnInit { + final EngineService engineService; + + SimulationComponent(this.engineService); + + @override + void ngOnInit() { + html.CanvasElement canvas = html.CanvasElement()..id = "simulation"; + html.querySelector("#simulation")..append(canvas); + canvas.width = 500; + canvas.height= 500; + + canvas.context2D.setFillColorRgb(200, 0, 0); + canvas.context2D.fillRect(0, 0, canvas.width, canvas.height); + canvas.context2D.setFillColorRgb(0, 255, 0); + canvas.context2D.fillText(''' + If you see this\n + the app is broken :( + ''', canvas.width/2-50, canvas.height/2); + engineService.create(canvas); + + html.window.animationFrame.then(animFrame); + } + + void animFrame(num now) { + engineService.engine.process(now); + html.window.animationFrame.then(animFrame); + } +} diff --git a/lib/components/simulation_component.html b/lib/components/simulation_component.html new file mode 100644 index 0000000..1e5f113 --- /dev/null +++ b/lib/components/simulation_component.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/lib/service/engine_service.dart b/lib/service/engine_service.dart new file mode 100644 index 0000000..5107f3c --- /dev/null +++ b/lib/service/engine_service.dart @@ -0,0 +1,11 @@ +import 'dart:html' as html; + +import 'package:rules_of_living/src/Engine.dart'; + +class EngineService { + Engine _engine; + + Engine get engine => _engine; + + void create(html.CanvasElement canvas) => _engine = Engine(canvas); +} From bd7990991e00b48eeedb08e0ec192d035bdf927f Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 23 Aug 2018 09:33:15 +0200 Subject: [PATCH 035/120] Connect Speed Slider to internal Variable --- lib/components/controls_component.dart | 2 ++ lib/components/controls_component.html | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/components/controls_component.dart b/lib/components/controls_component.dart index 3f0fa1b..cd18105 100644 --- a/lib/components/controls_component.dart +++ b/lib/components/controls_component.dart @@ -12,6 +12,8 @@ import 'package:rules_of_living/src/Engine.dart'; ) class ControlsComponent { final EngineService engineService; + int simSpeed = 5; + Engine get engine => engineService.engine; ControlsComponent(this.engineService); diff --git a/lib/components/controls_component.html b/lib/components/controls_component.html index cc6f600..4d07357 100644 --- a/lib/components/controls_component.html +++ b/lib/components/controls_component.html @@ -9,6 +9,6 @@ - Speed: + {{simSpeed}} \ No newline at end of file From 4906bbe54cf01f5d9f11f8f6f4ab1af953af6a34 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 23 Aug 2018 11:34:08 +0200 Subject: [PATCH 036/120] Switch Control Interface Icons to MaterialIcons --- lib/components/controls_component.dart | 2 +- lib/components/controls_component.html | 16 ++++++++-------- web/index.html | 5 ----- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/lib/components/controls_component.dart b/lib/components/controls_component.dart index cd18105..b2c09e3 100644 --- a/lib/components/controls_component.dart +++ b/lib/components/controls_component.dart @@ -6,7 +6,7 @@ import 'package:rules_of_living/src/Engine.dart'; @Component( selector: 'sim-controls', templateUrl: "controls_component.html", - directives: [coreDirectives, MaterialButtonComponent, MaterialIconComponent, MaterialSliderComponent], + directives: [coreDirectives, MaterialButtonComponent, MaterialIconComponent, MaterialSliderComponent, MaterialTooltipDirective], providers: [], styleUrls: const ["controls_component.css"], ) diff --git a/lib/components/controls_component.html b/lib/components/controls_component.html index 4d07357..c8eb9cd 100644 --- a/lib/components/controls_component.html +++ b/lib/components/controls_component.html @@ -1,14 +1,14 @@
+ - - + + - - - - - {{simSpeed}} - + + + + +
\ No newline at end of file diff --git a/web/index.html b/web/index.html index be2e05b..d5432b4 100644 --- a/web/index.html +++ b/web/index.html @@ -19,11 +19,6 @@ - - - - - From c3368524f982b3c79b34d07aa89b8ef85412a5c3 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 23 Aug 2018 12:07:43 +0200 Subject: [PATCH 037/120] Change Step Forward Icon --- lib/components/controls_component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/components/controls_component.html b/lib/components/controls_component.html index c8eb9cd..76a64e3 100644 --- a/lib/components/controls_component.html +++ b/lib/components/controls_component.html @@ -6,7 +6,7 @@ - + From abd2c3ac238a104cffb22a9842ff79563884355c Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 23 Aug 2018 12:07:54 +0200 Subject: [PATCH 038/120] Add Speed Slider Tooltip --- lib/components/controls_component.dart | 1 + lib/components/controls_component.html | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/components/controls_component.dart b/lib/components/controls_component.dart index b2c09e3..02cbe1a 100644 --- a/lib/components/controls_component.dart +++ b/lib/components/controls_component.dart @@ -13,6 +13,7 @@ import 'package:rules_of_living/src/Engine.dart'; class ControlsComponent { final EngineService engineService; int simSpeed = 5; + String get speedSliderTooltip => "Simulation Speed: $simSpeed"; Engine get engine => engineService.engine; ControlsComponent(this.engineService); diff --git a/lib/components/controls_component.html b/lib/components/controls_component.html index 76a64e3..b5ab389 100644 --- a/lib/components/controls_component.html +++ b/lib/components/controls_component.html @@ -9,6 +9,6 @@ - + \ No newline at end of file From 6ba0ca55cbf4a3afbd87f3abc16fbb19650ee420 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 23 Aug 2018 12:38:34 +0200 Subject: [PATCH 039/120] dartfmt --- lib/app_component.dart | 18 +++++++++++++----- lib/components/controls_component.dart | 8 +++++++- lib/components/header_component.dart | 11 +++++++---- lib/components/simulation_component.dart | 4 ++-- lib/src/Engine.dart | 7 ++++++- lib/src/Grid.dart | 10 ++++++++-- 6 files changed, 43 insertions(+), 15 deletions(-) diff --git a/lib/app_component.dart b/lib/app_component.dart index bfdd949..9576d3a 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -6,11 +6,19 @@ import 'package:rules_of_living/components/simulation_component.dart'; import 'package:rules_of_living/service/engine_service.dart'; @Component( - selector: 'my-app', - templateUrl: "app_component.html", - directives: [coreDirectives, MaterialButtonComponent, MaterialIconComponent, MaterialSliderComponent, HeaderComponent, SimulationComponent, ControlsComponent], - providers: [materialProviders, ClassProvider(EngineService)], - styleUrls: const ['package:angular_components/app_layout/layout.scss.css'], + selector: 'my-app', + templateUrl: "app_component.html", + directives: [ + coreDirectives, + MaterialButtonComponent, + MaterialIconComponent, + MaterialSliderComponent, + HeaderComponent, + SimulationComponent, + ControlsComponent + ], + providers: [materialProviders, ClassProvider(EngineService)], + styleUrls: const ['package:angular_components/app_layout/layout.scss.css'], ) class AppComponent { var name = "World"; diff --git a/lib/components/controls_component.dart b/lib/components/controls_component.dart index 02cbe1a..1655abf 100644 --- a/lib/components/controls_component.dart +++ b/lib/components/controls_component.dart @@ -6,7 +6,13 @@ import 'package:rules_of_living/src/Engine.dart'; @Component( selector: 'sim-controls', templateUrl: "controls_component.html", - directives: [coreDirectives, MaterialButtonComponent, MaterialIconComponent, MaterialSliderComponent, MaterialTooltipDirective], + directives: [ + coreDirectives, + MaterialButtonComponent, + MaterialIconComponent, + MaterialSliderComponent, + MaterialTooltipDirective + ], providers: [], styleUrls: const ["controls_component.css"], ) diff --git a/lib/components/header_component.dart b/lib/components/header_component.dart index 94e9a9b..83970fd 100644 --- a/lib/components/header_component.dart +++ b/lib/components/header_component.dart @@ -4,10 +4,13 @@ import 'package:angular_components/angular_components.dart'; @Component( selector: 'app_header', templateUrl: "header_component.html", - directives: [coreDirectives, MaterialButtonComponent, MaterialIconComponent, MaterialSliderComponent], + directives: [ + coreDirectives, + MaterialButtonComponent, + MaterialIconComponent, + MaterialSliderComponent + ], providers: [], styleUrls: const ['package:angular_components/app_layout/layout.scss.css'], ) -class HeaderComponent { - -} +class HeaderComponent {} diff --git a/lib/components/simulation_component.dart b/lib/components/simulation_component.dart index 47567d5..e64fa82 100644 --- a/lib/components/simulation_component.dart +++ b/lib/components/simulation_component.dart @@ -20,7 +20,7 @@ class SimulationComponent implements OnInit { html.CanvasElement canvas = html.CanvasElement()..id = "simulation"; html.querySelector("#simulation")..append(canvas); canvas.width = 500; - canvas.height= 500; + canvas.height = 500; canvas.context2D.setFillColorRgb(200, 0, 0); canvas.context2D.fillRect(0, 0, canvas.width, canvas.height); @@ -28,7 +28,7 @@ class SimulationComponent implements OnInit { canvas.context2D.fillText(''' If you see this\n the app is broken :( - ''', canvas.width/2-50, canvas.height/2); + ''', canvas.width / 2 - 50, canvas.height / 2); engineService.create(canvas); html.window.animationFrame.then(animFrame); diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index 80f16ed..6f7ff16 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -74,7 +74,12 @@ class Engine { } void addPattern( - {CellPattern pattern, int x, int y, int amount, int dispersal, int seed}) { + {CellPattern pattern, + int x, + int y, + int amount, + int dispersal, + int seed}) { _grid.addPattern( pattern: pattern, x: x, diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index 22b9728..d95c25e 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -44,7 +44,12 @@ class Grid { } void addPattern( - {CellPattern pattern, int x, int y, int amount, int dispersal, int seed}) { + {CellPattern pattern, + int x, + int y, + int amount, + int dispersal, + int seed}) { _startingSeed = seed ?? DateTime.now().millisecondsSinceEpoch; math.Random rng = new math.Random(_startingSeed); _x = x; @@ -154,7 +159,7 @@ class Grid { for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { Cell c = map[y][x]; - if(c.state != c.nextState) stateChanges = true; + if (c.state != c.nextState) stateChanges = true; c.advanceState(); if (!_dirty && map[y][x].dirty) _dirty = true; @@ -212,5 +217,6 @@ class Grid { _renderEdges = on; _dirty = true; } + bool get renderEdges => _renderEdges; } From bf0d136d8ba70d1ccd02f16a7fdda0c6f0d14959 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 23 Aug 2018 14:12:22 +0200 Subject: [PATCH 040/120] Add Configuration Sidebar with ConfigurationService --- lib/app_component.css | 11 ++++++++ lib/app_component.dart | 9 ++++-- lib/app_component.html | 15 +++++----- lib/components/configuration_component.css | 4 +++ lib/components/configuration_component.dart | 31 +++++++++++++++++++++ lib/components/configuration_component.html | 5 ++++ lib/components/controls_component.css | 4 --- lib/components/controls_component.dart | 8 +----- lib/components/controls_component.html | 2 -- lib/service/configuration_service.dart | 17 +++++++++++ 10 files changed, 83 insertions(+), 23 deletions(-) create mode 100644 lib/app_component.css create mode 100644 lib/components/configuration_component.css create mode 100644 lib/components/configuration_component.dart create mode 100644 lib/components/configuration_component.html create mode 100644 lib/service/configuration_service.dart diff --git a/lib/app_component.css b/lib/app_component.css new file mode 100644 index 0000000..2e1a6f4 --- /dev/null +++ b/lib/app_component.css @@ -0,0 +1,11 @@ +#wrapper { + display: flex; +} + +#viewport { + flex: 0 0 65%; +} + +#sidebar { + flex: 1; +} \ No newline at end of file diff --git a/lib/app_component.dart b/lib/app_component.dart index 9576d3a..e9b44cc 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -1,8 +1,10 @@ import 'package:angular/angular.dart'; import 'package:angular_components/angular_components.dart'; +import 'package:rules_of_living/components/configuration_component.dart'; import 'package:rules_of_living/components/controls_component.dart'; import 'package:rules_of_living/components/header_component.dart'; import 'package:rules_of_living/components/simulation_component.dart'; +import 'package:rules_of_living/service/configuration_service.dart'; import 'package:rules_of_living/service/engine_service.dart'; @Component( @@ -15,10 +17,11 @@ import 'package:rules_of_living/service/engine_service.dart'; MaterialSliderComponent, HeaderComponent, SimulationComponent, - ControlsComponent + ControlsComponent, + ConfigurationComponent ], - providers: [materialProviders, ClassProvider(EngineService)], - styleUrls: const ['package:angular_components/app_layout/layout.scss.css'], + providers: [materialProviders, ClassProvider(EngineService), ClassProvider(ConfigurationService)], + styleUrls: const ['package:angular_components/app_layout/layout.scss.css', 'app_component.css'], ) class AppComponent { var name = "World"; diff --git a/lib/app_component.html b/lib/app_component.html index f4dc816..8b57941 100644 --- a/lib/app_component.html +++ b/lib/app_component.html @@ -1,9 +1,10 @@ -
- Ruleset: - -
-
- - +
+
+ + +
+
\ No newline at end of file diff --git a/lib/components/configuration_component.css b/lib/components/configuration_component.css new file mode 100644 index 0000000..2108951 --- /dev/null +++ b/lib/components/configuration_component.css @@ -0,0 +1,4 @@ +material-slider { + display: inline-block; + width: 150px; +} \ No newline at end of file diff --git a/lib/components/configuration_component.dart b/lib/components/configuration_component.dart new file mode 100644 index 0000000..bd3ae0c --- /dev/null +++ b/lib/components/configuration_component.dart @@ -0,0 +1,31 @@ +import 'package:angular/angular.dart'; +import 'package:angular_components/material_button/material_button.dart'; +import 'package:angular_components/material_icon/material_icon.dart'; +import 'package:angular_components/material_slider/material_slider.dart'; +import 'package:angular_components/material_tooltip/material_tooltip.dart'; +import 'package:rules_of_living/service/configuration_service.dart'; + +@Component( + selector: "configuration", + templateUrl: "configuration_component.html", + styleUrls: ["configuration_component.css"], + directives: [ + MaterialButtonComponent, + MaterialIconComponent, + MaterialSliderComponent, + MaterialTooltipDirective + ]) +class ConfigurationComponent { + final ConfigurationService config; + + int get simSpeed => config.simSpeed; + int set simSpeed(int value) => config.simSpeed = value; + + String get speedSliderTooltip => "Simulation Speed: $simSpeed"; + + ConfigurationComponent(this.config); + + void onEdgesClicked() { + config.toggleGrid(); + } +} diff --git a/lib/components/configuration_component.html b/lib/components/configuration_component.html new file mode 100644 index 0000000..a17261d --- /dev/null +++ b/lib/components/configuration_component.html @@ -0,0 +1,5 @@ +
+ + + Ruleset: +
\ No newline at end of file diff --git a/lib/components/controls_component.css b/lib/components/controls_component.css index 580e03c..e69de29 100644 --- a/lib/components/controls_component.css +++ b/lib/components/controls_component.css @@ -1,4 +0,0 @@ -material-slider { - display: inline-block; - width: 50px; -} \ No newline at end of file diff --git a/lib/components/controls_component.dart b/lib/components/controls_component.dart index 1655abf..1f2a65d 100644 --- a/lib/components/controls_component.dart +++ b/lib/components/controls_component.dart @@ -1,5 +1,6 @@ import 'package:angular/angular.dart'; import 'package:angular_components/angular_components.dart'; +import 'package:rules_of_living/service/configuration_service.dart'; import 'package:rules_of_living/service/engine_service.dart'; import 'package:rules_of_living/src/Engine.dart'; @@ -10,7 +11,6 @@ import 'package:rules_of_living/src/Engine.dart'; coreDirectives, MaterialButtonComponent, MaterialIconComponent, - MaterialSliderComponent, MaterialTooltipDirective ], providers: [], @@ -18,8 +18,6 @@ import 'package:rules_of_living/src/Engine.dart'; ) class ControlsComponent { final EngineService engineService; - int simSpeed = 5; - String get speedSliderTooltip => "Simulation Speed: $simSpeed"; Engine get engine => engineService.engine; ControlsComponent(this.engineService); @@ -41,10 +39,6 @@ class ControlsComponent { engine.addPattern(); } - void onEdgesClicked() { - engine.toggleEdgeRendering(); - } - void onClearClicked() { engine.clear(); } diff --git a/lib/components/controls_component.html b/lib/components/controls_component.html index b5ab389..30ddf55 100644 --- a/lib/components/controls_component.html +++ b/lib/components/controls_component.html @@ -9,6 +9,4 @@ - -
\ No newline at end of file diff --git a/lib/service/configuration_service.dart b/lib/service/configuration_service.dart new file mode 100644 index 0000000..7da2ca6 --- /dev/null +++ b/lib/service/configuration_service.dart @@ -0,0 +1,17 @@ +import 'package:rules_of_living/service/engine_service.dart'; + +class ConfigurationService { + final EngineService engineService; + + bool showGrid; + int simSpeed; + + ConfigurationService(this.engineService) { + showGrid = false; + simSpeed = 5; + } + + void toggleGrid() { + showGrid = !showGrid; + } +} \ No newline at end of file From 8d7575eaf7619becf56078eced5e4200be83bda7 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Fri, 24 Aug 2018 20:01:36 +0200 Subject: [PATCH 041/120] Disable superfluous tests In preparation for first test of the app. --- test/{app_test.dart => app_test_disable.dart} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/{app_test.dart => app_test_disable.dart} (100%) diff --git a/test/app_test.dart b/test/app_test_disable.dart similarity index 100% rename from test/app_test.dart rename to test/app_test_disable.dart From 6c9179b833886f81f77bc503e876af255547dc37 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Fri, 24 Aug 2018 20:02:43 +0200 Subject: [PATCH 042/120] make canvas argument optional on instantiating engine --- lib/src/Engine.dart | 11 +++++++---- test/src/engine_test.dart | 12 ++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 test/src/engine_test.dart diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index 6f7ff16..a52df66 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -6,7 +6,7 @@ class Engine { // Elapsed Time Counter - useful for Safety Timeout Stopwatch _elapsed = new Stopwatch(); - // Game Tick Rate - *does* impact game speed + // Game Tick Rate - *does* impact game speed TODO add configurable option int _MS_PER_STEP = 1000 ~/ 3; // Max Frame (i.e. Rendering) rate - does *not* impact game speed @@ -15,14 +15,18 @@ class Engine { // ms stuck in updateloop after which game will declare itself unresponsive final int SAFETY_TIMEOUT = 2000; + // Grid Size TODO add as configurable option + static final GRID_X = 100; + static final GRID_Y = 100; + num _updateLag = 0.0; num _drawLag = 0.0; final html.CanvasElement canvas; - Grid _grid = new Grid(100, 100); + Grid _grid = new Grid(GRID_X, GRID_Y); bool _running = false; - Engine(this.canvas) { + Engine([this.canvas]) { _elapsed.start(); _grid.addPattern(amount: 15, dispersal: 5); } @@ -59,7 +63,6 @@ class Engine { } void update() { -// print("updating"); if (!_grid.update()) running = false; } diff --git a/test/src/engine_test.dart b/test/src/engine_test.dart new file mode 100644 index 0000000..92794ff --- /dev/null +++ b/test/src/engine_test.dart @@ -0,0 +1,12 @@ +@TestOn('browser') + +import 'dart:html'; + +import 'package:rules_of_living/src/Engine.dart'; +import 'package:test/test.dart'; + +void main() { + test("Engine can be instantiated without canvas", () { + expect(Engine(), isNot(throwsA(anything))); + }); +} \ No newline at end of file From bbf61f875d7e819eabc12bee795320fced6b7466 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 25 Aug 2018 09:33:15 +0200 Subject: [PATCH 043/120] Separate Engine Service Functionality from Component --- lib/components/controls_component.dart | 12 +++----- lib/components/simulation_component.dart | 10 +------ lib/service/engine_service.dart | 37 ++++++++++++++++++++++-- lib/src/Engine.dart | 11 ++++--- 4 files changed, 47 insertions(+), 23 deletions(-) diff --git a/lib/components/controls_component.dart b/lib/components/controls_component.dart index 1f2a65d..511a7d4 100644 --- a/lib/components/controls_component.dart +++ b/lib/components/controls_component.dart @@ -1,8 +1,6 @@ import 'package:angular/angular.dart'; import 'package:angular_components/angular_components.dart'; -import 'package:rules_of_living/service/configuration_service.dart'; import 'package:rules_of_living/service/engine_service.dart'; -import 'package:rules_of_living/src/Engine.dart'; @Component( selector: 'sim-controls', @@ -17,13 +15,12 @@ import 'package:rules_of_living/src/Engine.dart'; styleUrls: const ["controls_component.css"], ) class ControlsComponent { - final EngineService engineService; + final EngineService engine; - Engine get engine => engineService.engine; - ControlsComponent(this.engineService); + ControlsComponent(this.engine); void onStartClicked() { - engine.running = !engine.running; + engine.toggleRunning(); } void onStepClicked() { @@ -35,8 +32,7 @@ class ControlsComponent { } void onRandomClicked() { - engine.running = false; - engine.addPattern(); + engine.addRandomPattern(); } void onClearClicked() { diff --git a/lib/components/simulation_component.dart b/lib/components/simulation_component.dart index e64fa82..c372026 100644 --- a/lib/components/simulation_component.dart +++ b/lib/components/simulation_component.dart @@ -8,7 +8,6 @@ import 'package:rules_of_living/service/engine_service.dart'; templateUrl: "simulation_component.html", directives: [coreDirectives], providers: [], -// styleUrls: const ['package:angular_components/app_layout/layout.scss.css'], ) class SimulationComponent implements OnInit { final EngineService engineService; @@ -29,13 +28,6 @@ class SimulationComponent implements OnInit { If you see this\n the app is broken :( ''', canvas.width / 2 - 50, canvas.height / 2); - engineService.create(canvas); - - html.window.animationFrame.then(animFrame); - } - - void animFrame(num now) { - engineService.engine.process(now); - html.window.animationFrame.then(animFrame); +// engineService.create(canvas); } } diff --git a/lib/service/engine_service.dart b/lib/service/engine_service.dart index 5107f3c..6384f5f 100644 --- a/lib/service/engine_service.dart +++ b/lib/service/engine_service.dart @@ -5,7 +5,40 @@ import 'package:rules_of_living/src/Engine.dart'; class EngineService { Engine _engine; - Engine get engine => _engine; + Engine get engine => _engine ?? create(null); + + Engine create(html.CanvasElement canvas) { + _engine = Engine(canvas); + return _engine; + } + + void run() { + engine.running = true; + } + + void stop() { + engine.running = false; + } + + void toggleRunning() { + engine.running = !engine.running; + } + + void step() { + engine.step(); + } + + void reset() { + engine.reset(); + } + + void addRandomPattern() { + engine.running = false; + engine.addPattern(); + } + + void clear() { + engine.clear(); + } - void create(html.CanvasElement canvas) => _engine = Engine(canvas); } diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index a52df66..9b1814e 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -24,11 +24,17 @@ class Engine { final html.CanvasElement canvas; Grid _grid = new Grid(GRID_X, GRID_Y); - bool _running = false; + bool running = false; Engine([this.canvas]) { _elapsed.start(); _grid.addPattern(amount: 15, dispersal: 5); + html.window.animationFrame.then(animFrame); + } + + void animFrame(num now) { + process(now); + html.window.animationFrame.then(animFrame); } void reset() { @@ -95,7 +101,4 @@ class Engine { void toggleEdgeRendering() { _grid.renderEdges = !_grid.renderEdges; } - - void set running(bool on) => _running = on; - bool get running => _running; } From a8cafbac499a63a1d1ee75a3bded2d03e9d7fe46 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 25 Aug 2018 09:35:59 +0200 Subject: [PATCH 044/120] Migrate to official dart-sdk version 2.0.0 --- pubspec.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index 1e77191..4cc6f88 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ author: Marty Oehme homepage: https://www.martyoehme.org/ environment: - sdk: '>=2.0.0-dev.66.0 <2.0.0' + sdk: '>=2.0.0' dependencies: angular: ^5.0.0-beta @@ -14,6 +14,6 @@ dependencies: dev_dependencies: angular_test: ^2.0.0-beta build_runner: ^0.9.0 - build_test: ^0.10.2 + build_test: ^0.10.3+1 build_web_compilers: ^0.4.0 - test: ^1.0.0 + test: ^1.3.0 From 1bd324a4066ab49170baaef9079e612f468f6963 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Fri, 24 Aug 2018 20:01:36 +0200 Subject: [PATCH 045/120] Disable superfluous tests In preparation for first test of the app. --- test/{app_test.dart => app_test_disable.dart} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/{app_test.dart => app_test_disable.dart} (100%) diff --git a/test/app_test.dart b/test/app_test_disable.dart similarity index 100% rename from test/app_test.dart rename to test/app_test_disable.dart From 842cbeca1f9ab5313efb10bbbd9409240a485f30 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Fri, 24 Aug 2018 20:02:43 +0200 Subject: [PATCH 046/120] make canvas argument optional on instantiating engine --- lib/src/Engine.dart | 11 +++++++---- test/src/engine_test.dart | 12 ++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 test/src/engine_test.dart diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index 6f7ff16..a52df66 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -6,7 +6,7 @@ class Engine { // Elapsed Time Counter - useful for Safety Timeout Stopwatch _elapsed = new Stopwatch(); - // Game Tick Rate - *does* impact game speed + // Game Tick Rate - *does* impact game speed TODO add configurable option int _MS_PER_STEP = 1000 ~/ 3; // Max Frame (i.e. Rendering) rate - does *not* impact game speed @@ -15,14 +15,18 @@ class Engine { // ms stuck in updateloop after which game will declare itself unresponsive final int SAFETY_TIMEOUT = 2000; + // Grid Size TODO add as configurable option + static final GRID_X = 100; + static final GRID_Y = 100; + num _updateLag = 0.0; num _drawLag = 0.0; final html.CanvasElement canvas; - Grid _grid = new Grid(100, 100); + Grid _grid = new Grid(GRID_X, GRID_Y); bool _running = false; - Engine(this.canvas) { + Engine([this.canvas]) { _elapsed.start(); _grid.addPattern(amount: 15, dispersal: 5); } @@ -59,7 +63,6 @@ class Engine { } void update() { -// print("updating"); if (!_grid.update()) running = false; } diff --git a/test/src/engine_test.dart b/test/src/engine_test.dart new file mode 100644 index 0000000..92794ff --- /dev/null +++ b/test/src/engine_test.dart @@ -0,0 +1,12 @@ +@TestOn('browser') + +import 'dart:html'; + +import 'package:rules_of_living/src/Engine.dart'; +import 'package:test/test.dart'; + +void main() { + test("Engine can be instantiated without canvas", () { + expect(Engine(), isNot(throwsA(anything))); + }); +} \ No newline at end of file From 976ec8097da4de1fb302088100de7689c53e7bea Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 25 Aug 2018 09:33:15 +0200 Subject: [PATCH 047/120] Separate Engine Service Functionality from Component --- lib/components/controls_component.dart | 12 +++----- lib/components/simulation_component.dart | 10 +------ lib/service/engine_service.dart | 37 ++++++++++++++++++++++-- lib/src/Engine.dart | 11 ++++--- 4 files changed, 47 insertions(+), 23 deletions(-) diff --git a/lib/components/controls_component.dart b/lib/components/controls_component.dart index 1f2a65d..511a7d4 100644 --- a/lib/components/controls_component.dart +++ b/lib/components/controls_component.dart @@ -1,8 +1,6 @@ import 'package:angular/angular.dart'; import 'package:angular_components/angular_components.dart'; -import 'package:rules_of_living/service/configuration_service.dart'; import 'package:rules_of_living/service/engine_service.dart'; -import 'package:rules_of_living/src/Engine.dart'; @Component( selector: 'sim-controls', @@ -17,13 +15,12 @@ import 'package:rules_of_living/src/Engine.dart'; styleUrls: const ["controls_component.css"], ) class ControlsComponent { - final EngineService engineService; + final EngineService engine; - Engine get engine => engineService.engine; - ControlsComponent(this.engineService); + ControlsComponent(this.engine); void onStartClicked() { - engine.running = !engine.running; + engine.toggleRunning(); } void onStepClicked() { @@ -35,8 +32,7 @@ class ControlsComponent { } void onRandomClicked() { - engine.running = false; - engine.addPattern(); + engine.addRandomPattern(); } void onClearClicked() { diff --git a/lib/components/simulation_component.dart b/lib/components/simulation_component.dart index e64fa82..c372026 100644 --- a/lib/components/simulation_component.dart +++ b/lib/components/simulation_component.dart @@ -8,7 +8,6 @@ import 'package:rules_of_living/service/engine_service.dart'; templateUrl: "simulation_component.html", directives: [coreDirectives], providers: [], -// styleUrls: const ['package:angular_components/app_layout/layout.scss.css'], ) class SimulationComponent implements OnInit { final EngineService engineService; @@ -29,13 +28,6 @@ class SimulationComponent implements OnInit { If you see this\n the app is broken :( ''', canvas.width / 2 - 50, canvas.height / 2); - engineService.create(canvas); - - html.window.animationFrame.then(animFrame); - } - - void animFrame(num now) { - engineService.engine.process(now); - html.window.animationFrame.then(animFrame); +// engineService.create(canvas); } } diff --git a/lib/service/engine_service.dart b/lib/service/engine_service.dart index 5107f3c..6384f5f 100644 --- a/lib/service/engine_service.dart +++ b/lib/service/engine_service.dart @@ -5,7 +5,40 @@ import 'package:rules_of_living/src/Engine.dart'; class EngineService { Engine _engine; - Engine get engine => _engine; + Engine get engine => _engine ?? create(null); + + Engine create(html.CanvasElement canvas) { + _engine = Engine(canvas); + return _engine; + } + + void run() { + engine.running = true; + } + + void stop() { + engine.running = false; + } + + void toggleRunning() { + engine.running = !engine.running; + } + + void step() { + engine.step(); + } + + void reset() { + engine.reset(); + } + + void addRandomPattern() { + engine.running = false; + engine.addPattern(); + } + + void clear() { + engine.clear(); + } - void create(html.CanvasElement canvas) => _engine = Engine(canvas); } diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index a52df66..9b1814e 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -24,11 +24,17 @@ class Engine { final html.CanvasElement canvas; Grid _grid = new Grid(GRID_X, GRID_Y); - bool _running = false; + bool running = false; Engine([this.canvas]) { _elapsed.start(); _grid.addPattern(amount: 15, dispersal: 5); + html.window.animationFrame.then(animFrame); + } + + void animFrame(num now) { + process(now); + html.window.animationFrame.then(animFrame); } void reset() { @@ -95,7 +101,4 @@ class Engine { void toggleEdgeRendering() { _grid.renderEdges = !_grid.renderEdges; } - - void set running(bool on) => _running = on; - bool get running => _running; } From 572406b963d029884db7898a080372b9d8863664 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 25 Aug 2018 14:10:19 +0200 Subject: [PATCH 048/120] Fix undefined running access --- lib/components/controls_component.html | 2 +- lib/service/engine_service.dart | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/components/controls_component.html b/lib/components/controls_component.html index 30ddf55..42e79f7 100644 --- a/lib/components/controls_component.html +++ b/lib/components/controls_component.html @@ -1,7 +1,7 @@
- + diff --git a/lib/service/engine_service.dart b/lib/service/engine_service.dart index 6384f5f..f6c7304 100644 --- a/lib/service/engine_service.dart +++ b/lib/service/engine_service.dart @@ -41,4 +41,6 @@ class EngineService { engine.clear(); } + bool get isRunning => engine.running; + } From 4c6dff35c3c29b1db70b8aeef33d2602bcfcb9df Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 25 Aug 2018 14:10:56 +0200 Subject: [PATCH 049/120] Add Canvas nullcheck to render function --- lib/components/simulation_component.dart | 5 +++-- lib/src/Engine.dart | 7 +++---- test/src/engine_test.dart | 16 +++++++++++++--- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/lib/components/simulation_component.dart b/lib/components/simulation_component.dart index c372026..b7e817c 100644 --- a/lib/components/simulation_component.dart +++ b/lib/components/simulation_component.dart @@ -25,8 +25,9 @@ class SimulationComponent implements OnInit { canvas.context2D.fillRect(0, 0, canvas.width, canvas.height); canvas.context2D.setFillColorRgb(0, 255, 0); canvas.context2D.fillText(''' - If you see this\n - the app is broken :( + If you see this + + the canvas did not load correctly :( ''', canvas.width / 2 - 50, canvas.height / 2); // engineService.create(canvas); } diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index 9b1814e..601e5ac 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -22,7 +22,7 @@ class Engine { num _updateLag = 0.0; num _drawLag = 0.0; - final html.CanvasElement canvas; + html.CanvasElement canvas; Grid _grid = new Grid(GRID_X, GRID_Y); bool running = false; @@ -43,7 +43,7 @@ class Engine { } void clear() { - _grid = new Grid(100, 100); + _grid = new Grid(GRID_X, GRID_Y); running = false; } @@ -78,8 +78,7 @@ class Engine { } void render([num interp]) { -// print("rendering"); - _grid.render(canvas, interp); + if(canvas != null) _grid.render(canvas, interp); } void addPattern( diff --git a/test/src/engine_test.dart b/test/src/engine_test.dart index 92794ff..72f8b0d 100644 --- a/test/src/engine_test.dart +++ b/test/src/engine_test.dart @@ -1,12 +1,22 @@ @TestOn('browser') -import 'dart:html'; - import 'package:rules_of_living/src/Engine.dart'; import 'package:test/test.dart'; void main() { test("Engine can be instantiated without canvas", () { - expect(Engine(), isNot(throwsA(anything))); + expect(Engine(), isNot(throwsNoSuchMethodError)); + }); + + test("Engine does not throw errors when calling render directly", () { + Engine sut = new Engine(); + // anonymous function necessary since throws can not use functions with args + expect(() => sut.render(), isNot(throwsNoSuchMethodError)); + }); + + test("Engine does not throw errors when processing without attached canvas", () { + Engine sut = new Engine(); + // anonymous function necessary since throws can not use functions with args + expect(() => sut.process(1000), isNot(throwsNoSuchMethodError)); }); } \ No newline at end of file From 66bf87d9d875409b2fc4e74707268f9098a5ab68 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 25 Aug 2018 14:36:50 +0200 Subject: [PATCH 050/120] Allow setting a canvas for an engine at any point --- lib/src/Engine.dart | 20 ++++++++++++++++++++ test/src/engine_test.dart | 16 +++++++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index 601e5ac..539e6d2 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -22,6 +22,11 @@ class Engine { num _updateLag = 0.0; num _drawLag = 0.0; + /// The Canvas to Paint on + /// + /// Manually define or change the canvas the engine should render to. Should + /// be used if no canvas was defined at engine creation and it should be + /// rendered later. html.CanvasElement canvas; Grid _grid = new Grid(GRID_X, GRID_Y); bool running = false; @@ -68,15 +73,30 @@ class Engine { } } + /// Update Engine Logic + /// + /// Updates the logic of the engine by one tick. Should usually not be called + /// directly, since it is automatically taken care of by the processing function. + /// If simulation should be advanced manually one time, prefer using step(). void update() { if (!_grid.update()) running = false; } + /// Advances Logic One Update + /// + /// Moves logic of the engine one step forward and pauses the + /// simulation. Does not automatically re-render the new state + /// (though this should usually not pose a problem). void step() { running = false; _grid.update(); } + /// Renders the Current Simulation State + /// + /// Renders the simulation once. Will usually automatically be called by + /// the internal engine processing. Does not do anything if no canvas is + /// defined. void render([num interp]) { if(canvas != null) _grid.render(canvas, interp); } diff --git a/test/src/engine_test.dart b/test/src/engine_test.dart index 72f8b0d..0712ba8 100644 --- a/test/src/engine_test.dart +++ b/test/src/engine_test.dart @@ -1,22 +1,32 @@ +import 'dart:html' as html; + @TestOn('browser') import 'package:rules_of_living/src/Engine.dart'; import 'package:test/test.dart'; void main() { + Engine sut; + setUp(() { + sut = Engine(); + }); + test("Engine can be instantiated without canvas", () { - expect(Engine(), isNot(throwsNoSuchMethodError)); + expect(sut, isNot(throwsNoSuchMethodError)); }); test("Engine does not throw errors when calling render directly", () { - Engine sut = new Engine(); // anonymous function necessary since throws can not use functions with args expect(() => sut.render(), isNot(throwsNoSuchMethodError)); }); test("Engine does not throw errors when processing without attached canvas", () { - Engine sut = new Engine(); // anonymous function necessary since throws can not use functions with args expect(() => sut.process(1000), isNot(throwsNoSuchMethodError)); }); + + test("setCanvas allows setting a canvas for an engine at any point", () { + sut.canvas = new html.CanvasElement(); + expect(sut.canvas, isNotNull); + }); } \ No newline at end of file From cc33628e5fd81e0702a48ecb20677b97adb3ae58 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 25 Aug 2018 14:51:28 +0200 Subject: [PATCH 051/120] Enable cached engine returns for EngineService --- lib/service/engine_service.dart | 6 ++++-- test/service/engine_service_test.dart | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 test/service/engine_service_test.dart diff --git a/lib/service/engine_service.dart b/lib/service/engine_service.dart index f6c7304..69f4699 100644 --- a/lib/service/engine_service.dart +++ b/lib/service/engine_service.dart @@ -5,13 +5,15 @@ import 'package:rules_of_living/src/Engine.dart'; class EngineService { Engine _engine; - Engine get engine => _engine ?? create(null); + Engine get engine => _engine ?? createEngine(null); - Engine create(html.CanvasElement canvas) { + Engine createEngine(html.CanvasElement canvas) { _engine = Engine(canvas); return _engine; } + void setCanvas(html.CanvasElement canvas) => engine.canvas = canvas; + void run() { engine.running = true; } diff --git a/test/service/engine_service_test.dart b/test/service/engine_service_test.dart new file mode 100644 index 0000000..9d4a226 --- /dev/null +++ b/test/service/engine_service_test.dart @@ -0,0 +1,19 @@ +@TestOn('browser') + +import 'package:test/test.dart'; +import 'package:rules_of_living/service/engine_service.dart'; + +void main() { + EngineService sut; + setUp(() { + sut = EngineService(); + }); + + test("EngineService creates an engine on demand", () { + expect(sut.engine, isNotNull); + }); + + test("EngineService returns the cached engine on subsequent requests", () { + expect(sut.engine, allOf(isNotNull, equals(sut.engine))); + }); +} From 71023de49a68e27a8cd07c361a1d8588eda53760 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 25 Aug 2018 15:00:46 +0200 Subject: [PATCH 052/120] Make canvas virtual variable on EngineService --- lib/service/engine_service.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/service/engine_service.dart b/lib/service/engine_service.dart index 69f4699..d7b0bed 100644 --- a/lib/service/engine_service.dart +++ b/lib/service/engine_service.dart @@ -12,7 +12,8 @@ class EngineService { return _engine; } - void setCanvas(html.CanvasElement canvas) => engine.canvas = canvas; + void set canvas(html.CanvasElement canvas) => engine.canvas = canvas; + html.CanvasElement get canvas => engine.canvas; void run() { engine.running = true; From 3c27f5ef38f76ccc6dfaee5cd4d45e9d58554a8c Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 25 Aug 2018 15:01:00 +0200 Subject: [PATCH 053/120] Re-Add Canvas to Simulation component --- lib/components/simulation_component.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/components/simulation_component.dart b/lib/components/simulation_component.dart index b7e817c..12b7844 100644 --- a/lib/components/simulation_component.dart +++ b/lib/components/simulation_component.dart @@ -29,6 +29,6 @@ class SimulationComponent implements OnInit { the canvas did not load correctly :( ''', canvas.width / 2 - 50, canvas.height / 2); -// engineService.create(canvas); + engineService.canvas = canvas; } } From 588a3ad2a0dcd60dc2d96f2a42bf633d2b8f5c5c Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 25 Aug 2018 15:26:44 +0200 Subject: [PATCH 054/120] Add explicit getter and setter for Simulation Speed In preparation for adding additional logic as a quasi-callback to execute whenever the simSpeed changes (i.e. the slider is changed) --- lib/service/configuration_service.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/service/configuration_service.dart b/lib/service/configuration_service.dart index 7da2ca6..083b7fb 100644 --- a/lib/service/configuration_service.dart +++ b/lib/service/configuration_service.dart @@ -4,7 +4,12 @@ class ConfigurationService { final EngineService engineService; bool showGrid; - int simSpeed; + + int _simSpeed; + int get simSpeed => _simSpeed; + void set simSpeed(int val) { + _simSpeed = 5; + } ConfigurationService(this.engineService) { showGrid = false; From 905af769f641a98fdf0b45c77fcb3fe43e8daffb Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 25 Aug 2018 15:51:17 +0200 Subject: [PATCH 055/120] Add Configurable stepsPerSecond for engine logic --- lib/src/Engine.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index 539e6d2..d15987d 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -8,6 +8,8 @@ class Engine { // Game Tick Rate - *does* impact game speed TODO add configurable option int _MS_PER_STEP = 1000 ~/ 3; + int get stepsPerSecond => 1000 ~/ _MS_PER_STEP; + set stepsPerSecond(int val) => _MS_PER_STEP = 1000 ~/ val; // Max Frame (i.e. Rendering) rate - does *not* impact game speed final int _MS_PER_FRAME = 1000 ~/ 30; From c3f0881454d39332c60972bbb64c8cdbcc93e04a Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 25 Aug 2018 15:51:32 +0200 Subject: [PATCH 056/120] Wire up Speed slider to Engine Configuration --- lib/service/configuration_service.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/service/configuration_service.dart b/lib/service/configuration_service.dart index 083b7fb..d8c6084 100644 --- a/lib/service/configuration_service.dart +++ b/lib/service/configuration_service.dart @@ -8,7 +8,8 @@ class ConfigurationService { int _simSpeed; int get simSpeed => _simSpeed; void set simSpeed(int val) { - _simSpeed = 5; + _simSpeed = val; + engineService.engine.stepsPerSecond = simSpeed; } ConfigurationService(this.engineService) { From 774e9e3782d21b4853423b14680b6cb7e824f583 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 25 Aug 2018 16:41:11 +0200 Subject: [PATCH 057/120] Add Simple Documentation --- lib/service/configuration_service.dart | 6 ++++++ lib/src/Engine.dart | 13 ++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/service/configuration_service.dart b/lib/service/configuration_service.dart index d8c6084..93b89d7 100644 --- a/lib/service/configuration_service.dart +++ b/lib/service/configuration_service.dart @@ -6,6 +6,12 @@ class ConfigurationService { bool showGrid; int _simSpeed; + + /// Simulation Speed + /// + /// Sets the number of updates the simulation takes per second. Can range from + /// 1 to arbitrarily high numbers (though setting it too high can potentially + /// make the app brittle). int get simSpeed => _simSpeed; void set simSpeed(int val) { _simSpeed = val; diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index d15987d..be3f31f 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -6,8 +6,19 @@ class Engine { // Elapsed Time Counter - useful for Safety Timeout Stopwatch _elapsed = new Stopwatch(); - // Game Tick Rate - *does* impact game speed TODO add configurable option + /// Game Tick Rate + /// + /// *does* impact game speed; dictates how long each logic step takes. Only + /// interesting for engine internal calculations, to set simulation speed + /// from the outside use stepsPerSecond instead. int _MS_PER_STEP = 1000 ~/ 3; + + /// Set Logic Updates per Second + /// + /// Dictates simulation speed. Sets the amount of (logic) updates per second. + /// Translations between number of updates and their timings is not exact so + /// comparing this variable to fixed ints might not yield the expected results. + /// Does not affect render frequency, which is handled by framesPerSecond. int get stepsPerSecond => 1000 ~/ _MS_PER_STEP; set stepsPerSecond(int val) => _MS_PER_STEP = 1000 ~/ val; From 952179eee3f98a61e8e9367fbb726d0182cc90e9 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 25 Aug 2018 16:43:38 +0200 Subject: [PATCH 058/120] Implement Test Case --- pubspec.yaml | 1 + test/service/configuration_service_test.dart | 30 ++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 test/service/configuration_service_test.dart diff --git a/pubspec.yaml b/pubspec.yaml index 4cc6f88..a63ea9a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,3 +17,4 @@ dev_dependencies: build_test: ^0.10.3+1 build_web_compilers: ^0.4.0 test: ^1.3.0 + mockito: ^3.0.0 diff --git a/test/service/configuration_service_test.dart b/test/service/configuration_service_test.dart new file mode 100644 index 0000000..1afa50a --- /dev/null +++ b/test/service/configuration_service_test.dart @@ -0,0 +1,30 @@ +import 'package:rules_of_living/src/Engine.dart'; +@TestOn('browser') + +import 'package:test/test.dart'; +import 'package:rules_of_living/service/configuration_service.dart'; +import 'package:rules_of_living/service/engine_service.dart'; +import 'package:mockito/mockito.dart'; + +class MockEngine extends Mock implements Engine {} +class MockEngineService extends Mock implements EngineService { + MockEngine _engine = MockEngine(); + @override + Engine get engine => _engine; +} + +void main() { + group("simulation speed", () { + ConfigurationService sut; + MockEngineService mes; + setUp(() { + mes = MockEngineService(); + sut = ConfigurationService(mes); + }); + + test("speed changes propagate to engine", () { + sut.simSpeed = 312; + verify(mes.engine.stepsPerSecond=312); + }); + }); +} From 7a3fdf3681f86b45b0a71839f993fe62cb0d3227 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 25 Aug 2018 16:43:47 +0200 Subject: [PATCH 059/120] Fix Engine Test case --- test/src/engine_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/engine_test.dart b/test/src/engine_test.dart index 0712ba8..43ea13e 100644 --- a/test/src/engine_test.dart +++ b/test/src/engine_test.dart @@ -17,12 +17,12 @@ void main() { test("Engine does not throw errors when calling render directly", () { // anonymous function necessary since throws can not use functions with args - expect(() => sut.render(), isNot(throwsNoSuchMethodError)); + expect(() => sut.render, isNot(throwsNoSuchMethodError)); }); test("Engine does not throw errors when processing without attached canvas", () { // anonymous function necessary since throws can not use functions with args - expect(() => sut.process(1000), isNot(throwsNoSuchMethodError)); + expect(() => sut.process, isNot(throwsNoSuchMethodError)); }); test("setCanvas allows setting a canvas for an engine at any point", () { From dd18fc3bc7ded19b134e26867988bdb48455d2bb Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Sat, 25 Aug 2018 17:23:06 +0200 Subject: [PATCH 060/120] Make Engine Gridsize configurable --- lib/src/Engine.dart | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index be3f31f..b05f79c 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -1,4 +1,5 @@ import 'dart:html' as html; +import 'dart:math'; import 'package:rules_of_living/src/Grid.dart'; @@ -28,9 +29,10 @@ class Engine { // ms stuck in updateloop after which game will declare itself unresponsive final int SAFETY_TIMEOUT = 2000; - // Grid Size TODO add as configurable option - static final GRID_X = 100; - static final GRID_Y = 100; + /// Grid Size + /// + /// Number of cells on x coordinate and y coordinate. Can be set individually. + Point gridSize = Point(100, 100); num _updateLag = 0.0; num _drawLag = 0.0; @@ -41,10 +43,12 @@ class Engine { /// be used if no canvas was defined at engine creation and it should be /// rendered later. html.CanvasElement canvas; - Grid _grid = new Grid(GRID_X, GRID_Y); + Grid _grid; bool running = false; Engine([this.canvas]) { + _grid = Grid(gridSize.x, gridSize.y); + _elapsed.start(); _grid.addPattern(amount: 15, dispersal: 5); html.window.animationFrame.then(animFrame); @@ -61,7 +65,7 @@ class Engine { } void clear() { - _grid = new Grid(GRID_X, GRID_Y); + _grid = new Grid(gridSize.x, gridSize.y); running = false; } From 5e8f83cf8a6cb186dc4d77bec58aa3e57b86ad53 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 27 Aug 2018 19:33:17 +0200 Subject: [PATCH 061/120] Refactor EngineService to be able to inject custom Engine fixes #38 --- lib/service/engine_service.dart | 7 +++--- test/service/engine_service_test.dart | 32 ++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/lib/service/engine_service.dart b/lib/service/engine_service.dart index d7b0bed..f43cd55 100644 --- a/lib/service/engine_service.dart +++ b/lib/service/engine_service.dart @@ -5,10 +5,10 @@ import 'package:rules_of_living/src/Engine.dart'; class EngineService { Engine _engine; - Engine get engine => _engine ?? createEngine(null); + Engine get engine => _engine ?? getEngine(Engine()); - Engine createEngine(html.CanvasElement canvas) { - _engine = Engine(canvas); + Engine getEngine(Engine engine) { + _engine = engine; return _engine; } @@ -45,5 +45,4 @@ class EngineService { } bool get isRunning => engine.running; - } diff --git a/test/service/engine_service_test.dart b/test/service/engine_service_test.dart index 9d4a226..209fd47 100644 --- a/test/service/engine_service_test.dart +++ b/test/service/engine_service_test.dart @@ -1,19 +1,41 @@ @TestOn('browser') - import 'package:test/test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:rules_of_living/src/Engine.dart'; import 'package:rules_of_living/service/engine_service.dart'; +class MockEngine extends Mock implements Engine {} + void main() { EngineService sut; + MockEngine me; setUp(() { + me = MockEngine(); sut = EngineService(); }); + group("Dependency Injection", () { + test("EngineService accesses the Engine defined in getEngine", () { + sut.getEngine(me); - test("EngineService creates an engine on demand", () { - expect(sut.engine, isNotNull); + Engine result = sut.engine; + expect(result, equals(me)); + }); }); + group("caching", () { + test("EngineService creates an engine on demand", () { + Engine result = sut.engine; + expect(result, TypeMatcher()); + }); - test("EngineService returns the cached engine on subsequent requests", () { - expect(sut.engine, allOf(isNotNull, equals(sut.engine))); + test("EngineService returns the cached engine on subsequent requests", () { + Engine result = sut.engine; + expect(sut.engine, equals(result)); + }); + test("caching can be overriden by providing a custom engine", () { + Engine first = sut.engine; + sut.getEngine(me); + Engine second = sut.engine; + expect(second, isNot(equals(first))); + }); }); } From 9886f13d69bf07eb6e46e4414c633bda91cfc0ee Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 27 Aug 2018 19:55:30 +0200 Subject: [PATCH 062/120] Add grid changing function --- lib/service/configuration_service.dart | 10 ++++- test/service/configuration_service_test.dart | 44 +++++++++++++------- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/lib/service/configuration_service.dart b/lib/service/configuration_service.dart index 93b89d7..8ca89ec 100644 --- a/lib/service/configuration_service.dart +++ b/lib/service/configuration_service.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:rules_of_living/service/engine_service.dart'; class ConfigurationService { @@ -26,4 +28,10 @@ class ConfigurationService { void toggleGrid() { showGrid = !showGrid; } -} \ No newline at end of file + + void setGridSize({int x, int y}) { + x = x ?? engineService.engine.gridSize.x; + y = y ?? engineService.engine.gridSize.y; + engineService.engine.gridSize = Point(x, y); + } +} diff --git a/test/service/configuration_service_test.dart b/test/service/configuration_service_test.dart index 1afa50a..f28f6e8 100644 --- a/test/service/configuration_service_test.dart +++ b/test/service/configuration_service_test.dart @@ -1,30 +1,46 @@ +import 'dart:math'; + import 'package:rules_of_living/src/Engine.dart'; @TestOn('browser') - import 'package:test/test.dart'; import 'package:rules_of_living/service/configuration_service.dart'; import 'package:rules_of_living/service/engine_service.dart'; import 'package:mockito/mockito.dart'; class MockEngine extends Mock implements Engine {} -class MockEngineService extends Mock implements EngineService { - MockEngine _engine = MockEngine(); - @override - Engine get engine => _engine; -} void main() { - group("simulation speed", () { - ConfigurationService sut; - MockEngineService mes; - setUp(() { - mes = MockEngineService(); - sut = ConfigurationService(mes); - }); + ConfigurationService sut; + EngineService engineService; + MockEngine me; + setUp(() { + me = MockEngine(); + engineService = EngineService(); + engineService.getEngine(me); + sut = ConfigurationService(engineService); + }); + group("simulation speed", () { test("speed changes propagate to engine", () { sut.simSpeed = 312; - verify(mes.engine.stepsPerSecond=312); + verify(me.stepsPerSecond = 312); + }); + }); + + group("grid size", () { + test("grid changes are sent to engine", () { + sut.setGridSize(x: 512, y: 388); + verify(me.gridSize = Point(512, 388)); + }); + test("grid can be changed solely on x axis", () { + when(me.gridSize).thenReturn(Point(100, 100)); + sut.setGridSize(x: 555); + verify(me.gridSize = Point(555, 100)); + }); + test("grid can be changed solely on y axis", () { + when(me.gridSize).thenReturn(Point(100, 100)); + sut.setGridSize(y: 556); + verify(me.gridSize = Point(100, 556)); }); }); } From 873bd9c8814b8105b50611d00bc389d09e65b924 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 27 Aug 2018 20:13:19 +0200 Subject: [PATCH 063/120] Allow Optional Injection of grid size into engine on creation --- lib/src/Engine.dart | 6 ++--- test/service/engine_service_test.dart | 6 ++--- test/src/engine_test.dart | 33 +++++++++++++++------------ 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index b05f79c..aa2a36c 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -46,8 +46,8 @@ class Engine { Grid _grid; bool running = false; - Engine([this.canvas]) { - _grid = Grid(gridSize.x, gridSize.y); + Engine([x = 100, y = 100, this.canvas]) { + _grid = Grid(x, y); _elapsed.start(); _grid.addPattern(amount: 15, dispersal: 5); @@ -115,7 +115,7 @@ class Engine { /// the internal engine processing. Does not do anything if no canvas is /// defined. void render([num interp]) { - if(canvas != null) _grid.render(canvas, interp); + if (canvas != null) _grid.render(canvas, interp); } void addPattern( diff --git a/test/service/engine_service_test.dart b/test/service/engine_service_test.dart index 209fd47..cbd9655 100644 --- a/test/service/engine_service_test.dart +++ b/test/service/engine_service_test.dart @@ -1,8 +1,8 @@ +import 'package:mockito/mockito.dart'; +import 'package:rules_of_living/service/engine_service.dart'; +import 'package:rules_of_living/src/Engine.dart'; @TestOn('browser') import 'package:test/test.dart'; -import 'package:mockito/mockito.dart'; -import 'package:rules_of_living/src/Engine.dart'; -import 'package:rules_of_living/service/engine_service.dart'; class MockEngine extends Mock implements Engine {} diff --git a/test/src/engine_test.dart b/test/src/engine_test.dart index 43ea13e..7707418 100644 --- a/test/src/engine_test.dart +++ b/test/src/engine_test.dart @@ -10,23 +10,26 @@ void main() { setUp(() { sut = Engine(); }); + group("canvas", () { + test("Engine can be instantiated without canvas", () { + expect(sut, isNot(throwsNoSuchMethodError)); + }); - test("Engine can be instantiated without canvas", () { - expect(sut, isNot(throwsNoSuchMethodError)); - }); + test("Engine does not throw errors when calling render directly", () { + // anonymous function necessary since throws can not use functions with args + expect(() => sut.render, isNot(throwsNoSuchMethodError)); + }); - test("Engine does not throw errors when calling render directly", () { - // anonymous function necessary since throws can not use functions with args - expect(() => sut.render, isNot(throwsNoSuchMethodError)); - }); + test("Engine does not throw errors when processing without attached canvas", + () { + // anonymous function necessary since throws can not use functions with args + expect(() => sut.process, isNot(throwsNoSuchMethodError)); + }); - test("Engine does not throw errors when processing without attached canvas", () { - // anonymous function necessary since throws can not use functions with args - expect(() => sut.process, isNot(throwsNoSuchMethodError)); + test("setCanvas allows setting a canvas for an engine at any point", () { + sut.canvas = new html.CanvasElement(); + expect(sut.canvas, isNotNull); + }); }); - - test("setCanvas allows setting a canvas for an engine at any point", () { - sut.canvas = new html.CanvasElement(); - expect(sut.canvas, isNotNull); }); -} \ No newline at end of file +} From 04d61bfa029128fd705ad879f5cb0dbb5286f66c Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 27 Aug 2018 20:18:19 +0200 Subject: [PATCH 064/120] Error out on bad gridsize input --- lib/src/Engine.dart | 7 ++++++- test/src/engine_test.dart | 9 ++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index aa2a36c..b06e53a 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -32,7 +32,12 @@ class Engine { /// Grid Size /// /// Number of cells on x coordinate and y coordinate. Can be set individually. - Point gridSize = Point(100, 100); + Point get gridSize => Point(_grid.w, _grid.h); + void set gridSize(Point value) { + if (value.x <= 0 || value.y <= 0) + throw ArgumentError("grid size must not be smaller than 1"); + _grid = Grid(value.x, value.y); + } num _updateLag = 0.0; num _drawLag = 0.0; diff --git a/test/src/engine_test.dart b/test/src/engine_test.dart index 7707418..fcfefc2 100644 --- a/test/src/engine_test.dart +++ b/test/src/engine_test.dart @@ -1,7 +1,7 @@ import 'dart:html' as html; +import 'dart:math'; @TestOn('browser') - import 'package:rules_of_living/src/Engine.dart'; import 'package:test/test.dart'; @@ -31,5 +31,12 @@ void main() { expect(sut.canvas, isNotNull); }); }); + group("gridSize", () { + test("zero gridSizes throw ArgumentErrors", () { + expect(() => sut.gridSize = Point(0, 5), throwsArgumentError); + }); + test("negative gridSizes throw ArgumentErrors", () { + expect(() => sut.gridSize = Point(1, -5), throwsArgumentError); + }); }); } From a92b864dfa9b5cb2f9bb4aa5aab0199863dd47a6 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 27 Aug 2018 20:50:12 +0200 Subject: [PATCH 065/120] Extract EngineService into separate service --- lib/app_component.dart | 13 +++++- lib/components/controls_component.dart | 16 +++---- lib/components/simulation_component.dart | 8 ++-- lib/service/configuration_service.dart | 12 ++--- lib/service/control_service.dart | 43 ++++++++++++++++++ lib/service/engine_service.dart | 47 +++----------------- test/service/configuration_service_test.dart | 8 ++-- test/service/engine_service_test.dart | 6 +-- 8 files changed, 86 insertions(+), 67 deletions(-) create mode 100644 lib/service/control_service.dart diff --git a/lib/app_component.dart b/lib/app_component.dart index e9b44cc..c9f05e1 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -5,6 +5,7 @@ import 'package:rules_of_living/components/controls_component.dart'; import 'package:rules_of_living/components/header_component.dart'; import 'package:rules_of_living/components/simulation_component.dart'; import 'package:rules_of_living/service/configuration_service.dart'; +import 'package:rules_of_living/service/control_service.dart'; import 'package:rules_of_living/service/engine_service.dart'; @Component( @@ -20,8 +21,16 @@ import 'package:rules_of_living/service/engine_service.dart'; ControlsComponent, ConfigurationComponent ], - providers: [materialProviders, ClassProvider(EngineService), ClassProvider(ConfigurationService)], - styleUrls: const ['package:angular_components/app_layout/layout.scss.css', 'app_component.css'], + providers: [ + materialProviders, + ClassProvider(EngineService), + ClassProvider(ConfigurationService), + ClassProvider(EngineService) + ], + styleUrls: const [ + 'package:angular_components/app_layout/layout.scss.css', + 'app_component.css' + ], ) class AppComponent { var name = "World"; diff --git a/lib/components/controls_component.dart b/lib/components/controls_component.dart index 511a7d4..954d94b 100644 --- a/lib/components/controls_component.dart +++ b/lib/components/controls_component.dart @@ -1,6 +1,6 @@ import 'package:angular/angular.dart'; import 'package:angular_components/angular_components.dart'; -import 'package:rules_of_living/service/engine_service.dart'; +import 'package:rules_of_living/service/control_service.dart'; @Component( selector: 'sim-controls', @@ -15,27 +15,27 @@ import 'package:rules_of_living/service/engine_service.dart'; styleUrls: const ["controls_component.css"], ) class ControlsComponent { - final EngineService engine; + final ControlService ctrl; - ControlsComponent(this.engine); + ControlsComponent(this.ctrl); void onStartClicked() { - engine.toggleRunning(); + ctrl.toggleRunning(); } void onStepClicked() { - engine.step(); + ctrl.step(); } void onResetClicked() { - engine.reset(); + ctrl.reset(); } void onRandomClicked() { - engine.addRandomPattern(); + ctrl.addRandomPattern(); } void onClearClicked() { - engine.clear(); + ctrl.clear(); } } diff --git a/lib/components/simulation_component.dart b/lib/components/simulation_component.dart index 12b7844..99b3f02 100644 --- a/lib/components/simulation_component.dart +++ b/lib/components/simulation_component.dart @@ -1,7 +1,7 @@ import 'dart:html' as html; import 'package:angular/angular.dart'; -import 'package:rules_of_living/service/engine_service.dart'; +import 'package:rules_of_living/service/control_service.dart'; @Component( selector: 'gol-simulation', @@ -10,9 +10,9 @@ import 'package:rules_of_living/service/engine_service.dart'; providers: [], ) class SimulationComponent implements OnInit { - final EngineService engineService; + final ControlService ctrl; - SimulationComponent(this.engineService); + SimulationComponent(this.ctrl); @override void ngOnInit() { @@ -29,6 +29,6 @@ class SimulationComponent implements OnInit { the canvas did not load correctly :( ''', canvas.width / 2 - 50, canvas.height / 2); - engineService.canvas = canvas; + ctrl.canvas = canvas; } } diff --git a/lib/service/configuration_service.dart b/lib/service/configuration_service.dart index 8ca89ec..edee10c 100644 --- a/lib/service/configuration_service.dart +++ b/lib/service/configuration_service.dart @@ -3,7 +3,7 @@ import 'dart:math'; import 'package:rules_of_living/service/engine_service.dart'; class ConfigurationService { - final EngineService engineService; + final EngineService _es; bool showGrid; @@ -17,10 +17,10 @@ class ConfigurationService { int get simSpeed => _simSpeed; void set simSpeed(int val) { _simSpeed = val; - engineService.engine.stepsPerSecond = simSpeed; + _es.engine.stepsPerSecond = simSpeed; } - ConfigurationService(this.engineService) { + ConfigurationService(this._es) { showGrid = false; simSpeed = 5; } @@ -30,8 +30,8 @@ class ConfigurationService { } void setGridSize({int x, int y}) { - x = x ?? engineService.engine.gridSize.x; - y = y ?? engineService.engine.gridSize.y; - engineService.engine.gridSize = Point(x, y); + x = x ?? _es.engine.gridSize.x; + y = y ?? _es.engine.gridSize.y; + _es.engine.gridSize = Point(x, y); } } diff --git a/lib/service/control_service.dart b/lib/service/control_service.dart new file mode 100644 index 0000000..abc1f57 --- /dev/null +++ b/lib/service/control_service.dart @@ -0,0 +1,43 @@ +import 'dart:html' as html; + +import 'package:rules_of_living/service/engine_service.dart'; + +class ControlService { + EngineService _es; + + ControlService(this._es); + + void set canvas(html.CanvasElement canvas) => _es.engine.canvas = canvas; + html.CanvasElement get canvas => _es.engine.canvas; + + void run() { + _es.engine.running = true; + } + + void stop() { + _es.engine.running = false; + } + + void toggleRunning() { + _es.engine.running = !_es.engine.running; + } + + void step() { + _es.engine.step(); + } + + void reset() { + _es.engine.reset(); + } + + void addRandomPattern() { + _es.engine.running = false; + _es.engine.addPattern(); + } + + void clear() { + _es.engine.clear(); + } + + bool get isRunning => _es.engine.running; +} diff --git a/lib/service/engine_service.dart b/lib/service/engine_service.dart index f43cd55..8168735 100644 --- a/lib/service/engine_service.dart +++ b/lib/service/engine_service.dart @@ -1,48 +1,15 @@ -import 'dart:html' as html; - import 'package:rules_of_living/src/Engine.dart'; class EngineService { - Engine _engine; + Engine _uncachedEngineAccess; - Engine get engine => _engine ?? getEngine(Engine()); - - Engine getEngine(Engine engine) { - _engine = engine; - return _engine; + Engine get engine => _uncachedEngineAccess ?? _setCachedAndReturn(Engine()); + void set engine(Engine newEngine) { + _uncachedEngineAccess = newEngine; } - void set canvas(html.CanvasElement canvas) => engine.canvas = canvas; - html.CanvasElement get canvas => engine.canvas; - - void run() { - engine.running = true; + Engine _setCachedAndReturn(Engine newEngine) { + engine = newEngine; + return newEngine; } - - void stop() { - engine.running = false; - } - - void toggleRunning() { - engine.running = !engine.running; - } - - void step() { - engine.step(); - } - - void reset() { - engine.reset(); - } - - void addRandomPattern() { - engine.running = false; - engine.addPattern(); - } - - void clear() { - engine.clear(); - } - - bool get isRunning => engine.running; } diff --git a/test/service/configuration_service_test.dart b/test/service/configuration_service_test.dart index f28f6e8..44e23b2 100644 --- a/test/service/configuration_service_test.dart +++ b/test/service/configuration_service_test.dart @@ -1,11 +1,11 @@ import 'dart:math'; +import 'package:mockito/mockito.dart'; +import 'package:rules_of_living/service/configuration_service.dart'; +import 'package:rules_of_living/service/engine_service.dart'; import 'package:rules_of_living/src/Engine.dart'; @TestOn('browser') import 'package:test/test.dart'; -import 'package:rules_of_living/service/configuration_service.dart'; -import 'package:rules_of_living/service/engine_service.dart'; -import 'package:mockito/mockito.dart'; class MockEngine extends Mock implements Engine {} @@ -16,7 +16,7 @@ void main() { setUp(() { me = MockEngine(); engineService = EngineService(); - engineService.getEngine(me); + engineService.engine = me; sut = ConfigurationService(engineService); }); diff --git a/test/service/engine_service_test.dart b/test/service/engine_service_test.dart index cbd9655..a792b93 100644 --- a/test/service/engine_service_test.dart +++ b/test/service/engine_service_test.dart @@ -14,8 +14,8 @@ void main() { sut = EngineService(); }); group("Dependency Injection", () { - test("EngineService accesses the Engine defined in getEngine", () { - sut.getEngine(me); + test("EngineService can be passed a custom Engine", () { + sut.engine = me; Engine result = sut.engine; expect(result, equals(me)); @@ -33,7 +33,7 @@ void main() { }); test("caching can be overriden by providing a custom engine", () { Engine first = sut.engine; - sut.getEngine(me); + sut.engine = me; Engine second = sut.engine; expect(second, isNot(equals(first))); }); From b6919cff6bae126a05206086d57be3b6f56dce81 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 27 Aug 2018 20:55:55 +0200 Subject: [PATCH 066/120] Move Canvas setting to configuration service Fix #39 --- lib/components/simulation_component.dart | 8 ++++---- lib/service/configuration_service.dart | 12 ++++++++---- lib/service/control_service.dart | 5 ----- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/lib/components/simulation_component.dart b/lib/components/simulation_component.dart index 99b3f02..312eef4 100644 --- a/lib/components/simulation_component.dart +++ b/lib/components/simulation_component.dart @@ -1,7 +1,7 @@ import 'dart:html' as html; import 'package:angular/angular.dart'; -import 'package:rules_of_living/service/control_service.dart'; +import 'package:rules_of_living/service/configuration_service.dart'; @Component( selector: 'gol-simulation', @@ -10,9 +10,9 @@ import 'package:rules_of_living/service/control_service.dart'; providers: [], ) class SimulationComponent implements OnInit { - final ControlService ctrl; + final ConfigurationService config; - SimulationComponent(this.ctrl); + SimulationComponent(this.config); @override void ngOnInit() { @@ -29,6 +29,6 @@ class SimulationComponent implements OnInit { the canvas did not load correctly :( ''', canvas.width / 2 - 50, canvas.height / 2); - ctrl.canvas = canvas; + config.canvas = canvas; } } diff --git a/lib/service/configuration_service.dart b/lib/service/configuration_service.dart index edee10c..880cf45 100644 --- a/lib/service/configuration_service.dart +++ b/lib/service/configuration_service.dart @@ -1,3 +1,4 @@ +import 'dart:html' as html; import 'dart:math'; import 'package:rules_of_living/service/engine_service.dart'; @@ -9,6 +10,11 @@ class ConfigurationService { int _simSpeed; + ConfigurationService(this._es) { + showGrid = false; + simSpeed = 5; + } + /// Simulation Speed /// /// Sets the number of updates the simulation takes per second. Can range from @@ -20,10 +26,8 @@ class ConfigurationService { _es.engine.stepsPerSecond = simSpeed; } - ConfigurationService(this._es) { - showGrid = false; - simSpeed = 5; - } + void set canvas(html.CanvasElement canvas) => _es.engine.canvas = canvas; + html.CanvasElement get canvas => _es.engine.canvas; void toggleGrid() { showGrid = !showGrid; diff --git a/lib/service/control_service.dart b/lib/service/control_service.dart index abc1f57..0066106 100644 --- a/lib/service/control_service.dart +++ b/lib/service/control_service.dart @@ -1,5 +1,3 @@ -import 'dart:html' as html; - import 'package:rules_of_living/service/engine_service.dart'; class ControlService { @@ -7,9 +5,6 @@ class ControlService { ControlService(this._es); - void set canvas(html.CanvasElement canvas) => _es.engine.canvas = canvas; - html.CanvasElement get canvas => _es.engine.canvas; - void run() { _es.engine.running = true; } From 3a1ba1c1e95c9a173fe70a34c47c7c19aa30cf18 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 27 Aug 2018 23:02:48 +0200 Subject: [PATCH 067/120] Fix Wrong ControlService being provided to Angular --- lib/app_component.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/app_component.dart b/lib/app_component.dart index c9f05e1..ae8a931 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -25,7 +25,7 @@ import 'package:rules_of_living/service/engine_service.dart'; materialProviders, ClassProvider(EngineService), ClassProvider(ConfigurationService), - ClassProvider(EngineService) + ClassProvider(ControlService) ], styleUrls: const [ 'package:angular_components/app_layout/layout.scss.css', From 800c85d14fb5c192cb5170af6f74d933819a7d2b Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 27 Aug 2018 23:03:13 +0200 Subject: [PATCH 068/120] Fix wrong variable being accessed by controls_component --- lib/components/controls_component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/components/controls_component.html b/lib/components/controls_component.html index 42e79f7..b4c43f3 100644 --- a/lib/components/controls_component.html +++ b/lib/components/controls_component.html @@ -1,7 +1,7 @@
- + From b1221c7c84f8aa5df4fc7a620f0fcb7215575969 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 27 Aug 2018 23:03:35 +0200 Subject: [PATCH 069/120] Add Grid Size Input to Configuration Bar Fixes #37 --- lib/components/configuration_component.dart | 25 ++++++++++++++++++--- lib/components/configuration_component.html | 20 +++++++++++++++-- lib/service/configuration_service.dart | 2 ++ 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/lib/components/configuration_component.dart b/lib/components/configuration_component.dart index bd3ae0c..cc1ecd1 100644 --- a/lib/components/configuration_component.dart +++ b/lib/components/configuration_component.dart @@ -1,6 +1,8 @@ import 'package:angular/angular.dart'; import 'package:angular_components/material_button/material_button.dart'; import 'package:angular_components/material_icon/material_icon.dart'; +import 'package:angular_components/material_input/material_input.dart'; +import 'package:angular_components/material_input/material_number_accessor.dart'; import 'package:angular_components/material_slider/material_slider.dart'; import 'package:angular_components/material_tooltip/material_tooltip.dart'; import 'package:rules_of_living/service/configuration_service.dart'; @@ -8,18 +10,35 @@ import 'package:rules_of_living/service/configuration_service.dart'; @Component( selector: "configuration", templateUrl: "configuration_component.html", - styleUrls: ["configuration_component.css"], + styleUrls: [ + "configuration_component.css" + ], directives: [ MaterialButtonComponent, MaterialIconComponent, MaterialSliderComponent, - MaterialTooltipDirective + MaterialTooltipDirective, + materialInputDirectives, + materialNumberInputDirectives, + NgModel ]) class ConfigurationComponent { final ConfigurationService config; + int get width => config.gridSize.x; + void set width(num value) { + if (value == null || value <= 0) return; + config.setGridSize(x: value.toInt()); + } + + int get height => config.gridSize.y; + void set height(num value) { + if (value == null || value <= 0) return; + config.setGridSize(y: value.toInt()); + } + int get simSpeed => config.simSpeed; - int set simSpeed(int value) => config.simSpeed = value; + void set simSpeed(int value) => config.simSpeed = value; String get speedSliderTooltip => "Simulation Speed: $simSpeed"; diff --git a/lib/components/configuration_component.html b/lib/components/configuration_component.html index a17261d..d8a3e8b 100644 --- a/lib/components/configuration_component.html +++ b/lib/components/configuration_component.html @@ -1,5 +1,21 @@
- - + + + + Ruleset: + + +
\ No newline at end of file diff --git a/lib/service/configuration_service.dart b/lib/service/configuration_service.dart index 880cf45..e11a5e8 100644 --- a/lib/service/configuration_service.dart +++ b/lib/service/configuration_service.dart @@ -38,4 +38,6 @@ class ConfigurationService { y = y ?? _es.engine.gridSize.y; _es.engine.gridSize = Point(x, y); } + + Point get gridSize => _es.engine.gridSize; } From 0c487f3427ec76ee675e8c9b63ce62eeedecf57a Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Wed, 29 Aug 2018 20:11:56 +0200 Subject: [PATCH 070/120] Rename Grid to Simulation in order to craft an actual grid data structure --- lib/src/Engine.dart | 10 +++++----- lib/src/{Grid.dart => Simulation.dart} | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) rename lib/src/{Grid.dart => Simulation.dart} (99%) diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index b06e53a..84d52e8 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -1,7 +1,7 @@ import 'dart:html' as html; import 'dart:math'; -import 'package:rules_of_living/src/Grid.dart'; +import 'package:rules_of_living/src/Simulation.dart'; class Engine { // Elapsed Time Counter - useful for Safety Timeout @@ -36,7 +36,7 @@ class Engine { void set gridSize(Point value) { if (value.x <= 0 || value.y <= 0) throw ArgumentError("grid size must not be smaller than 1"); - _grid = Grid(value.x, value.y); + _grid = Simulation(value.x, value.y); } num _updateLag = 0.0; @@ -48,11 +48,11 @@ class Engine { /// be used if no canvas was defined at engine creation and it should be /// rendered later. html.CanvasElement canvas; - Grid _grid; + Simulation _grid; bool running = false; Engine([x = 100, y = 100, this.canvas]) { - _grid = Grid(x, y); + _grid = Simulation(x, y); _elapsed.start(); _grid.addPattern(amount: 15, dispersal: 5); @@ -70,7 +70,7 @@ class Engine { } void clear() { - _grid = new Grid(gridSize.x, gridSize.y); + _grid = new Simulation(gridSize.x, gridSize.y); running = false; } diff --git a/lib/src/Grid.dart b/lib/src/Simulation.dart similarity index 99% rename from lib/src/Grid.dart rename to lib/src/Simulation.dart index d95c25e..3b2c559 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Simulation.dart @@ -6,7 +6,7 @@ import 'package:rules_of_living/src/Rule.dart'; enum CellPattern { SpaceShip, Blinker } -class Grid { +class Simulation { final int w; final int h; final List> map; @@ -21,7 +21,7 @@ class Grid { int _dispersal; CellPattern _pattern; - Grid(int w, int h) + Simulation(int w, int h) : this.w = w, this.h = h, this.map = new List() { From 27ef72014e8b7a43c6a8e0af0b53e30f76a360fa Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Wed, 29 Aug 2018 22:12:19 +0200 Subject: [PATCH 071/120] Add simple Grid - List Wrapper Data Structure --- lib/src/Grid.dart | 22 ++++++++++ test/src/grid_test.dart | 91 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 lib/src/Grid.dart create mode 100644 test/src/grid_test.dart diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart new file mode 100644 index 0000000..540e9e7 --- /dev/null +++ b/lib/src/Grid.dart @@ -0,0 +1,22 @@ +import 'dart:core'; + +import 'package:collection/collection.dart'; + +class Grid extends DelegatingList { + final List _internal; + final width; + final height; + + Grid(int width, int height) : this._(List(width * height), width, height); + + Grid.from(Grid l) + : this._(List.from(l.getRange(0, l.length)), l.width, l.height); + + Grid.fromList(List l, int width) : this._(l, width, l.length ~/ width); + + Grid._(l, int w, int h) + : _internal = l, + width = w, + height = h, + super(l); +} diff --git a/test/src/grid_test.dart b/test/src/grid_test.dart new file mode 100644 index 0000000..2435ae1 --- /dev/null +++ b/test/src/grid_test.dart @@ -0,0 +1,91 @@ +import 'package:rules_of_living/src/Grid.dart'; +import 'package:test/test.dart'; + +@Tags(const ["nobrowser"]) +void main() { + Grid sut; + group("Instantiation", () { + List l; + setUp(() { + l = [ + "Hey", + "you", + "me", + "together", + "Hello", + "World", + "I", + "am", + "ready." + ]; + }); + test("gets created with the correct length for given quadratic gridsize", + () { + Grid sut = Grid(3, 3); + expect(sut.length, 9); + }); + test("gets created with the correct length for given rectangular gridsize", + () { + Grid sut = Grid(87, 85); + expect(sut.length, 7395); + }); + test("copies the content of another grid on .from Constructor call", () { + Grid original = Grid(2, 2); + original[0] = "Hey"; + original[1] = "you"; + original[2] = "me"; + original[3] = "together"; + + Grid sut = Grid.from(original); + expect(sut, containsAllInOrder(["Hey", "you", "me", "together"])); + }); + test("copies the length of another grid on .from Constructor call", () { + Grid original = Grid(2, 2); + original[0] = "Hey"; + original[1] = "you"; + original[2] = "me"; + original[3] = "together"; + + Grid sut = Grid.from(original); + expect(sut.length, 4); + }); + test("sets the length for list passed in on .fromList Constructor call", + () { + Grid sut = Grid.fromList(l, 3); + + expect(sut.length, 9); + }); + test("sets the contents of list passed in on .fromList Constructor call", + () { + Grid sut = Grid.fromList(l, 3); + + expect(sut[3], "together"); + }); + test( + "sets the correct height for list passed in on .fromList Constructor call", + () { + Grid sut = Grid.fromList(l, 3); + + expect(sut.width, 3); + }); + }); + group("getter", () { + setUp(() { + sut = Grid(3, 3); + sut.setAll(0, [ + "Hey", + "you", + "me", + "together", + "Hello", + "World", + "I", + "am", + "ready." + ]); + }); + test("Engine can be instantiated without canvas", () { + expect(sut, isNot(throwsNoSuchMethodError)); + }); + }); +} From b0e67d9f85f69a5cb5c2259d9c61c53a92784bdc Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Wed, 29 Aug 2018 22:13:13 +0200 Subject: [PATCH 072/120] Add getter and setter methods for wrapper !!Need testing --- lib/src/Grid.dart | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index 540e9e7..e6bf335 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -1,4 +1,5 @@ import 'dart:core'; +import 'dart:math'; import 'package:collection/collection.dart'; @@ -19,4 +20,24 @@ class Grid extends DelegatingList { width = w, height = h, super(l); + + E elementAtPos(int x, int y) { + int i = toIndex(x, y); + if (i >= length) throw RangeError.index(i, this); + _internal[i]; + } + + void setElement(int x, int y, E value) { + int i = toIndex(x, y); + if (i >= length) throw RangeError.index(i, this); + _internal[i] = value; + } + + E get(int x, int y) => elementAtPos(x, y); + + void set(int x, int y, E value) => setElement(x, y, value); + + int toIndex(int x, int y) => y * width + x; + + Point toCoords(int index) => Point(index % width, index ~/ width); } From 8865af4878a37fe1a83a4553c9416006be384d28 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 30 Aug 2018 09:36:57 +0200 Subject: [PATCH 073/120] Add tags to Instantiation tests --- test/src/grid_test.dart | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/src/grid_test.dart b/test/src/grid_test.dart index 2435ae1..290b183 100644 --- a/test/src/grid_test.dart +++ b/test/src/grid_test.dart @@ -23,12 +23,12 @@ void main() { () { Grid sut = Grid(3, 3); expect(sut.length, 9); - }); + }, tags: const ["happy"]); test("gets created with the correct length for given rectangular gridsize", () { Grid sut = Grid(87, 85); expect(sut.length, 7395); - }); + }, tags: const ["happy"]); test("copies the content of another grid on .from Constructor call", () { Grid original = Grid(2, 2); original[0] = "Hey"; @@ -38,7 +38,7 @@ void main() { Grid sut = Grid.from(original); expect(sut, containsAllInOrder(["Hey", "you", "me", "together"])); - }); + }, tags: const ["happy"]); test("copies the length of another grid on .from Constructor call", () { Grid original = Grid(2, 2); original[0] = "Hey"; @@ -48,26 +48,26 @@ void main() { Grid sut = Grid.from(original); expect(sut.length, 4); - }); + }, tags: const ["happy"]); test("sets the length for list passed in on .fromList Constructor call", () { Grid sut = Grid.fromList(l, 3); expect(sut.length, 9); - }); + }, tags: const ["happy"]); test("sets the contents of list passed in on .fromList Constructor call", () { Grid sut = Grid.fromList(l, 3); expect(sut[3], "together"); - }); + }, tags: const ["happy"]); test( "sets the correct height for list passed in on .fromList Constructor call", () { Grid sut = Grid.fromList(l, 3); expect(sut.width, 3); - }); + }, tags: const ["happy"]); }); group("getter", () { setUp(() { From 3f939601b3ac680e157144ff1d7a8565baff2f2b Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 30 Aug 2018 09:41:43 +0200 Subject: [PATCH 074/120] Add toIndex method can be used to get the correct index from coordinates passed in. Will only calculate the index, not take into consideration any grid size constraints etc. --- lib/src/Grid.dart | 9 ++++++++- test/src/grid_test.dart | 36 +++++++++++++++++++++--------------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index e6bf335..8fe745c 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -37,7 +37,14 @@ class Grid extends DelegatingList { void set(int x, int y, E value) => setElement(x, y, value); - int toIndex(int x, int y) => y * width + x; + /// Calculate list index from coordinates. + /// + /// Can be used to get the correct index from coordinates passed in. + /// Will only calculate the index, not take into consideration any grid size + /// constraints etc; use [get] for that (generally recommended). + int toIndex(int x, int y) => (x < 0 || y < 0) + ? throw RangeError("Coordinates for Grid Indexing must not be negative.") + : y * width + x; Point toCoords(int index) => Point(index % width, index ~/ width); } diff --git a/test/src/grid_test.dart b/test/src/grid_test.dart index 290b183..70adb30 100644 --- a/test/src/grid_test.dart +++ b/test/src/grid_test.dart @@ -3,7 +3,6 @@ import 'package:test/test.dart'; @Tags(const ["nobrowser"]) void main() { - Grid sut; group("Instantiation", () { List l; setUp(() { @@ -69,23 +68,30 @@ void main() { expect(sut.width, 3); }, tags: const ["happy"]); }); - group("getter", () { + group("toIndex", () { + Grid sut; setUp(() { sut = Grid(3, 3); - sut.setAll(0, [ - "Hey", - "you", - "me", - "together", - "Hello", - "World", - "I", - "am", - "ready." - ]); }); - test("Engine can be instantiated without canvas", () { - expect(sut, isNot(throwsNoSuchMethodError)); + test("throws RangeError on negative x argument", () { + expect(() => sut.toIndex(-1, 2), throwsA(isRangeError)); + }, tags: const ["bad"]); + test("throws RangeError on negative y argument", () { + expect(() => sut.toIndex(2, -1), throwsA(isRangeError)); + }, tags: const ["bad"]); + test("calculates correct index for first element", () { + expect(sut.toIndex(0, 0), equals(0)); + }, tags: const ["happy"]); + test("calculates correct index for last element", () { + expect(sut.toIndex(2, 2), equals(8)); + }, tags: const ["happy"]); + test("calculates correct index for element on first row", () { + expect(sut.toIndex(2, 0), equals(2)); + }, tags: const ["happy"]); + test("calculates correct index for example element", () { + expect(sut.toIndex(1, 1), equals(4)); + }, tags: const ["happy"]); + }); }); }); } From 46b11bc33b0ddf414b9d66da5b057ecd92072855 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 30 Aug 2018 09:42:29 +0200 Subject: [PATCH 075/120] Add dart_test.yaml file to suppress tag warnings tags are added in the file without any special options --- dart_test.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 dart_test.yaml diff --git a/dart_test.yaml b/dart_test.yaml new file mode 100644 index 0000000..a7c6d02 --- /dev/null +++ b/dart_test.yaml @@ -0,0 +1,10 @@ +platforms: [chrome] + +tags: + nobrowser: + + bad: + + sad: + + happy: From 6c3fcbe7b0a5b1f5c9eaecedb342a8656cbfeaee Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 30 Aug 2018 09:43:46 +0200 Subject: [PATCH 076/120] Add .get method for coordinate element retrieval to grid Coordinates passed in access the correct index in the internal list. --- lib/src/Grid.dart | 8 +++----- test/src/grid_test.dart | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index 8fe745c..bbe10eb 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -21,10 +21,10 @@ class Grid extends DelegatingList { height = h, super(l); - E elementAtPos(int x, int y) { + E get(int x, int y) { int i = toIndex(x, y); - if (i >= length) throw RangeError.index(i, this); - _internal[i]; + if (i >= length || x > width - 1) throw RangeError.index(i, this); + return _internal[i]; } void setElement(int x, int y, E value) { @@ -33,8 +33,6 @@ class Grid extends DelegatingList { _internal[i] = value; } - E get(int x, int y) => elementAtPos(x, y); - void set(int x, int y, E value) => setElement(x, y, value); /// Calculate list index from coordinates. diff --git a/test/src/grid_test.dart b/test/src/grid_test.dart index 70adb30..6190c7d 100644 --- a/test/src/grid_test.dart +++ b/test/src/grid_test.dart @@ -92,6 +92,27 @@ void main() { expect(sut.toIndex(1, 1), equals(4)); }, tags: const ["happy"]); }); + group("coordinates getter", () { + Grid sut; + setUp(() { + sut = Grid(3, 3); + sut.setAll(0, + ["Hey", "you", "me", "together", "Hello", null, "I", "am", "ready."]); }); + test("returns null if no element exists at the position requested", () { + expect(sut.get(2, 1), null); + }, tags: const ["sad"]); + test("throws RangeError if requesting element outside of grid width", () { + expect(() => sut.get(4, 1), throwsRangeError); + }, tags: const ["bad"]); + test("throws RangeError if requesting element outside of grid height", () { + expect(() => sut.get(1, 4), throwsRangeError); + }, tags: const ["bad"]); + test("returns element at correct index", () { + expect(sut.get(1, 0), "you"); + }, tags: const ["happy"]); + test("returns last element correctly", () { + expect(sut.get(2, 2), "ready."); + }, tags: const ["happy"]); }); } From 5a72783d57cc9837852ba6f4347f0464924cc2bd Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 30 Aug 2018 09:52:00 +0200 Subject: [PATCH 077/120] Add .toCoordinates() method to grid Calculates the 2-D array coordinates from the corresponding list index passed in. Relies on grid width to calculate coordinates. Does not check against grid size constraints. --- lib/src/Grid.dart | 11 +++++++++-- test/src/grid_test.dart | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index bbe10eb..04d8d3c 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -35,7 +35,7 @@ class Grid extends DelegatingList { void set(int x, int y, E value) => setElement(x, y, value); - /// Calculate list index from coordinates. + /// Calculate list index from coordinates /// /// Can be used to get the correct index from coordinates passed in. /// Will only calculate the index, not take into consideration any grid size @@ -44,5 +44,12 @@ class Grid extends DelegatingList { ? throw RangeError("Coordinates for Grid Indexing must not be negative.") : y * width + x; - Point toCoords(int index) => Point(index % width, index ~/ width); + /// Calculate coordinates from list index + /// + /// Calculates the 2-D array coordinates from the corresponding list index + /// passed in. Relies on grid width to calculate coordinates. Does not check + /// against grid size constraints; use [set] for that (generally recommended). + Point toCoordinates(int index) => (index < 0) + ? throw RangeError("Index for Grid Coordinates must not be negative") + : Point(index % width, index ~/ width); } diff --git a/test/src/grid_test.dart b/test/src/grid_test.dart index 6190c7d..1486ee9 100644 --- a/test/src/grid_test.dart +++ b/test/src/grid_test.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:rules_of_living/src/Grid.dart'; import 'package:test/test.dart'; @@ -115,4 +117,25 @@ void main() { expect(sut.get(2, 2), "ready."); }, tags: const ["happy"]); }); + group("toCoords", () { + Grid sut; + setUp(() { + sut = Grid(3, 3); + }); + test("throws RangeError on negative index argument", () { + expect(() => sut.toCoordinates(-1), throwsA(isRangeError)); + }, tags: const ["bad"]); + test("calculates correct index for first element", () { + expect(sut.toCoordinates(0), equals(Point(0, 0))); + }, tags: const ["happy"]); + test("calculates correct index for last element", () { + expect(sut.toCoordinates(8), equals(Point(2, 2))); + }, tags: const ["happy"]); + test("calculates correct index for last element on first row", () { + expect(sut.toCoordinates(2), equals(Point(2, 0))); + }, tags: const ["happy"]); + test("calculates correct index for example element", () { + expect(sut.toCoordinates(6), equals(Point(0, 2))); + }, tags: const ["happy"]); + }); } From 5725757aa0c7fef66d89c56788f53d3a8e2b4fbc Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 30 Aug 2018 09:55:25 +0200 Subject: [PATCH 078/120] Add Coordinate getter documentation --- lib/src/Grid.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index 04d8d3c..b009a99 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -21,6 +21,12 @@ class Grid extends DelegatingList { height = h, super(l); + /// Return element at coordinate position + /// + /// Returns the corresponding element after checking the parameters + /// for the correct constraints along the width and height of the grid. + /// Throws [RangeError] if outside of constraints. Preferred method + /// to access elements via coordinates. E get(int x, int y) { int i = toIndex(x, y); if (i >= length || x > width - 1) throw RangeError.index(i, this); From fb481669ed46dbd1e6e7abc0492bf5a969da217f Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 30 Aug 2018 10:02:29 +0200 Subject: [PATCH 079/120] Add Coordinates setter Sets the corresponding element to the parameter value passed in. Checks against the grid size constraints beforehand and throws RangeError if outside of constraints. Preferred method to set element via coordinates. --- lib/src/Grid.dart | 12 ++++++++---- test/src/grid_test.dart | 26 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index b009a99..40b87ea 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -33,14 +33,18 @@ class Grid extends DelegatingList { return _internal[i]; } - void setElement(int x, int y, E value) { + /// Sets element at coordinate position + /// + /// Sets the corresponding element to the [E] parameter [value] passed in. + /// Checks against the grid size constraints beforehand and throws + /// [RangeError] if outside of constraints. Preferred method to set + /// elements via coordinates. + void set(int x, int y, E value) { int i = toIndex(x, y); - if (i >= length) throw RangeError.index(i, this); + if (i >= length || x > width - 1) throw RangeError.index(i, this); _internal[i] = value; } - void set(int x, int y, E value) => setElement(x, y, value); - /// Calculate list index from coordinates /// /// Can be used to get the correct index from coordinates passed in. diff --git a/test/src/grid_test.dart b/test/src/grid_test.dart index 1486ee9..07dd467 100644 --- a/test/src/grid_test.dart +++ b/test/src/grid_test.dart @@ -138,4 +138,30 @@ void main() { expect(sut.toCoordinates(6), equals(Point(0, 2))); }, tags: const ["happy"]); }); + group("coordinates setter", () { + Grid sut; + setUp(() { + sut = Grid(3, 3); + sut.setAll(0, + ["Hey", "you", "me", "together", "Hello", null, "I", "am", "ready."]); + }); + test("sets element to null if passing null in", () { + sut.set(1, 1, null); + expect(sut.get(1, 1), null); + }, tags: const ["sad"]); + test("throws RangeError if setting element outside of grid width", () { + expect(() => sut.set(4, 1, "testValue"), throwsRangeError); + }, tags: const ["bad"]); + test("throws RangeError if setting element outside of grid height", () { + expect(() => sut.set(1, 4, "testValue"), throwsRangeError); + }, tags: const ["bad"]); + test("sets element at correct index", () { + sut.set(1, 0, "testValue"); + expect(sut.get(1, 0), "testValue"); + }, tags: const ["happy"]); + test("sets last element correctly", () { + sut.set(2, 2, "testValue"); + expect(sut.get(2, 2), "testValue"); + }, tags: const ["happy"]); + }); } From eef7a23c8f1e3cea8dbfe0d485b0a07de2659d6f Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 30 Aug 2018 10:17:31 +0200 Subject: [PATCH 080/120] Regroup Instantiation tests --- test/src/grid_test.dart | 72 ++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/test/src/grid_test.dart b/test/src/grid_test.dart index 07dd467..d6eae8f 100644 --- a/test/src/grid_test.dart +++ b/test/src/grid_test.dart @@ -30,45 +30,49 @@ void main() { Grid sut = Grid(87, 85); expect(sut.length, 7395); }, tags: const ["happy"]); - test("copies the content of another grid on .from Constructor call", () { - Grid original = Grid(2, 2); - original[0] = "Hey"; - original[1] = "you"; - original[2] = "me"; - original[3] = "together"; + group(".from", () { + test("copies the content of another grid on .from Constructor call", () { + Grid original = Grid(2, 2); + original[0] = "Hey"; + original[1] = "you"; + original[2] = "me"; + original[3] = "together"; - Grid sut = Grid.from(original); - expect(sut, containsAllInOrder(["Hey", "you", "me", "together"])); - }, tags: const ["happy"]); - test("copies the length of another grid on .from Constructor call", () { - Grid original = Grid(2, 2); - original[0] = "Hey"; - original[1] = "you"; - original[2] = "me"; - original[3] = "together"; + Grid sut = Grid.from(original); + expect(sut, containsAllInOrder(["Hey", "you", "me", "together"])); + }, tags: const ["happy"]); + test("copies the length of another grid on .from Constructor call", () { + Grid original = Grid(2, 2); + original[0] = "Hey"; + original[1] = "you"; + original[2] = "me"; + original[3] = "together"; - Grid sut = Grid.from(original); - expect(sut.length, 4); - }, tags: const ["happy"]); - test("sets the length for list passed in on .fromList Constructor call", - () { - Grid sut = Grid.fromList(l, 3); + Grid sut = Grid.from(original); + expect(sut.length, 4); + }, tags: const ["happy"]); + }); + group(".fromList", () { + test("sets the length for list passed in on .fromList Constructor call", + () { + Grid sut = Grid.fromList(l, 3); - expect(sut.length, 9); - }, tags: const ["happy"]); - test("sets the contents of list passed in on .fromList Constructor call", - () { - Grid sut = Grid.fromList(l, 3); + expect(sut.length, 9); + }, tags: const ["happy"]); + test("sets the contents of list passed in on .fromList Constructor call", + () { + Grid sut = Grid.fromList(l, 3); - expect(sut[3], "together"); - }, tags: const ["happy"]); - test( - "sets the correct height for list passed in on .fromList Constructor call", - () { - Grid sut = Grid.fromList(l, 3); + expect(sut[3], "together"); + }, tags: const ["happy"]); + test( + "sets the correct height for list passed in on .fromList Constructor call", + () { + Grid sut = Grid.fromList(l, 3); - expect(sut.width, 3); - }, tags: const ["happy"]); + expect(sut.width, 3); + }, tags: const ["happy"]); + }); }); group("toIndex", () { Grid sut; From 2dc1d7fecd1618777c2bcaa2e7072398ef1f1a49 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 30 Aug 2018 10:32:34 +0200 Subject: [PATCH 081/120] Add Grid.fill constructor Will completely fill the grid with the value passed in. --- lib/src/Grid.dart | 3 +++ test/src/grid_test.dart | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart index 40b87ea..e2a62fc 100644 --- a/lib/src/Grid.dart +++ b/lib/src/Grid.dart @@ -10,6 +10,9 @@ class Grid extends DelegatingList { Grid(int width, int height) : this._(List(width * height), width, height); + Grid.fill(int width, int height, E fillValue) + : this._(List.filled(width * height, fillValue), width, height); + Grid.from(Grid l) : this._(List.from(l.getRange(0, l.length)), l.width, l.height); diff --git a/test/src/grid_test.dart b/test/src/grid_test.dart index d6eae8f..fce1b3f 100644 --- a/test/src/grid_test.dart +++ b/test/src/grid_test.dart @@ -73,6 +73,24 @@ void main() { expect(sut.width, 3); }, tags: const ["happy"]); }); + group(".fill", () { + test("fills list with results of function passed in", () { + Grid sut = Grid.fill(3, 3, "testValue"); + expect( + sut, + containsAllInOrder([ + "testValue", + "testValue", + "testValue", + "testValue", + "testValue", + "testValue", + "testValue", + "testValue", + "testValue" + ])); + }, tags: const ["happy"]); + }); }); group("toIndex", () { Grid sut; From 227357a745e213d812bfeec63779dc5dabde5398 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 30 Aug 2018 10:57:14 +0200 Subject: [PATCH 082/120] Implement new Grid into Simulation --- lib/src/Simulation.dart | 131 ++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 84 deletions(-) diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index 3b2c559..8261071 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -2,14 +2,13 @@ import 'dart:html' as html; import 'dart:math' as math; import 'package:rules_of_living/src/Cell.dart'; +import 'package:rules_of_living/src/Grid.dart'; import 'package:rules_of_living/src/Rule.dart'; enum CellPattern { SpaceShip, Blinker } class Simulation { - final int w; - final int h; - final List> map; + final Grid map; bool _dirty = true; bool _renderEdges = true; @@ -21,17 +20,27 @@ class Simulation { int _dispersal; CellPattern _pattern; - Simulation(int w, int h) - : this.w = w, - this.h = h, - this.map = new List() { - map.addAll(_buildGrid(w, h)); - + Simulation(int w, int h) : this.map = new Grid.fill(w, h, _getGOLCell()) { print("Grid creation finished"); } + static Cell _getGOLCell([bool defaultState = false]) { + Cell cell = Cell(defaultState); + Rule threeTrue = new Rule((int n) { + if (n == 3) return true; + return false; + }); + Rule twoTrue = new Rule((int n) { + if (n == 2) return true; + return false; + }); + cell.surviveRules..add(twoTrue)..add(threeTrue); + cell.birthRules.add(twoTrue); + return cell; + } + void reset() { - map.setAll(0, _buildGrid(w, h)); + map.setAll(0, List.filled(map.length, _getGOLCell())); if (_startingSeed != null) addPattern( pattern: _pattern, @@ -57,8 +66,8 @@ class Simulation { _amount = amount ?? rng.nextInt(20); _dispersal = dispersal ?? 10; _pattern = pattern; - int cx = x ?? rng.nextInt(w ~/ 3) + (w ~/ 3); - int cy = y ?? rng.nextInt(h ~/ 3) + (h ~/ 3); + int cx = x ?? rng.nextInt(map.width ~/ 3) + (map.width ~/ 3); + int cy = y ?? rng.nextInt(map.height ~/ 3) + (map.height ~/ 3); switch (pattern) { // Two blocks, offset // ## @@ -101,70 +110,26 @@ class Simulation { } void setCellState(int x, int y, bool state) { - if (y < map.length && x < map[y].length) map[y][x].state = state; + if (y < map.height && x < map.width) map.get(x, y).state = state; } bool getCellState(int x, int y) { - if (y < map.length && x < map[y].length) return map[y][x].state; + if (y < map.height && x < map.width) return map.get(x, y).state; return null; } - List> _buildGrid(int w, int h) { - print("grid being created"); - List> grid = new List(h); - // GENERAL RULE LAYOUT - Rule threeTrue = new Rule((int n) { - if (n == 3) return true; - return false; - }); - Rule twoTrue = new Rule((int n) { - if (n == 2) return true; - return false; - }); - - // DEBUG RULE TESTING FOR PATTERNS - Rule coagSurvive = new Rule((int n) { - if (n == 1) return true; - return false; - }); - Rule coagBirth = new Rule((int n) { - if (n == 1) return true; - 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.surviveRules.add(twoTrue); - cell.birthRules.add(threeTrue); - - grid[y][x] = cell; - } - } - return grid; - } - bool update() { bool stateChanges = false; - 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(getSurroundingNeighbors(x, y, 1)); - } - } - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - Cell c = map[y][x]; - if (c.state != c.nextState) stateChanges = true; - c.advanceState(); - if (!_dirty && map[y][x].dirty) _dirty = true; - } + for (int i = 0; i < map.length; i++) { + math.Point p = map.toCoordinates(i); + map[i].update(getSurroundingNeighbors(p.x, p.y, 1)); } + // TODO when implementing changeSet we can remove this second loop and add to changeSet in the first + map.forEach((Cell el) { + if (el.state != el.nextState) stateChanges = true; + el.advanceState(); + }); return stateChanges; } @@ -174,9 +139,9 @@ class Simulation { for (int ix = x - range; ix <= x + range; ix++) { if (ix > 0 && iy > 0 && - iy < map.length && - ix < map[iy].length && - map[iy][ix].state == true && + iy < map.height && + ix < map.width && + map.get(x, y).state == true && !(x == ix && y == iy)) { count++; } @@ -190,24 +155,22 @@ class Simulation { if (!_dirty) return; html.CanvasRenderingContext2D ctx = canvas.getContext('2d'); - int brickW = (canvas.width ~/ map[0].length); - int brickH = (canvas.height ~/ map.length); + int brickW = (canvas.width ~/ map.width); + int brickH = (canvas.height ~/ map.height); 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++) { - if (_renderEdges) { - ctx.setStrokeColorRgb(100, 100, 100); - ctx.strokeRect(x * brickW, y * brickH, brickW, brickH); - } - - 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); + for (int i; i < map.length; i++) { + math.Point p = map.toCoordinates(i); + if (_renderEdges) { + ctx.setStrokeColorRgb(100, 100, 100); + ctx.strokeRect(p.x * brickW, p.y * brickH, brickW, brickH); } + + if (map[i].state == true) + ctx.setFillColorRgb(155, 155, 255); + else + ctx.setFillColorRgb(0, 0, 0); + ctx.fillRect(p.x * brickW, p.y * brickH, brickW, brickH); } _dirty = false; From b95d39d2b4b13caa7ebd29d48eb5b8ed5f70cd64 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 30 Aug 2018 10:58:55 +0200 Subject: [PATCH 083/120] Fix not carrying width and height in Simulation --- lib/src/Simulation.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index 8261071..7f221ba 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -20,6 +20,9 @@ class Simulation { int _dispersal; CellPattern _pattern; + int get w => map.width; + int get h => map.height; + Simulation(int w, int h) : this.map = new Grid.fill(w, h, _getGOLCell()) { print("Grid creation finished"); } From a324d52df5a489ae82d8b21772f2d51581fed7be Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Thu, 30 Aug 2018 12:03:23 +0200 Subject: [PATCH 084/120] Fix Simulation Neighbor Propagation --- lib/src/Simulation.dart | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index 7f221ba..ca7bb71 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -23,11 +23,14 @@ class Simulation { int get w => map.width; int get h => map.height; - Simulation(int w, int h) : this.map = new Grid.fill(w, h, _getGOLCell()) { + Simulation(int w, int h) : this.map = new Grid(w, h) { + for (int i = 0; i < map.length; i++) { + map[i] = _getGOLCell(); + } print("Grid creation finished"); } - static Cell _getGOLCell([bool defaultState = false]) { + Cell _getGOLCell([bool defaultState = false]) { Cell cell = Cell(defaultState); Rule threeTrue = new Rule((int n) { if (n == 3) return true; @@ -37,8 +40,9 @@ class Simulation { if (n == 2) return true; return false; }); - cell.surviveRules..add(twoTrue)..add(threeTrue); - cell.birthRules.add(twoTrue); + cell.surviveRules.add(twoTrue); + cell.surviveRules.add(threeTrue); + cell.birthRules.add(threeTrue); return cell; } @@ -133,21 +137,20 @@ class Simulation { if (el.state != el.nextState) stateChanges = true; el.advanceState(); }); + stateChanges ? _dirty = true : false; return stateChanges; } int getSurroundingNeighbors(int x, int y, int range) { int count = 0; - for (int iy = y - range; iy <= y + range; iy++) { - for (int ix = x - range; ix <= x + range; ix++) { - if (ix > 0 && - iy > 0 && - iy < map.height && + for (int ix = -range + x; ix <= range + x; ix++) { + for (int iy = -range + y; iy <= range + y; iy++) { + if (ix >= 0 && + iy >= 0 && ix < map.width && - map.get(x, y).state == true && - !(x == ix && y == iy)) { - count++; - } + iy < map.height && + map.get(ix, iy).state == true && + !(x == ix && y == iy)) count++; } } return count; @@ -161,8 +164,7 @@ class Simulation { int brickW = (canvas.width ~/ map.width); int brickH = (canvas.height ~/ map.height); ctx.clearRect(0, 0, canvas.width, canvas.height); - - for (int i; i < map.length; i++) { + for (int i = 0; i < map.length; i++) { math.Point p = map.toCoordinates(i); if (_renderEdges) { ctx.setStrokeColorRgb(100, 100, 100); @@ -175,7 +177,6 @@ class Simulation { ctx.setFillColorRgb(0, 0, 0); ctx.fillRect(p.x * brickW, p.y * brickH, brickW, brickH); } - _dirty = false; } From c50e92fb19705ebc4a3fe49df5150c6dd71fcbb3 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 2 Oct 2018 14:55:39 +0200 Subject: [PATCH 085/120] Add simple stateChanges map into Simulation --- lib/src/Engine.dart | 3 ++- lib/src/Simulation.dart | 16 +++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index 84d52e8..9855d14 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -101,7 +101,8 @@ class Engine { /// directly, since it is automatically taken care of by the processing function. /// If simulation should be advanced manually one time, prefer using step(). void update() { - if (!_grid.update()) running = false; + // TODO: create hasUpdated/hasAdvanced method in simulation to abstract actual updating away + if (_grid.update().length != 0) running = false; } /// Advances Logic One Update diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index ca7bb71..e451bf0 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -125,19 +125,17 @@ class Simulation { return null; } - bool update() { - bool stateChanges = false; + Map update() { + Map stateChanges = Map(); for (int i = 0; i < map.length; i++) { math.Point p = map.toCoordinates(i); - map[i].update(getSurroundingNeighbors(p.x, p.y, 1)); + Cell el = map[i]; + el.update(getSurroundingNeighbors(p.x, p.y, 1)); + stateChanges[i] = el; } - // TODO when implementing changeSet we can remove this second loop and add to changeSet in the first - map.forEach((Cell el) { - if (el.state != el.nextState) stateChanges = true; - el.advanceState(); - }); - stateChanges ? _dirty = true : false; + stateChanges.forEach((_, el) => el.advanceState()); + stateChanges.length != 0 ? _dirty = true : false; return stateChanges; } From 08155b70a5ab0a7df15dffb999f473f075a5f4e2 Mon Sep 17 00:00:00 2001 From: Unknown Date: Mon, 15 Oct 2018 17:16:09 +0200 Subject: [PATCH 086/120] Fix Pausing after every Update Updates would pause when any change has happened, not when no change has happened. --- lib/src/Engine.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index 9855d14..36ab89a 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -102,7 +102,7 @@ class Engine { /// If simulation should be advanced manually one time, prefer using step(). void update() { // TODO: create hasUpdated/hasAdvanced method in simulation to abstract actual updating away - if (_grid.update().length != 0) running = false; + if (_grid.update().length == 0) running = false; } /// Advances Logic One Update From 71f4df85af8a63f1bacb08b4c62ecaadaf9c3106 Mon Sep 17 00:00:00 2001 From: Unknown Date: Mon, 15 Oct 2018 17:28:09 +0200 Subject: [PATCH 087/120] Refactor Simulation to be List of dumb cells Cells are now only an empty struct, they carry no information beyond needing to be re-rendered. All Simulation logic is handled in the Simulation Class. --- lib/src/Cell.dart | 30 ------------------------------ lib/src/Simulation.dart | 38 +++++++++++++++++--------------------- 2 files changed, 17 insertions(+), 51 deletions(-) diff --git a/lib/src/Cell.dart b/lib/src/Cell.dart index b10142b..4e12f04 100644 --- a/lib/src/Cell.dart +++ b/lib/src/Cell.dart @@ -1,36 +1,6 @@ import 'package:rules_of_living/src/Rule.dart'; class Cell { - bool state; - bool nextState = false; - List surviveRules = new List(); - List birthRules = new List(); - /// For determining if render updates are necessary in [Grid].render() function bool dirty = false; - - Cell([bool state = false]) : this.state = state; - - // Sets the actual state to what it should be next update - // Returns the newly assumed actual state of the cell. - bool advanceState() { - this.state = this.nextState; - this.nextState = false; - - this.dirty = true; - - return this.state; - } - - void update(int neighbors) { - if (state == true) { - surviveRules.forEach((Rule rule) { - if (rule.evaluate(neighbors) == true) this.nextState = true; - }); - } else { - birthRules.forEach((Rule rule) { - if (rule.evaluate(neighbors) == true) this.nextState = true; - }); - } - } } diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index e451bf0..4f6a864 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -3,7 +3,6 @@ import 'dart:math' as math; import 'package:rules_of_living/src/Cell.dart'; import 'package:rules_of_living/src/Grid.dart'; -import 'package:rules_of_living/src/Rule.dart'; enum CellPattern { SpaceShip, Blinker } @@ -31,18 +30,7 @@ class Simulation { } Cell _getGOLCell([bool defaultState = false]) { - Cell cell = Cell(defaultState); - Rule threeTrue = new Rule((int n) { - if (n == 3) return true; - return false; - }); - Rule twoTrue = new Rule((int n) { - if (n == 2) return true; - return false; - }); - cell.surviveRules.add(twoTrue); - cell.surviveRules.add(threeTrue); - cell.birthRules.add(threeTrue); + Cell cell = Cell(); return cell; } @@ -117,12 +105,15 @@ class Simulation { } void setCellState(int x, int y, bool state) { - if (y < map.height && x < map.width) map.get(x, y).state = state; + if (y >= map.height || x >= map.width) return; + + state ? map.set(x, y, Cell()) : map.set(x, y, null); } bool getCellState(int x, int y) { - if (y < map.height && x < map.width) return map.get(x, y).state; - return null; + if (y >= map.height || x >= map.width) return null; + + return map.get(x, y) == null ? false : true; } Map update() { @@ -131,10 +122,15 @@ class Simulation { for (int i = 0; i < map.length; i++) { math.Point p = map.toCoordinates(i); Cell el = map[i]; - el.update(getSurroundingNeighbors(p.x, p.y, 1)); - stateChanges[i] = el; + bool changed = false; + int neighbors = getSurroundingNeighbors(p.x, p.y, 1); + if (el == null && neighbors == 3) { + stateChanges[i] = Cell(); + } else if (el != null && neighbors != 2 && neighbors != 3) { + stateChanges[i] = null; + } } - stateChanges.forEach((_, el) => el.advanceState()); + stateChanges.forEach((i, el) => map[i] = el); stateChanges.length != 0 ? _dirty = true : false; return stateChanges; } @@ -147,7 +143,7 @@ class Simulation { iy >= 0 && ix < map.width && iy < map.height && - map.get(ix, iy).state == true && + map.get(ix, iy) != null && !(x == ix && y == iy)) count++; } } @@ -169,7 +165,7 @@ class Simulation { ctx.strokeRect(p.x * brickW, p.y * brickH, brickW, brickH); } - if (map[i].state == true) + if (map[i] != null) ctx.setFillColorRgb(155, 155, 255); else ctx.setFillColorRgb(0, 0, 0); From 245d9a22c2b844c6d4169ff131cebbdc40913732 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 16 Oct 2018 18:21:01 +0200 Subject: [PATCH 088/120] Remove Cell Data Structure Cells are only boolean values of true or false for now. --- lib/src/Simulation.dart | 59 ++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index 4f6a864..02c3c3a 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -1,13 +1,12 @@ import 'dart:html' as html; import 'dart:math' as math; -import 'package:rules_of_living/src/Cell.dart'; import 'package:rules_of_living/src/Grid.dart'; enum CellPattern { SpaceShip, Blinker } class Simulation { - final Grid map; + final Grid map; bool _dirty = true; bool _renderEdges = true; @@ -23,19 +22,12 @@ class Simulation { int get h => map.height; Simulation(int w, int h) : this.map = new Grid(w, h) { - for (int i = 0; i < map.length; i++) { - map[i] = _getGOLCell(); - } - print("Grid creation finished"); - } - - Cell _getGOLCell([bool defaultState = false]) { - Cell cell = Cell(); - return cell; + reset(); + print("Grid Created"); } void reset() { - map.setAll(0, List.filled(map.length, _getGOLCell())); + map.setAll(0, List.filled(map.length, false)); if (_startingSeed != null) addPattern( pattern: _pattern, @@ -105,33 +97,46 @@ class Simulation { } void setCellState(int x, int y, bool state) { - if (y >= map.height || x >= map.width) return; + if (y >= map.height || x >= map.width) return null; - state ? map.set(x, y, Cell()) : map.set(x, y, null); + state ? map.set(x, y, true) : map.set(x, y, false); } bool getCellState(int x, int y) { if (y >= map.height || x >= map.width) return null; - return map.get(x, y) == null ? false : true; + return map.get(x, y); } - Map update() { - Map stateChanges = Map(); + void toggleCellState(int x, int y) { + if (y >= map.height || x >= map.width) return null; + + getCellState(x, y) == null + ? setCellState(x, y, true) + : setCellState(x, y, false); + } + + Map update() { + Map stateChanges = calculateNextState(map); + + stateChanges.forEach((i, el) => map[i] = el); + stateChanges.length != 0 ? _dirty = true : false; + return stateChanges; + } + + Map calculateNextState(Grid oldState) { + Map stateChanges = Map(); for (int i = 0; i < map.length; i++) { math.Point p = map.toCoordinates(i); - Cell el = map[i]; - bool changed = false; + bool cell = map[i]; int neighbors = getSurroundingNeighbors(p.x, p.y, 1); - if (el == null && neighbors == 3) { - stateChanges[i] = Cell(); - } else if (el != null && neighbors != 2 && neighbors != 3) { - stateChanges[i] = null; + if (cell == false && neighbors == 3) { + stateChanges[i] = true; + } else if (cell == true && neighbors != 2 && neighbors != 3) { + stateChanges[i] = false; } } - stateChanges.forEach((i, el) => map[i] = el); - stateChanges.length != 0 ? _dirty = true : false; return stateChanges; } @@ -143,7 +148,7 @@ class Simulation { iy >= 0 && ix < map.width && iy < map.height && - map.get(ix, iy) != null && + getCellState(ix, iy) == true && !(x == ix && y == iy)) count++; } } @@ -165,7 +170,7 @@ class Simulation { ctx.strokeRect(p.x * brickW, p.y * brickH, brickW, brickH); } - if (map[i] != null) + if (map[i] == true) ctx.setFillColorRgb(155, 155, 255); else ctx.setFillColorRgb(0, 0, 0); From 27d4879b1bca3f11cbeb16efae3b295b6a9df9ea Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 17 Oct 2018 20:56:30 +0200 Subject: [PATCH 089/120] Extract RuleSet Class from Simulation --- lib/src/RuleSet.dart | 27 ++++++++++++++++++++++++++ lib/src/Simulation.dart | 43 ++++++----------------------------------- 2 files changed, 33 insertions(+), 37 deletions(-) create mode 100644 lib/src/RuleSet.dart diff --git a/lib/src/RuleSet.dart b/lib/src/RuleSet.dart new file mode 100644 index 0000000..edfc5a9 --- /dev/null +++ b/lib/src/RuleSet.dart @@ -0,0 +1,27 @@ +import 'dart:math'; + +import 'package:collection/collection.dart'; + +abstract class RuleSet { + int checkRange; + + bool checkSurvival(int neighbors); + bool checkBirth(int neighbors); +} + +class Pattern extends DelegatingList { + final String _name; + Pattern(String name, List base) + : _name = name, + super(base); + + String get name => _name; +} + +class GameOfLife implements RuleSet { + int checkRange = 1; + + bool checkSurvival(int neighbors) => + neighbors == 2 || neighbors == 3 ? true : false; + bool checkBirth(int neighbors) => neighbors == 3 ? true : false; +} diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index 02c3c3a..05db54b 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -2,11 +2,13 @@ import 'dart:html' as html; import 'dart:math' as math; import 'package:rules_of_living/src/Grid.dart'; +import 'package:rules_of_living/src/RuleSet.dart'; enum CellPattern { SpaceShip, Blinker } class Simulation { final Grid map; + RuleSet rules = GameOfLife(); bool _dirty = true; bool _renderEdges = true; @@ -28,14 +30,6 @@ class Simulation { void reset() { map.setAll(0, List.filled(map.length, false)); - if (_startingSeed != null) - addPattern( - pattern: _pattern, - dispersal: _dispersal, - amount: _amount, - seed: _startingSeed, - x: _x, - y: _y); _dirty = true; } @@ -56,31 +50,6 @@ class Simulation { int cx = x ?? rng.nextInt(map.width ~/ 3) + (map.width ~/ 3); int cy = y ?? rng.nextInt(map.height ~/ 3) + (map.height ~/ 3); switch (pattern) { - // Two blocks, offset - // ## - // ## - case CellPattern.Blinker: - setCellState(cx, cy, true); - setCellState(cx + 1, cy, true); - setCellState(cx, cy + 1, true); - setCellState(cx + 1, cy + 1, true); - - setCellState(cx + 2, cy + 2, true); - setCellState(cx + 3, cy + 2, true); - setCellState(cx + 2, cy + 3, true); - setCellState(cx + 3, cy + 3, true); - break; - // A 'gliding' Spaceship - // # - // # - // ### - case CellPattern.SpaceShip: - setCellState(1 + cx, 0 + cy, true); - setCellState(2 + cx, 1 + cy, true); - setCellState(2 + cx, 2 + cy, true); - setCellState(1 + cx, 2 + cy, true); - setCellState(0 + cx, 2 + cy, true); - break; default: int sanityCheck = 0; for (var i = 0; i < (_amount); i++) { @@ -130,17 +99,17 @@ class Simulation { for (int i = 0; i < map.length; i++) { math.Point p = map.toCoordinates(i); bool cell = map[i]; - int neighbors = getSurroundingNeighbors(p.x, p.y, 1); - if (cell == false && neighbors == 3) { + int neighbors = getNeighbors(p.x, p.y, 1); + if (cell == false && rules.checkBirth(neighbors) == true) { stateChanges[i] = true; - } else if (cell == true && neighbors != 2 && neighbors != 3) { + } else if (cell == true && rules.checkSurvival(neighbors) == false) { stateChanges[i] = false; } } return stateChanges; } - int getSurroundingNeighbors(int x, int y, int range) { + int getNeighbors(int x, int y, int range) { int count = 0; for (int ix = -range + x; ix <= range + x; ix++) { for (int iy = -range + y; iy <= range + y; iy++) { From 9b2b5f3e55060bd500e1af6eb9faff7492d1272e Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 17 Oct 2018 21:00:14 +0200 Subject: [PATCH 090/120] Remove unnecessary Simulation variables --- lib/src/Simulation.dart | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index 05db54b..bfdfa2c 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -14,11 +14,8 @@ class Simulation { bool _renderEdges = true; int _startingSeed; - int _x; - int _y; int _amount; int _dispersal; - CellPattern _pattern; int get w => map.width; int get h => map.height; @@ -42,11 +39,8 @@ class Simulation { int seed}) { _startingSeed = seed ?? DateTime.now().millisecondsSinceEpoch; math.Random rng = new math.Random(_startingSeed); - _x = x; - _y = y; _amount = amount ?? rng.nextInt(20); _dispersal = dispersal ?? 10; - _pattern = pattern; int cx = x ?? rng.nextInt(map.width ~/ 3) + (map.width ~/ 3); int cy = y ?? rng.nextInt(map.height ~/ 3) + (map.height ~/ 3); switch (pattern) { From e6e82f78f24ab7c434e16f4ea66b5438352baced Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 17 Oct 2018 21:07:48 +0200 Subject: [PATCH 091/120] Remove unnecessary Switch Case in Simulation --- lib/src/Simulation.dart | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index bfdfa2c..8342d7c 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -43,19 +43,17 @@ class Simulation { _dispersal = dispersal ?? 10; int cx = x ?? rng.nextInt(map.width ~/ 3) + (map.width ~/ 3); int cy = y ?? rng.nextInt(map.height ~/ 3) + (map.height ~/ 3); - switch (pattern) { - default: - int sanityCheck = 0; - for (var i = 0; i < (_amount); i++) { - sanityCheck++; - getCellState(cx, cy) - ? i-- - : setCellState(cx + rng.nextInt(_dispersal), - cy + rng.nextInt(_dispersal), true); - if (sanityCheck > 100 && sanityCheck > i * 3) break; - } - break; + + int sanityCheck = 0; + for (var i = 0; i < (_amount); i++) { + sanityCheck++; + getCellState(cx, cy) + ? i-- + : setCellState( + cx + rng.nextInt(_dispersal), cy + rng.nextInt(_dispersal), true); + if (sanityCheck > 100 && sanityCheck > i * 3) break; } + _dirty = true; } From 6d7120650fdb2ab2757cb8052bc18cd481cdf3db Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 17 Oct 2018 21:08:55 +0200 Subject: [PATCH 092/120] Add Special Patterns to RuleSet --- lib/src/RuleSet.dart | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/src/RuleSet.dart b/lib/src/RuleSet.dart index edfc5a9..f115699 100644 --- a/lib/src/RuleSet.dart +++ b/lib/src/RuleSet.dart @@ -4,6 +4,7 @@ import 'package:collection/collection.dart'; abstract class RuleSet { int checkRange; + List patterns; bool checkSurvival(int neighbors); bool checkBirth(int neighbors); @@ -20,6 +21,32 @@ class Pattern extends DelegatingList { class GameOfLife implements RuleSet { int checkRange = 1; + List patterns = [ + // Two blocks, offset + // ## + // ## + Pattern("Blinker", [ + Point(0, 0), + Point(1, 0), + Point(0, 1), + Point(1, 1), + Point(2, 2), + Point(3, 2), + Point(2, 3), + Point(3, 3) + ]), + // A 'gliding' Spaceship + // # + // # + // ### + Pattern("SpaceShip", [ + Point(1, 0), + Point(2, 1), + Point(2, 2), + Point(1, 2), + Point(0, 2), + ]) + ]; bool checkSurvival(int neighbors) => neighbors == 2 || neighbors == 3 ? true : false; From bac65ef1163c6479675e6c2fbf5d1d0ce2e7d194 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 09:57:08 +0200 Subject: [PATCH 093/120] Remove unnecessary pattern parameters --- lib/src/Engine.dart | 16 ++-------------- lib/src/Simulation.dart | 15 ++++----------- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index 36ab89a..73ab7ea 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -124,20 +124,8 @@ class Engine { if (canvas != null) _grid.render(canvas, interp); } - void addPattern( - {CellPattern pattern, - int x, - int y, - int amount, - int dispersal, - int seed}) { - _grid.addPattern( - pattern: pattern, - x: x, - y: y, - amount: amount, - dispersal: dispersal, - seed: seed); + void addPattern({int amount, int dispersal}) { + _grid.addPattern(amount: amount, dispersal: dispersal); } void toggleEdgeRendering() { diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index 8342d7c..b0bbb46 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -13,7 +13,6 @@ class Simulation { bool _dirty = true; bool _renderEdges = true; - int _startingSeed; int _amount; int _dispersal; @@ -30,19 +29,13 @@ class Simulation { _dirty = true; } - void addPattern( - {CellPattern pattern, - int x, - int y, - int amount, - int dispersal, - int seed}) { - _startingSeed = seed ?? DateTime.now().millisecondsSinceEpoch; + void addPattern({int amount, int dispersal}) { + int _startingSeed = DateTime.now().millisecondsSinceEpoch; math.Random rng = new math.Random(_startingSeed); _amount = amount ?? rng.nextInt(20); _dispersal = dispersal ?? 10; - int cx = x ?? rng.nextInt(map.width ~/ 3) + (map.width ~/ 3); - int cy = y ?? rng.nextInt(map.height ~/ 3) + (map.height ~/ 3); + int cx = rng.nextInt(map.width ~/ 3) + (map.width ~/ 3); + int cy = rng.nextInt(map.height ~/ 3) + (map.height ~/ 3); int sanityCheck = 0; for (var i = 0; i < (_amount); i++) { From e16085153aa26670d0d8c7e3dab1791352341a12 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 09:59:26 +0200 Subject: [PATCH 094/120] Rename Simulation in Engine Object --- lib/src/Engine.dart | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index 73ab7ea..e00b50f 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -32,11 +32,11 @@ class Engine { /// Grid Size /// /// Number of cells on x coordinate and y coordinate. Can be set individually. - Point get gridSize => Point(_grid.w, _grid.h); + Point get gridSize => Point(_simulation.w, _simulation.h); void set gridSize(Point value) { if (value.x <= 0 || value.y <= 0) throw ArgumentError("grid size must not be smaller than 1"); - _grid = Simulation(value.x, value.y); + _simulation = Simulation(value.x, value.y); } num _updateLag = 0.0; @@ -48,14 +48,14 @@ class Engine { /// be used if no canvas was defined at engine creation and it should be /// rendered later. html.CanvasElement canvas; - Simulation _grid; + Simulation _simulation; bool running = false; Engine([x = 100, y = 100, this.canvas]) { - _grid = Simulation(x, y); + _simulation = Simulation(x, y); _elapsed.start(); - _grid.addPattern(amount: 15, dispersal: 5); + _simulation.addPattern(amount: 15, dispersal: 5); html.window.animationFrame.then(animFrame); } @@ -65,12 +65,12 @@ class Engine { } void reset() { - _grid.reset(); + _simulation.reset(); running = false; } void clear() { - _grid = new Simulation(gridSize.x, gridSize.y); + _simulation = new Simulation(gridSize.x, gridSize.y); running = false; } @@ -102,7 +102,7 @@ class Engine { /// If simulation should be advanced manually one time, prefer using step(). void update() { // TODO: create hasUpdated/hasAdvanced method in simulation to abstract actual updating away - if (_grid.update().length == 0) running = false; + if (_simulation.update().length == 0) running = false; } /// Advances Logic One Update @@ -112,7 +112,7 @@ class Engine { /// (though this should usually not pose a problem). void step() { running = false; - _grid.update(); + _simulation.update(); } /// Renders the Current Simulation State @@ -121,14 +121,16 @@ class Engine { /// the internal engine processing. Does not do anything if no canvas is /// defined. void render([num interp]) { - if (canvas != null) _grid.render(canvas, interp); + if (canvas == null) return; + + _simulation.render(canvas, interp); } void addPattern({int amount, int dispersal}) { - _grid.addPattern(amount: amount, dispersal: dispersal); + _simulation.addPattern(amount: amount, dispersal: dispersal); } void toggleEdgeRendering() { - _grid.renderEdges = !_grid.renderEdges; + _simulation.renderEdges = !_simulation.renderEdges; } } From de1aa46743709fe45057a8972cfe9ac1f829b22c Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 10:58:06 +0200 Subject: [PATCH 095/120] Separate Simulation calculating updates and merging Simulation updates were one step of calculation and merging the calculations into the map in one function. Separating the two allows checking for a new update without affecting the grid, allows passing the last Update around and allows custom changes to the grid by passing changes to the merge function that were not derived from the update function. --- lib/src/Engine.dart | 5 ++++- lib/src/Simulation.dart | 8 +++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index e00b50f..59bcc66 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -102,7 +102,10 @@ class Engine { /// If simulation should be advanced manually one time, prefer using step(). void update() { // TODO: create hasUpdated/hasAdvanced method in simulation to abstract actual updating away - if (_simulation.update().length == 0) running = false; + Map simulationUpdate = _simulation.update(); + _simulation.mergeStateChanges(simulationUpdate); + + if (simulationUpdate.length == 0) running = false; } /// Advances Logic One Update diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index b0bbb46..8cc04ef 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -72,12 +72,14 @@ class Simulation { Map update() { Map stateChanges = calculateNextState(map); - - stateChanges.forEach((i, el) => map[i] = el); - stateChanges.length != 0 ? _dirty = true : false; return stateChanges; } + void mergeStateChanges(Map stateChanges) { + stateChanges.forEach((i, el) => map[i] = el); + if (stateChanges.length != 0) _dirty = true; + } + Map calculateNextState(Grid oldState) { Map stateChanges = Map(); From c3244b085e152278c34739fcda864ca6de430e50 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 11:04:23 +0200 Subject: [PATCH 096/120] Fix single steps not updating simulation --- lib/src/Engine.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index 59bcc66..e5190cf 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -101,7 +101,6 @@ class Engine { /// directly, since it is automatically taken care of by the processing function. /// If simulation should be advanced manually one time, prefer using step(). void update() { - // TODO: create hasUpdated/hasAdvanced method in simulation to abstract actual updating away Map simulationUpdate = _simulation.update(); _simulation.mergeStateChanges(simulationUpdate); @@ -114,8 +113,8 @@ class Engine { /// simulation. Does not automatically re-render the new state /// (though this should usually not pose a problem). void step() { + update(); running = false; - _simulation.update(); } /// Renders the Current Simulation State From 4f63947ab9a999253119a8943651197863d821c9 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 11:19:04 +0200 Subject: [PATCH 097/120] Delete unused Cell and Rule Classes They were used under the old system of every gridspace being its own cell data structure with its own rules to observe. Replaced by the RuleSet class. Cell has vanished in favor of simple boolean values filling the grid. --- lib/src/Cell.dart | 6 ------ lib/src/Rule.dart | 5 ----- 2 files changed, 11 deletions(-) delete mode 100644 lib/src/Cell.dart delete mode 100644 lib/src/Rule.dart diff --git a/lib/src/Cell.dart b/lib/src/Cell.dart deleted file mode 100644 index 4e12f04..0000000 --- a/lib/src/Cell.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:rules_of_living/src/Rule.dart'; - -class Cell { - /// For determining if render updates are necessary in [Grid].render() function - bool dirty = false; -} diff --git a/lib/src/Rule.dart b/lib/src/Rule.dart deleted file mode 100644 index 723b4d0..0000000 --- a/lib/src/Rule.dart +++ /dev/null @@ -1,5 +0,0 @@ -class Rule { - final Function evaluate; - - Rule(this.evaluate); -} From fbdf114fed22f9fe1fe8585d4234a546f25abba1 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 11:21:09 +0200 Subject: [PATCH 098/120] Move RuleSet to its own directory --- lib/src/Simulation.dart | 2 +- lib/src/{ => rules}/RuleSet.dart | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename lib/src/{ => rules}/RuleSet.dart (100%) diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index 8cc04ef..2f167a3 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -2,7 +2,7 @@ import 'dart:html' as html; import 'dart:math' as math; import 'package:rules_of_living/src/Grid.dart'; -import 'package:rules_of_living/src/RuleSet.dart'; +import 'package:rules_of_living/src/rules/RuleSet.dart'; enum CellPattern { SpaceShip, Blinker } diff --git a/lib/src/RuleSet.dart b/lib/src/rules/RuleSet.dart similarity index 100% rename from lib/src/RuleSet.dart rename to lib/src/rules/RuleSet.dart From 0aa3df30b4e0f3cc261247c9c97a7a6275a89c64 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 11:27:44 +0200 Subject: [PATCH 099/120] Extract CellPattern and GameOfLife into own files --- lib/src/Simulation.dart | 1 + lib/src/rules/CellPattern.dart | 10 +++++++ lib/src/rules/GameOfLife.dart | 38 ++++++++++++++++++++++++++ lib/src/rules/RuleSet.dart | 49 ++-------------------------------- 4 files changed, 51 insertions(+), 47 deletions(-) create mode 100644 lib/src/rules/CellPattern.dart create mode 100644 lib/src/rules/GameOfLife.dart diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index 2f167a3..a3f99c5 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -2,6 +2,7 @@ import 'dart:html' as html; import 'dart:math' as math; import 'package:rules_of_living/src/Grid.dart'; +import 'package:rules_of_living/src/rules/GameOfLife.dart'; import 'package:rules_of_living/src/rules/RuleSet.dart'; enum CellPattern { SpaceShip, Blinker } diff --git a/lib/src/rules/CellPattern.dart b/lib/src/rules/CellPattern.dart new file mode 100644 index 0000000..9798948 --- /dev/null +++ b/lib/src/rules/CellPattern.dart @@ -0,0 +1,10 @@ +import 'package:collection/collection.dart'; + +class CellPattern extends DelegatingList { + final String _name; + CellPattern(String name, List base) + : _name = name, + super(base); + + String get name => _name; +} diff --git a/lib/src/rules/GameOfLife.dart b/lib/src/rules/GameOfLife.dart new file mode 100644 index 0000000..f812233 --- /dev/null +++ b/lib/src/rules/GameOfLife.dart @@ -0,0 +1,38 @@ +import 'dart:math'; + +import 'package:rules_of_living/src/rules/RuleSet.dart'; +import 'package:rules_of_living/src/rules/CellPattern.dart'; + +class GameOfLife implements RuleSet { + int checkRange = 1; + List patterns = [ + // Two blocks, offset + // ## + // ## + CellPattern("Blinker", [ + Point(0, 0), + Point(1, 0), + Point(0, 1), + Point(1, 1), + Point(2, 2), + Point(3, 2), + Point(2, 3), + Point(3, 3) + ]), + // A 'gliding' Spaceship + // # + // # + // ### + CellPattern("SpaceShip", [ + Point(1, 0), + Point(2, 1), + Point(2, 2), + Point(1, 2), + Point(0, 2), + ]) + ]; + + bool checkSurvival(int neighbors) => + neighbors == 2 || neighbors == 3 ? true : false; + bool checkBirth(int neighbors) => neighbors == 3 ? true : false; +} diff --git a/lib/src/rules/RuleSet.dart b/lib/src/rules/RuleSet.dart index f115699..ad2bb70 100644 --- a/lib/src/rules/RuleSet.dart +++ b/lib/src/rules/RuleSet.dart @@ -1,54 +1,9 @@ -import 'dart:math'; - -import 'package:collection/collection.dart'; +import 'package:rules_of_living/src/rules/CellPattern.dart'; abstract class RuleSet { int checkRange; - List patterns; + List patterns; bool checkSurvival(int neighbors); bool checkBirth(int neighbors); } - -class Pattern extends DelegatingList { - final String _name; - Pattern(String name, List base) - : _name = name, - super(base); - - String get name => _name; -} - -class GameOfLife implements RuleSet { - int checkRange = 1; - List patterns = [ - // Two blocks, offset - // ## - // ## - Pattern("Blinker", [ - Point(0, 0), - Point(1, 0), - Point(0, 1), - Point(1, 1), - Point(2, 2), - Point(3, 2), - Point(2, 3), - Point(3, 3) - ]), - // A 'gliding' Spaceship - // # - // # - // ### - Pattern("SpaceShip", [ - Point(1, 0), - Point(2, 1), - Point(2, 2), - Point(1, 2), - Point(0, 2), - ]) - ]; - - bool checkSurvival(int neighbors) => - neighbors == 2 || neighbors == 3 ? true : false; - bool checkBirth(int neighbors) => neighbors == 3 ? true : false; -} From e13962f3718ca307022e8ca195a35e2e121bfa57 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 11:29:55 +0200 Subject: [PATCH 100/120] Shorten RuleSet variable for their checked range Range is self-explanatory and not as confusing as checkRange. --- lib/src/rules/GameOfLife.dart | 2 +- lib/src/rules/RuleSet.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/rules/GameOfLife.dart b/lib/src/rules/GameOfLife.dart index f812233..edb2dde 100644 --- a/lib/src/rules/GameOfLife.dart +++ b/lib/src/rules/GameOfLife.dart @@ -4,7 +4,7 @@ import 'package:rules_of_living/src/rules/RuleSet.dart'; import 'package:rules_of_living/src/rules/CellPattern.dart'; class GameOfLife implements RuleSet { - int checkRange = 1; + int range = 1; List patterns = [ // Two blocks, offset // ## diff --git a/lib/src/rules/RuleSet.dart b/lib/src/rules/RuleSet.dart index ad2bb70..03aeb36 100644 --- a/lib/src/rules/RuleSet.dart +++ b/lib/src/rules/RuleSet.dart @@ -1,7 +1,7 @@ import 'package:rules_of_living/src/rules/CellPattern.dart'; abstract class RuleSet { - int checkRange; + int range; List patterns; bool checkSurvival(int neighbors); From f1399064a20c04feb89cc9a416bac3ee129c7d5e Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 11:30:14 +0200 Subject: [PATCH 101/120] Fix Simulation using RuleSet range for neighbor checks --- lib/src/Simulation.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index a3f99c5..90969ce 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -87,7 +87,7 @@ class Simulation { for (int i = 0; i < map.length; i++) { math.Point p = map.toCoordinates(i); bool cell = map[i]; - int neighbors = getNeighbors(p.x, p.y, 1); + int neighbors = getNeighbors(p.x, p.y, rules.range); if (cell == false && rules.checkBirth(neighbors) == true) { stateChanges[i] = true; } else if (cell == true && rules.checkSurvival(neighbors) == false) { From 4f92c69a82794b97365d5186eadb437a8a9bbaf7 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 11:32:00 +0200 Subject: [PATCH 102/120] Rename Simulation function adding random patterns Rename from addPattern to addRandomPattern to more clearly signify its purpose. --- lib/src/Engine.dart | 4 ++-- lib/src/Simulation.dart | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index e5190cf..3653353 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -55,7 +55,7 @@ class Engine { _simulation = Simulation(x, y); _elapsed.start(); - _simulation.addPattern(amount: 15, dispersal: 5); + _simulation.addRandomPattern(amount: 15, dispersal: 5); html.window.animationFrame.then(animFrame); } @@ -129,7 +129,7 @@ class Engine { } void addPattern({int amount, int dispersal}) { - _simulation.addPattern(amount: amount, dispersal: dispersal); + _simulation.addRandomPattern(amount: amount, dispersal: dispersal); } void toggleEdgeRendering() { diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index 90969ce..42df2a4 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -30,7 +30,7 @@ class Simulation { _dirty = true; } - void addPattern({int amount, int dispersal}) { + void addRandomPattern({int amount, int dispersal}) { int _startingSeed = DateTime.now().millisecondsSinceEpoch; math.Random rng = new math.Random(_startingSeed); _amount = amount ?? rng.nextInt(20); From 17697070ee4df34a9d7ed3f90cedd4ae06e9f418 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 11:58:38 +0200 Subject: [PATCH 103/120] Move ControlService tasks into EngineService All ControlService was used for was a redirection to the engine service. This will be further split up in the future into more logical units of responsibility. --- lib/app_component.dart | 2 -- lib/components/controls_component.dart | 4 +-- lib/service/control_service.dart | 38 -------------------------- lib/service/engine_service.dart | 31 +++++++++++++++++++++ 4 files changed, 33 insertions(+), 42 deletions(-) delete mode 100644 lib/service/control_service.dart diff --git a/lib/app_component.dart b/lib/app_component.dart index ae8a931..2d4557f 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -5,7 +5,6 @@ import 'package:rules_of_living/components/controls_component.dart'; import 'package:rules_of_living/components/header_component.dart'; import 'package:rules_of_living/components/simulation_component.dart'; import 'package:rules_of_living/service/configuration_service.dart'; -import 'package:rules_of_living/service/control_service.dart'; import 'package:rules_of_living/service/engine_service.dart'; @Component( @@ -25,7 +24,6 @@ import 'package:rules_of_living/service/engine_service.dart'; materialProviders, ClassProvider(EngineService), ClassProvider(ConfigurationService), - ClassProvider(ControlService) ], styleUrls: const [ 'package:angular_components/app_layout/layout.scss.css', diff --git a/lib/components/controls_component.dart b/lib/components/controls_component.dart index 954d94b..f4b5264 100644 --- a/lib/components/controls_component.dart +++ b/lib/components/controls_component.dart @@ -1,6 +1,6 @@ import 'package:angular/angular.dart'; import 'package:angular_components/angular_components.dart'; -import 'package:rules_of_living/service/control_service.dart'; +import 'package:rules_of_living/service/engine_service.dart'; @Component( selector: 'sim-controls', @@ -15,7 +15,7 @@ import 'package:rules_of_living/service/control_service.dart'; styleUrls: const ["controls_component.css"], ) class ControlsComponent { - final ControlService ctrl; + final EngineService ctrl; ControlsComponent(this.ctrl); diff --git a/lib/service/control_service.dart b/lib/service/control_service.dart deleted file mode 100644 index 0066106..0000000 --- a/lib/service/control_service.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:rules_of_living/service/engine_service.dart'; - -class ControlService { - EngineService _es; - - ControlService(this._es); - - void run() { - _es.engine.running = true; - } - - void stop() { - _es.engine.running = false; - } - - void toggleRunning() { - _es.engine.running = !_es.engine.running; - } - - void step() { - _es.engine.step(); - } - - void reset() { - _es.engine.reset(); - } - - void addRandomPattern() { - _es.engine.running = false; - _es.engine.addPattern(); - } - - void clear() { - _es.engine.clear(); - } - - bool get isRunning => _es.engine.running; -} diff --git a/lib/service/engine_service.dart b/lib/service/engine_service.dart index 8168735..df1492c 100644 --- a/lib/service/engine_service.dart +++ b/lib/service/engine_service.dart @@ -12,4 +12,35 @@ class EngineService { engine = newEngine; return newEngine; } + + void run() { + engine.running = true; + } + + void stop() { + engine.running = false; + } + + void toggleRunning() { + engine.running = !engine.running; + } + + void step() { + engine.step(); + } + + void reset() { + engine.reset(); + } + + void addRandomPattern() { + engine.running = false; + engine.addPattern(); + } + + void clear() { + engine.clear(); + } + + bool get isRunning => engine.running; } From 72ce25a8066f2d1a5f970d584644796dee77420d Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 11:59:36 +0200 Subject: [PATCH 104/120] Rename Controls component variable accessing engine --- lib/components/controls_component.dart | 14 +++++++------- lib/components/controls_component.html | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/components/controls_component.dart b/lib/components/controls_component.dart index f4b5264..511a7d4 100644 --- a/lib/components/controls_component.dart +++ b/lib/components/controls_component.dart @@ -15,27 +15,27 @@ import 'package:rules_of_living/service/engine_service.dart'; styleUrls: const ["controls_component.css"], ) class ControlsComponent { - final EngineService ctrl; + final EngineService engine; - ControlsComponent(this.ctrl); + ControlsComponent(this.engine); void onStartClicked() { - ctrl.toggleRunning(); + engine.toggleRunning(); } void onStepClicked() { - ctrl.step(); + engine.step(); } void onResetClicked() { - ctrl.reset(); + engine.reset(); } void onRandomClicked() { - ctrl.addRandomPattern(); + engine.addRandomPattern(); } void onClearClicked() { - ctrl.clear(); + engine.clear(); } } diff --git a/lib/components/controls_component.html b/lib/components/controls_component.html index b4c43f3..42e79f7 100644 --- a/lib/components/controls_component.html +++ b/lib/components/controls_component.html @@ -1,7 +1,7 @@
- + From 6b4786fdd08e250da3cd8ac60dfab47d4d7b73db Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 12:05:02 +0200 Subject: [PATCH 105/120] Add SimulationService to controls Will eventually attach to the Simulation directly without first going through Engine. For now just redirects calls to EngineService to keep functions intact. --- lib/app_component.dart | 2 ++ lib/components/controls_component.dart | 10 ++++++---- lib/service/simulation_service.dart | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 lib/service/simulation_service.dart diff --git a/lib/app_component.dart b/lib/app_component.dart index 2d4557f..eaa2e41 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -6,6 +6,7 @@ import 'package:rules_of_living/components/header_component.dart'; import 'package:rules_of_living/components/simulation_component.dart'; import 'package:rules_of_living/service/configuration_service.dart'; import 'package:rules_of_living/service/engine_service.dart'; +import 'package:rules_of_living/service/simulation_service.dart'; @Component( selector: 'my-app', @@ -24,6 +25,7 @@ import 'package:rules_of_living/service/engine_service.dart'; materialProviders, ClassProvider(EngineService), ClassProvider(ConfigurationService), + ClassProvider(SimulationService) ], styleUrls: const [ 'package:angular_components/app_layout/layout.scss.css', diff --git a/lib/components/controls_component.dart b/lib/components/controls_component.dart index 511a7d4..e524e60 100644 --- a/lib/components/controls_component.dart +++ b/lib/components/controls_component.dart @@ -1,6 +1,7 @@ import 'package:angular/angular.dart'; import 'package:angular_components/angular_components.dart'; import 'package:rules_of_living/service/engine_service.dart'; +import 'package:rules_of_living/service/simulation_service.dart'; @Component( selector: 'sim-controls', @@ -16,8 +17,9 @@ import 'package:rules_of_living/service/engine_service.dart'; ) class ControlsComponent { final EngineService engine; + final SimulationService sim; - ControlsComponent(this.engine); + ControlsComponent(this.engine, this.sim); void onStartClicked() { engine.toggleRunning(); @@ -28,14 +30,14 @@ class ControlsComponent { } void onResetClicked() { - engine.reset(); + sim.reset(); } void onRandomClicked() { - engine.addRandomPattern(); + sim.addRandomPattern(); } void onClearClicked() { - engine.clear(); + sim.clear(); } } diff --git a/lib/service/simulation_service.dart b/lib/service/simulation_service.dart new file mode 100644 index 0000000..1081bf0 --- /dev/null +++ b/lib/service/simulation_service.dart @@ -0,0 +1,19 @@ +import 'package:rules_of_living/service/engine_service.dart'; + +class SimulationService { + final EngineService engine; + + SimulationService(this.engine); + + void reset() { + engine.reset(); + } + + void addRandomPattern() { + engine.addRandomPattern(); + } + + void clear() { + engine.clear(); + } +} From 7729da3a40be6d65e951190a5a7061828dd34766 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 12:16:47 +0200 Subject: [PATCH 106/120] Split ConfigurationService to use SimulationService Methods concerning engine make use of EngineService, those concerning grid and patterns make use of SimulationService. --- lib/service/configuration_service.dart | 19 ++++++++++--------- lib/service/simulation_service.dart | 18 +++++++++++++----- test/service/configuration_service_test.dart | 4 +++- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/lib/service/configuration_service.dart b/lib/service/configuration_service.dart index e11a5e8..045e66c 100644 --- a/lib/service/configuration_service.dart +++ b/lib/service/configuration_service.dart @@ -2,15 +2,17 @@ import 'dart:html' as html; import 'dart:math'; import 'package:rules_of_living/service/engine_service.dart'; +import 'package:rules_of_living/service/simulation_service.dart'; class ConfigurationService { - final EngineService _es; + final EngineService _engine; + final SimulationService _sim; bool showGrid; int _simSpeed; - ConfigurationService(this._es) { + ConfigurationService(this._engine, this._sim) { showGrid = false; simSpeed = 5; } @@ -23,21 +25,20 @@ class ConfigurationService { int get simSpeed => _simSpeed; void set simSpeed(int val) { _simSpeed = val; - _es.engine.stepsPerSecond = simSpeed; + //TODO make method in EngineService to respect Demeter + _engine.engine.stepsPerSecond = simSpeed; } - void set canvas(html.CanvasElement canvas) => _es.engine.canvas = canvas; - html.CanvasElement get canvas => _es.engine.canvas; + void set canvas(html.CanvasElement canvas) => _engine.engine.canvas = canvas; + html.CanvasElement get canvas => _engine.engine.canvas; void toggleGrid() { showGrid = !showGrid; } void setGridSize({int x, int y}) { - x = x ?? _es.engine.gridSize.x; - y = y ?? _es.engine.gridSize.y; - _es.engine.gridSize = Point(x, y); + _sim.gridSize = Point(x ?? gridSize.x, y ?? gridSize.y); } - Point get gridSize => _es.engine.gridSize; + Point get gridSize => _sim.gridSize; } diff --git a/lib/service/simulation_service.dart b/lib/service/simulation_service.dart index 1081bf0..45a7b09 100644 --- a/lib/service/simulation_service.dart +++ b/lib/service/simulation_service.dart @@ -1,19 +1,27 @@ +import 'dart:math'; + import 'package:rules_of_living/service/engine_service.dart'; class SimulationService { - final EngineService engine; + final EngineService _engine; - SimulationService(this.engine); + SimulationService(this._engine); void reset() { - engine.reset(); + _engine.reset(); } void addRandomPattern() { - engine.addRandomPattern(); + _engine.addRandomPattern(); } void clear() { - engine.clear(); + _engine.clear(); } + + void set gridSize(Point size) { + _engine.engine.gridSize = size; + } + + Point get gridSize => _engine.engine.gridSize; } diff --git a/test/service/configuration_service_test.dart b/test/service/configuration_service_test.dart index 44e23b2..9aa4893 100644 --- a/test/service/configuration_service_test.dart +++ b/test/service/configuration_service_test.dart @@ -3,6 +3,7 @@ import 'dart:math'; import 'package:mockito/mockito.dart'; import 'package:rules_of_living/service/configuration_service.dart'; import 'package:rules_of_living/service/engine_service.dart'; +import 'package:rules_of_living/service/simulation_service.dart'; import 'package:rules_of_living/src/Engine.dart'; @TestOn('browser') import 'package:test/test.dart'; @@ -12,12 +13,13 @@ class MockEngine extends Mock implements Engine {} void main() { ConfigurationService sut; EngineService engineService; + SimulationService simService; MockEngine me; setUp(() { me = MockEngine(); engineService = EngineService(); engineService.engine = me; - sut = ConfigurationService(engineService); + sut = ConfigurationService(engineService, simService); }); group("simulation speed", () { From 99ead8691bc22b1dfe3676e61ded0757409f70be Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 12:29:46 +0200 Subject: [PATCH 107/120] Make gridSize in Services pass correct signature Both need to conform to Point to be accepted by the engine. --- lib/service/configuration_service.dart | 2 +- lib/service/simulation_service.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/service/configuration_service.dart b/lib/service/configuration_service.dart index 045e66c..ffd0b78 100644 --- a/lib/service/configuration_service.dart +++ b/lib/service/configuration_service.dart @@ -37,7 +37,7 @@ class ConfigurationService { } void setGridSize({int x, int y}) { - _sim.gridSize = Point(x ?? gridSize.x, y ?? gridSize.y); + _sim.gridSize = Point(x ?? gridSize.x, y ?? gridSize.y); } Point get gridSize => _sim.gridSize; diff --git a/lib/service/simulation_service.dart b/lib/service/simulation_service.dart index 45a7b09..0c967ef 100644 --- a/lib/service/simulation_service.dart +++ b/lib/service/simulation_service.dart @@ -19,7 +19,7 @@ class SimulationService { _engine.clear(); } - void set gridSize(Point size) { + void set gridSize(Point size) { _engine.engine.gridSize = size; } From 58971016dab2f92d0584548918b8262bf36bb2ad Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 12:51:35 +0200 Subject: [PATCH 108/120] Remove ConfigurationService Replaced with direct access to both EngineService and SimulationService. --- lib/app_component.dart | 2 - lib/components/configuration_component.dart | 24 ++++++---- lib/components/controls_component.dart | 1 + lib/components/simulation_component.dart | 8 ++-- lib/service/configuration_service.dart | 44 ------------------ lib/service/engine_service.dart | 22 +++++++++ test/service/configuration_service_test.dart | 48 -------------------- 7 files changed, 41 insertions(+), 108 deletions(-) delete mode 100644 lib/service/configuration_service.dart delete mode 100644 test/service/configuration_service_test.dart diff --git a/lib/app_component.dart b/lib/app_component.dart index eaa2e41..1656739 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -4,7 +4,6 @@ import 'package:rules_of_living/components/configuration_component.dart'; import 'package:rules_of_living/components/controls_component.dart'; import 'package:rules_of_living/components/header_component.dart'; import 'package:rules_of_living/components/simulation_component.dart'; -import 'package:rules_of_living/service/configuration_service.dart'; import 'package:rules_of_living/service/engine_service.dart'; import 'package:rules_of_living/service/simulation_service.dart'; @@ -24,7 +23,6 @@ import 'package:rules_of_living/service/simulation_service.dart'; providers: [ materialProviders, ClassProvider(EngineService), - ClassProvider(ConfigurationService), ClassProvider(SimulationService) ], styleUrls: const [ diff --git a/lib/components/configuration_component.dart b/lib/components/configuration_component.dart index cc1ecd1..c72106c 100644 --- a/lib/components/configuration_component.dart +++ b/lib/components/configuration_component.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:angular/angular.dart'; import 'package:angular_components/material_button/material_button.dart'; import 'package:angular_components/material_icon/material_icon.dart'; @@ -5,7 +7,8 @@ import 'package:angular_components/material_input/material_input.dart'; import 'package:angular_components/material_input/material_number_accessor.dart'; import 'package:angular_components/material_slider/material_slider.dart'; import 'package:angular_components/material_tooltip/material_tooltip.dart'; -import 'package:rules_of_living/service/configuration_service.dart'; +import 'package:rules_of_living/service/engine_service.dart'; +import 'package:rules_of_living/service/simulation_service.dart'; @Component( selector: "configuration", @@ -23,28 +26,29 @@ import 'package:rules_of_living/service/configuration_service.dart'; NgModel ]) class ConfigurationComponent { - final ConfigurationService config; + final EngineService engine; + final SimulationService sim; - int get width => config.gridSize.x; + int get width => sim.gridSize.x; void set width(num value) { if (value == null || value <= 0) return; - config.setGridSize(x: value.toInt()); + sim.gridSize = Point(value, sim.gridSize.y); } - int get height => config.gridSize.y; + int get height => sim.gridSize.y; void set height(num value) { if (value == null || value <= 0) return; - config.setGridSize(y: value.toInt()); + sim.gridSize = Point(sim.gridSize.x, value); } - int get simSpeed => config.simSpeed; - void set simSpeed(int value) => config.simSpeed = value; + int get simSpeed => engine.simSpeed; + void set simSpeed(int value) => engine.simSpeed = value; String get speedSliderTooltip => "Simulation Speed: $simSpeed"; - ConfigurationComponent(this.config); + ConfigurationComponent(this.engine, this.sim); void onEdgesClicked() { - config.toggleGrid(); + engine.toggleGrid(); } } diff --git a/lib/components/controls_component.dart b/lib/components/controls_component.dart index e524e60..3f31741 100644 --- a/lib/components/controls_component.dart +++ b/lib/components/controls_component.dart @@ -35,6 +35,7 @@ class ControlsComponent { void onRandomClicked() { sim.addRandomPattern(); + engine.stop(); } void onClearClicked() { diff --git a/lib/components/simulation_component.dart b/lib/components/simulation_component.dart index 312eef4..91812fb 100644 --- a/lib/components/simulation_component.dart +++ b/lib/components/simulation_component.dart @@ -1,7 +1,7 @@ import 'dart:html' as html; import 'package:angular/angular.dart'; -import 'package:rules_of_living/service/configuration_service.dart'; +import 'package:rules_of_living/service/engine_service.dart'; @Component( selector: 'gol-simulation', @@ -10,9 +10,9 @@ import 'package:rules_of_living/service/configuration_service.dart'; providers: [], ) class SimulationComponent implements OnInit { - final ConfigurationService config; + final EngineService engine; - SimulationComponent(this.config); + SimulationComponent(this.engine); @override void ngOnInit() { @@ -29,6 +29,6 @@ class SimulationComponent implements OnInit { the canvas did not load correctly :( ''', canvas.width / 2 - 50, canvas.height / 2); - config.canvas = canvas; + engine.canvas = canvas; } } diff --git a/lib/service/configuration_service.dart b/lib/service/configuration_service.dart deleted file mode 100644 index ffd0b78..0000000 --- a/lib/service/configuration_service.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'dart:html' as html; -import 'dart:math'; - -import 'package:rules_of_living/service/engine_service.dart'; -import 'package:rules_of_living/service/simulation_service.dart'; - -class ConfigurationService { - final EngineService _engine; - final SimulationService _sim; - - bool showGrid; - - int _simSpeed; - - ConfigurationService(this._engine, this._sim) { - showGrid = false; - simSpeed = 5; - } - - /// Simulation Speed - /// - /// Sets the number of updates the simulation takes per second. Can range from - /// 1 to arbitrarily high numbers (though setting it too high can potentially - /// make the app brittle). - int get simSpeed => _simSpeed; - void set simSpeed(int val) { - _simSpeed = val; - //TODO make method in EngineService to respect Demeter - _engine.engine.stepsPerSecond = simSpeed; - } - - void set canvas(html.CanvasElement canvas) => _engine.engine.canvas = canvas; - html.CanvasElement get canvas => _engine.engine.canvas; - - void toggleGrid() { - showGrid = !showGrid; - } - - void setGridSize({int x, int y}) { - _sim.gridSize = Point(x ?? gridSize.x, y ?? gridSize.y); - } - - Point get gridSize => _sim.gridSize; -} diff --git a/lib/service/engine_service.dart b/lib/service/engine_service.dart index df1492c..6d40681 100644 --- a/lib/service/engine_service.dart +++ b/lib/service/engine_service.dart @@ -1,8 +1,14 @@ +import 'dart:html' as html; + import 'package:rules_of_living/src/Engine.dart'; class EngineService { Engine _uncachedEngineAccess; + EngineService() { + simSpeed = 5; + } + Engine get engine => _uncachedEngineAccess ?? _setCachedAndReturn(Engine()); void set engine(Engine newEngine) { _uncachedEngineAccess = newEngine; @@ -29,6 +35,22 @@ class EngineService { engine.step(); } + /// Simulation Speed + /// + /// Sets the number of updates the simulation takes per second. Can range from + /// 1 to arbitrarily high numbers (though setting it too high can potentially + /// make the app brittle). + int get simSpeed => engine.stepsPerSecond; + void set simSpeed(int val) => engine.stepsPerSecond = val; + + //TODO split into RenderService when rendering is decoupled from engine. + html.CanvasElement get canvas => engine.canvas; + void set canvas(html.CanvasElement canvas) => engine.canvas = canvas; + + void toggleGrid() { + engine.toggleEdgeRendering(); + } + void reset() { engine.reset(); } diff --git a/test/service/configuration_service_test.dart b/test/service/configuration_service_test.dart deleted file mode 100644 index 9aa4893..0000000 --- a/test/service/configuration_service_test.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'dart:math'; - -import 'package:mockito/mockito.dart'; -import 'package:rules_of_living/service/configuration_service.dart'; -import 'package:rules_of_living/service/engine_service.dart'; -import 'package:rules_of_living/service/simulation_service.dart'; -import 'package:rules_of_living/src/Engine.dart'; -@TestOn('browser') -import 'package:test/test.dart'; - -class MockEngine extends Mock implements Engine {} - -void main() { - ConfigurationService sut; - EngineService engineService; - SimulationService simService; - MockEngine me; - setUp(() { - me = MockEngine(); - engineService = EngineService(); - engineService.engine = me; - sut = ConfigurationService(engineService, simService); - }); - - group("simulation speed", () { - test("speed changes propagate to engine", () { - sut.simSpeed = 312; - verify(me.stepsPerSecond = 312); - }); - }); - - group("grid size", () { - test("grid changes are sent to engine", () { - sut.setGridSize(x: 512, y: 388); - verify(me.gridSize = Point(512, 388)); - }); - test("grid can be changed solely on x axis", () { - when(me.gridSize).thenReturn(Point(100, 100)); - sut.setGridSize(x: 555); - verify(me.gridSize = Point(555, 100)); - }); - test("grid can be changed solely on y axis", () { - when(me.gridSize).thenReturn(Point(100, 100)); - sut.setGridSize(y: 556); - verify(me.gridSize = Point(100, 556)); - }); - }); -} From 45e8f01acb2205896cd53387a5e5586e2cd34a72 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 14:41:57 +0200 Subject: [PATCH 109/120] Move Render Methods into SimulationService --- lib/components/configuration_component.dart | 2 +- lib/components/simulation_component.dart | 4 +++- lib/service/engine_service.dart | 10 ---------- lib/service/simulation_service.dart | 9 +++++++++ 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/components/configuration_component.dart b/lib/components/configuration_component.dart index c72106c..abbd2e5 100644 --- a/lib/components/configuration_component.dart +++ b/lib/components/configuration_component.dart @@ -49,6 +49,6 @@ class ConfigurationComponent { ConfigurationComponent(this.engine, this.sim); void onEdgesClicked() { - engine.toggleGrid(); + sim.toggleGrid(); } } diff --git a/lib/components/simulation_component.dart b/lib/components/simulation_component.dart index 91812fb..1135865 100644 --- a/lib/components/simulation_component.dart +++ b/lib/components/simulation_component.dart @@ -2,6 +2,7 @@ import 'dart:html' as html; import 'package:angular/angular.dart'; import 'package:rules_of_living/service/engine_service.dart'; +import 'package:rules_of_living/service/simulation_service.dart'; @Component( selector: 'gol-simulation', @@ -11,6 +12,7 @@ import 'package:rules_of_living/service/engine_service.dart'; ) class SimulationComponent implements OnInit { final EngineService engine; + final SimulationService sim; SimulationComponent(this.engine); @@ -29,6 +31,6 @@ class SimulationComponent implements OnInit { the canvas did not load correctly :( ''', canvas.width / 2 - 50, canvas.height / 2); - engine.canvas = canvas; + sim.canvas = canvas; } } diff --git a/lib/service/engine_service.dart b/lib/service/engine_service.dart index 6d40681..a76fedb 100644 --- a/lib/service/engine_service.dart +++ b/lib/service/engine_service.dart @@ -1,5 +1,3 @@ -import 'dart:html' as html; - import 'package:rules_of_living/src/Engine.dart'; class EngineService { @@ -43,14 +41,6 @@ class EngineService { int get simSpeed => engine.stepsPerSecond; void set simSpeed(int val) => engine.stepsPerSecond = val; - //TODO split into RenderService when rendering is decoupled from engine. - html.CanvasElement get canvas => engine.canvas; - void set canvas(html.CanvasElement canvas) => engine.canvas = canvas; - - void toggleGrid() { - engine.toggleEdgeRendering(); - } - void reset() { engine.reset(); } diff --git a/lib/service/simulation_service.dart b/lib/service/simulation_service.dart index 0c967ef..b5a9021 100644 --- a/lib/service/simulation_service.dart +++ b/lib/service/simulation_service.dart @@ -1,3 +1,4 @@ +import 'dart:html' as html; import 'dart:math'; import 'package:rules_of_living/service/engine_service.dart'; @@ -24,4 +25,12 @@ class SimulationService { } Point get gridSize => _engine.engine.gridSize; + + //TODO split into RenderService when rendering is decoupled from engine. + html.CanvasElement get canvas => _engine.engine.canvas; + void set canvas(html.CanvasElement canvas) => _engine.engine.canvas = canvas; + + void toggleGrid() { + _engine.engine.toggleEdgeRendering(); + } } From bbfb2f735b26b3112f0773072b14bc5fb72e1138 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 14:41:57 +0200 Subject: [PATCH 110/120] Move Render Methods into SimulationService --- lib/components/configuration_component.dart | 2 +- lib/components/simulation_component.dart | 6 ++++-- lib/service/engine_service.dart | 10 ---------- lib/service/simulation_service.dart | 9 +++++++++ 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/lib/components/configuration_component.dart b/lib/components/configuration_component.dart index c72106c..abbd2e5 100644 --- a/lib/components/configuration_component.dart +++ b/lib/components/configuration_component.dart @@ -49,6 +49,6 @@ class ConfigurationComponent { ConfigurationComponent(this.engine, this.sim); void onEdgesClicked() { - engine.toggleGrid(); + sim.toggleGrid(); } } diff --git a/lib/components/simulation_component.dart b/lib/components/simulation_component.dart index 91812fb..1fcef71 100644 --- a/lib/components/simulation_component.dart +++ b/lib/components/simulation_component.dart @@ -2,6 +2,7 @@ import 'dart:html' as html; import 'package:angular/angular.dart'; import 'package:rules_of_living/service/engine_service.dart'; +import 'package:rules_of_living/service/simulation_service.dart'; @Component( selector: 'gol-simulation', @@ -11,8 +12,9 @@ import 'package:rules_of_living/service/engine_service.dart'; ) class SimulationComponent implements OnInit { final EngineService engine; + final SimulationService sim; - SimulationComponent(this.engine); + SimulationComponent(this.engine, this.sim); @override void ngOnInit() { @@ -29,6 +31,6 @@ class SimulationComponent implements OnInit { the canvas did not load correctly :( ''', canvas.width / 2 - 50, canvas.height / 2); - engine.canvas = canvas; + sim.canvas = canvas; } } diff --git a/lib/service/engine_service.dart b/lib/service/engine_service.dart index 6d40681..a76fedb 100644 --- a/lib/service/engine_service.dart +++ b/lib/service/engine_service.dart @@ -1,5 +1,3 @@ -import 'dart:html' as html; - import 'package:rules_of_living/src/Engine.dart'; class EngineService { @@ -43,14 +41,6 @@ class EngineService { int get simSpeed => engine.stepsPerSecond; void set simSpeed(int val) => engine.stepsPerSecond = val; - //TODO split into RenderService when rendering is decoupled from engine. - html.CanvasElement get canvas => engine.canvas; - void set canvas(html.CanvasElement canvas) => engine.canvas = canvas; - - void toggleGrid() { - engine.toggleEdgeRendering(); - } - void reset() { engine.reset(); } diff --git a/lib/service/simulation_service.dart b/lib/service/simulation_service.dart index 0c967ef..b5a9021 100644 --- a/lib/service/simulation_service.dart +++ b/lib/service/simulation_service.dart @@ -1,3 +1,4 @@ +import 'dart:html' as html; import 'dart:math'; import 'package:rules_of_living/service/engine_service.dart'; @@ -24,4 +25,12 @@ class SimulationService { } Point get gridSize => _engine.engine.gridSize; + + //TODO split into RenderService when rendering is decoupled from engine. + html.CanvasElement get canvas => _engine.engine.canvas; + void set canvas(html.CanvasElement canvas) => _engine.engine.canvas = canvas; + + void toggleGrid() { + _engine.engine.toggleEdgeRendering(); + } } From 32a3676d95aaef417342936ffdc6302ffd1d4464 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 15:19:54 +0200 Subject: [PATCH 111/120] Remove deprecated strict mode --- analysis_options.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index caef4c8..78fb282 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,6 +1,6 @@ analyzer: exclude: [build/**] - strong-mode: true + errors: uri_has_not_been_generated: ignore plugins: From 8db9cd6ff1c363b21913b468ffa83be14db79055 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 18 Oct 2018 15:21:50 +0200 Subject: [PATCH 112/120] Move Simulation Accesses to Simulation Class Everything has been refactored away from engine, which now only controls updating & rendering within a specific timestep. (As well as stepping forward by calling a single update) Everything regarding grids, patterns and cells has been moved into the simulation and the Services have been updated to reflect that. --- lib/service/engine_service.dart | 16 +++---------- lib/service/simulation_service.dart | 25 ++++++++++++------- lib/src/Engine.dart | 37 ++++------------------------- lib/src/Simulation.dart | 10 +++++++- test/src/engine_test.dart | 8 ------- 5 files changed, 33 insertions(+), 63 deletions(-) diff --git a/lib/service/engine_service.dart b/lib/service/engine_service.dart index a76fedb..b276d28 100644 --- a/lib/service/engine_service.dart +++ b/lib/service/engine_service.dart @@ -1,4 +1,5 @@ import 'package:rules_of_living/src/Engine.dart'; +import 'package:rules_of_living/src/Simulation.dart'; class EngineService { Engine _uncachedEngineAccess; @@ -41,18 +42,7 @@ class EngineService { int get simSpeed => engine.stepsPerSecond; void set simSpeed(int val) => engine.stepsPerSecond = val; - void reset() { - engine.reset(); - } - - void addRandomPattern() { - engine.running = false; - engine.addPattern(); - } - - void clear() { - engine.clear(); - } - bool get isRunning => engine.running; + + void set simulation(Simulation value) => engine.simulation = value; } diff --git a/lib/service/simulation_service.dart b/lib/service/simulation_service.dart index b5a9021..396290b 100644 --- a/lib/service/simulation_service.dart +++ b/lib/service/simulation_service.dart @@ -2,35 +2,42 @@ import 'dart:html' as html; import 'dart:math'; import 'package:rules_of_living/service/engine_service.dart'; +import 'package:rules_of_living/src/Simulation.dart'; class SimulationService { - final EngineService _engine; + // DEFAULT VALUES + static final int DEFAULT_GRID_SIZE = 50; - SimulationService(this._engine); + final EngineService _engine; + final Simulation _sim = Simulation(DEFAULT_GRID_SIZE, DEFAULT_GRID_SIZE); + + SimulationService(this._engine) { + _engine.simulation = _sim; + _sim.addRandomPattern(amount: 15, dispersal: 5); + } void reset() { - _engine.reset(); + _sim.reset(); } void addRandomPattern() { - _engine.addRandomPattern(); + _sim.addRandomPattern(); } void clear() { - _engine.clear(); + _sim.reset(); } + Point get gridSize => _sim.gridSize; void set gridSize(Point size) { - _engine.engine.gridSize = size; + _sim.gridSize = size; } - Point get gridSize => _engine.engine.gridSize; - //TODO split into RenderService when rendering is decoupled from engine. html.CanvasElement get canvas => _engine.engine.canvas; void set canvas(html.CanvasElement canvas) => _engine.engine.canvas = canvas; void toggleGrid() { - _engine.engine.toggleEdgeRendering(); + _sim.renderEdges = !_sim.renderEdges; } } diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index 3653353..ad101ca 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -29,16 +29,6 @@ class Engine { // ms stuck in updateloop after which game will declare itself unresponsive final int SAFETY_TIMEOUT = 2000; - /// Grid Size - /// - /// Number of cells on x coordinate and y coordinate. Can be set individually. - Point get gridSize => Point(_simulation.w, _simulation.h); - void set gridSize(Point value) { - if (value.x <= 0 || value.y <= 0) - throw ArgumentError("grid size must not be smaller than 1"); - _simulation = Simulation(value.x, value.y); - } - num _updateLag = 0.0; num _drawLag = 0.0; @@ -51,11 +41,8 @@ class Engine { Simulation _simulation; bool running = false; - Engine([x = 100, y = 100, this.canvas]) { - _simulation = Simulation(x, y); - + Engine() { _elapsed.start(); - _simulation.addRandomPattern(amount: 15, dispersal: 5); html.window.animationFrame.then(animFrame); } @@ -64,16 +51,6 @@ class Engine { html.window.animationFrame.then(animFrame); } - void reset() { - _simulation.reset(); - running = false; - } - - void clear() { - _simulation = new Simulation(gridSize.x, gridSize.y); - running = false; - } - void process(num now) { _drawLag += _elapsed.elapsedMilliseconds; _updateLag += _elapsed.elapsedMilliseconds; @@ -101,6 +78,8 @@ class Engine { /// directly, since it is automatically taken care of by the processing function. /// If simulation should be advanced manually one time, prefer using step(). void update() { + if (_simulation == null) return; + Map simulationUpdate = _simulation.update(); _simulation.mergeStateChanges(simulationUpdate); @@ -123,16 +102,10 @@ class Engine { /// the internal engine processing. Does not do anything if no canvas is /// defined. void render([num interp]) { - if (canvas == null) return; + if (canvas == null || _simulation == null) return; _simulation.render(canvas, interp); } - void addPattern({int amount, int dispersal}) { - _simulation.addRandomPattern(amount: amount, dispersal: dispersal); - } - - void toggleEdgeRendering() { - _simulation.renderEdges = !_simulation.renderEdges; - } + void set simulation(Simulation value) => _simulation = value; } diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index 42df2a4..fd8bbcb 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -1,5 +1,6 @@ import 'dart:html' as html; import 'dart:math' as math; +import 'dart:math'; import 'package:rules_of_living/src/Grid.dart'; import 'package:rules_of_living/src/rules/GameOfLife.dart'; @@ -8,7 +9,7 @@ import 'package:rules_of_living/src/rules/RuleSet.dart'; enum CellPattern { SpaceShip, Blinker } class Simulation { - final Grid map; + Grid map; RuleSet rules = GameOfLife(); bool _dirty = true; @@ -20,6 +21,13 @@ class Simulation { int get w => map.width; int get h => map.height; + Point get gridSize => Point(w, h); + void set gridSize(Point value) { + if (value.x <= 0 || value.y <= 0) + throw ArgumentError("grid size must not be smaller than 1"); + map = Grid(value.x, value.y); + } + Simulation(int w, int h) : this.map = new Grid(w, h) { reset(); print("Grid Created"); diff --git a/test/src/engine_test.dart b/test/src/engine_test.dart index fcfefc2..bd184a4 100644 --- a/test/src/engine_test.dart +++ b/test/src/engine_test.dart @@ -31,12 +31,4 @@ void main() { expect(sut.canvas, isNotNull); }); }); - group("gridSize", () { - test("zero gridSizes throw ArgumentErrors", () { - expect(() => sut.gridSize = Point(0, 5), throwsArgumentError); - }); - test("negative gridSizes throw ArgumentErrors", () { - expect(() => sut.gridSize = Point(1, -5), throwsArgumentError); - }); - }); } From 2993b33d9e9e8135297f171b055d2c607f0fcd7f Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 19 Oct 2018 08:23:00 +0200 Subject: [PATCH 113/120] Add tests for CellPattern & GameOfLife classes --- lib/src/rules/CellPattern.dart | 11 +++++++++-- test/src/rules/cellpattern_test.dart | 19 +++++++++++++++++++ test/src/rules/gameoflife_test.dart | 27 +++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 test/src/rules/cellpattern_test.dart create mode 100644 test/src/rules/gameoflife_test.dart diff --git a/lib/src/rules/CellPattern.dart b/lib/src/rules/CellPattern.dart index 9798948..ed4cae7 100644 --- a/lib/src/rules/CellPattern.dart +++ b/lib/src/rules/CellPattern.dart @@ -1,10 +1,17 @@ +import 'dart:math'; + import 'package:collection/collection.dart'; -class CellPattern extends DelegatingList { +class CellPattern extends DelegatingList { final String _name; - CellPattern(String name, List base) + CellPattern(String name, List base) : _name = name, super(base); String get name => _name; + + @override + String toString() { + return "$name: ${super.toString()}"; + } } diff --git a/test/src/rules/cellpattern_test.dart b/test/src/rules/cellpattern_test.dart new file mode 100644 index 0000000..a7989f5 --- /dev/null +++ b/test/src/rules/cellpattern_test.dart @@ -0,0 +1,19 @@ +import 'dart:math'; + +import 'package:rules_of_living/src/rules/CellPattern.dart'; +import 'package:test/test.dart'; + +void main() { + CellPattern sut; + setUp(() { + sut = CellPattern("testPattern", [Point(1, 1), Point(0, 0), Point(-1, -1)]); + }); + group("Naming", () { + test("contains the name passed in for name variable", + () => expect(sut.name, "testPattern")); + test( + "Contains the name passed in on being formatted as String", + () => expect(sut.toString(), + "testPattern: [Point(1, 1), Point(0, 0), Point(-1, -1)]")); + }); +} diff --git a/test/src/rules/gameoflife_test.dart b/test/src/rules/gameoflife_test.dart new file mode 100644 index 0000000..565e4e1 --- /dev/null +++ b/test/src/rules/gameoflife_test.dart @@ -0,0 +1,27 @@ +import 'package:rules_of_living/src/rules/GameOfLife.dart'; +import 'package:test/test.dart'; + +void main() { + GameOfLife sut; + setUp(() { + sut = GameOfLife(); + }); + group("BirthRules", () { + test("will return true when being passed three neighbors", + () => expect(sut.checkBirth(3), true)); + test("will return false when being passed zero neighbors", + () => expect(sut.checkBirth(0), false)); + test("will return false when being passed two neighbors", + () => expect(sut.checkBirth(2), false)); + }); + group("SurviveRules", () { + test("will return true when being passed two neighbors", + () => expect(sut.checkSurvival(2), true)); + test("will return true when being passed three neighbors", + () => expect(sut.checkSurvival(3), true)); + test("will return false when being passed 0 neighbors", + () => expect(sut.checkSurvival(0), false)); + test("will return false when being passed more than 3 neighbors", + () => expect(sut.checkSurvival(4), false)); + }); +} From e8c1e6ed8b36f7b0ed6fede88916eb1dfebb4f86 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 19 Oct 2018 11:50:34 +0200 Subject: [PATCH 114/120] Refactor Engine Methods Extract method checking for update necessity. --- lib/src/Engine.dart | 33 ++++++++------ test/src/engine_test.dart | 95 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 112 insertions(+), 16 deletions(-) diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart index ad101ca..5653bb9 100644 --- a/lib/src/Engine.dart +++ b/lib/src/Engine.dart @@ -1,5 +1,4 @@ import 'dart:html' as html; -import 'dart:math'; import 'package:rules_of_living/src/Simulation.dart'; @@ -47,31 +46,37 @@ class Engine { } void animFrame(num now) { - process(now); + int elapsed = _elapsed.elapsedMilliseconds; + _elapsed.reset(); + process(elapsed, SAFETY_TIMEOUT, update: this.update, render: this.render); html.window.animationFrame.then(animFrame); } - void process(num now) { - _drawLag += _elapsed.elapsedMilliseconds; - _updateLag += _elapsed.elapsedMilliseconds; - _elapsed.reset(); + void process(int elapsed, int timeOut, {Function update, Function render}) { + _drawLag += elapsed; + _updateLag += elapsed; - while (_updateLag >= _MS_PER_STEP) { - if (_elapsed.elapsedMilliseconds > SAFETY_TIMEOUT) { - // TODO stub - give warning etc when this occurs - print("ERROR STUCK IN UPDATE LOOP"); - break; - } - if (running == true) update(); + while (running == true && + _shouldUpdate(_updateLag, elapsed, timeOut) == true) { _updateLag -= _MS_PER_STEP; + if (update == null) break; + update(); } if (_drawLag >= _MS_PER_FRAME) { - render(_updateLag / _MS_PER_STEP); _drawLag = 0; + if (render == null) return; + render(_updateLag / _MS_PER_STEP); } } + bool _shouldUpdate(int updateLag, int elapsed, int timeOut) { + if (updateLag < _MS_PER_STEP) return false; + if (elapsed > timeOut) throw StackOverflowError; + + return true; + } + /// Update Engine Logic /// /// Updates the logic of the engine by one tick. Should usually not be called diff --git a/test/src/engine_test.dart b/test/src/engine_test.dart index bd184a4..f602069 100644 --- a/test/src/engine_test.dart +++ b/test/src/engine_test.dart @@ -1,15 +1,106 @@ import 'dart:html' as html; -import 'dart:math'; +import 'package:rules_of_living/src/Simulation.dart'; +import 'package:test/test.dart'; +import 'package:mockito/mockito.dart'; @TestOn('browser') import 'package:rules_of_living/src/Engine.dart'; -import 'package:test/test.dart'; + +class MockSimulation extends Mock implements Simulation { + int updateNum = 0; + bool hasChanges = false; + + @override + Map update() { + updateNum++; + return hasChanges ? {1: true, 2: false} : {}; + } +} void main() { Engine sut; setUp(() { sut = Engine(); }); + group("process", () { + setUp(() => sut.running = true); + test("errors out if updating takes too long", + () => expect(() => sut.process(5000, 10), throwsA(StackOverflowError))); + test("does not update if not enough time elapsed to pass ms per step", () { + bool result = false; + sut.stepsPerSecond = 1000; + + sut.process(999, 2000, + update: () => result = true, render: (double interp) => null); + + expect(result, true); + }); + test("updates only when the ms per step threshold is crossed", () { + int updateNum = 0; + sut.stepsPerSecond = 1; + + sut.process(1001, 2000, update: () => updateNum++); + expect(updateNum, equals(1)); + }); + test("updates until updateLag has been resolved", () { + int updateNum = 0; + sut.stepsPerSecond = 1; + + sut.process(2999, 5000, update: () => updateNum++); + expect(updateNum, equals(2)); + }); + test("works without passing in update or render function arguments", () { + sut.stepsPerSecond = 1000; + expect(() => sut.process(500, 5000), isNot(throwsA(anything))); + }); + }); + group("update", () { + MockSimulation mockSim; + setUp(() { + mockSim = MockSimulation(); + sut.simulation = mockSim; + }); + test("does not error out if no simulation variable is set", () { + sut.simulation = null; + expect(() => sut.update(), isNot(throwsA(anything))); + }); + test("updates simulation one tick for every time it is called", () { + sut.update(); + sut.update(); + sut.update(); + expect(mockSim.updateNum, equals(3)); + }); + test("sets running to false when simulation returns no changes", () { + sut.running = true; + sut.update(); + expect(sut.running, equals(false)); + }); + test("keeps running when simulation returns changes", () { + sut.running = true; + mockSim.hasChanges = true; + + sut.update(); + + expect(sut.running, equals(true)); + }); + }); + group("step", () { + MockSimulation mockSim; + setUp(() { + mockSim = MockSimulation(); + sut.simulation = mockSim; + }); + test("advances the simulation by one update", () { + sut.step(); + expect(mockSim.updateNum, equals(1)); + }); + test("turns off continuous engine updates", () { + sut.running = true; + sut.step(); + + expect(sut.running, equals(false)); + }); + }); group("canvas", () { test("Engine can be instantiated without canvas", () { expect(sut, isNot(throwsNoSuchMethodError)); From 2169de16fdd391e43e3670c2c388d7b3b63dc722 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 19 Oct 2018 19:35:09 +0200 Subject: [PATCH 115/120] Add Tests to Simulation --- lib/src/Simulation.dart | 21 +++++++++++---------- test/simulation_test.dart | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 test/simulation_test.dart diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index fd8bbcb..54c7efa 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -13,15 +13,15 @@ class Simulation { RuleSet rules = GameOfLife(); bool _dirty = true; + bool get dirty => _dirty; + bool _renderEdges = true; + bool get renderEdges => _renderEdges; int _amount; int _dispersal; - int get w => map.width; - int get h => map.height; - - Point get gridSize => Point(w, h); + Point get gridSize => Point(map.width, map.height); void set gridSize(Point value) { if (value.x <= 0 || value.y <= 0) throw ArgumentError("grid size must not be smaller than 1"); @@ -29,13 +29,16 @@ class Simulation { } Simulation(int w, int h) : this.map = new Grid(w, h) { - reset(); - print("Grid Created"); + this.map = reset(); } - void reset() { - map.setAll(0, List.filled(map.length, false)); + Simulation.fromGrid(Grid map) : this.map = map; + + Grid reset([Grid map]) { + map ??= this.map; _dirty = true; + map.setAll(0, List.filled(map.length, false)); + return map; } void addRandomPattern({int amount, int dispersal}) { @@ -148,6 +151,4 @@ class Simulation { _renderEdges = on; _dirty = true; } - - bool get renderEdges => _renderEdges; } diff --git a/test/simulation_test.dart b/test/simulation_test.dart new file mode 100644 index 0000000..b8f5db6 --- /dev/null +++ b/test/simulation_test.dart @@ -0,0 +1,37 @@ +import 'dart:math'; +import 'package:mockito/mockito.dart'; +import 'package:rules_of_living/src/Grid.dart'; +import 'package:test/test.dart'; + +import 'package:rules_of_living/src/Simulation.dart'; + +void main() { + Simulation sut; + setUp(() { + sut = Simulation(10, 10); + }); + group("gridSize", () { + test( + "returns the width and height of the underlying grid", + () => expect( + sut.gridSize, equals(Point(sut.map.width, sut.map.height)))); + test("sets the underlying grid width and height", () { + sut.gridSize = Point(2, 3); + expect(sut.gridSize, equals(Point(2, 3))); + }); + test("creates a new underlying grid on resizing", () { + var oldMap = sut.map; + sut.gridSize = Point(10, 10); + expect(sut.map, isNot(oldMap)); + }); + }); + group("reset", () { + test("returns a map filled with 'false' ", () { + expect(sut.reset(), allOf(TypeMatcher(), isNot(contains(true)))); + }); + test("sets the simulation to need re-rendering", () { + sut.reset(); + expect(sut.dirty, true); + }, skip: "can not find a way to set dirty to true first yet"); + }); +} From 0da2d08b74dccbeb630882e23d0cb017a27198c8 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 19 Oct 2018 19:59:00 +0200 Subject: [PATCH 116/120] Add Simulation Saving and Loading Methods --- lib/src/Simulation.dart | 5 +++++ test/simulation_test.dart | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index 54c7efa..5243b84 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -10,6 +10,8 @@ enum CellPattern { SpaceShip, Blinker } class Simulation { Grid map; + Grid _snapshot; + RuleSet rules = GameOfLife(); bool _dirty = true; @@ -151,4 +153,7 @@ class Simulation { _renderEdges = on; _dirty = true; } + + void saveSnapshot() => _snapshot = map; + Grid loadSnapshot() => map = _snapshot; } diff --git a/test/simulation_test.dart b/test/simulation_test.dart index b8f5db6..d137f97 100644 --- a/test/simulation_test.dart +++ b/test/simulation_test.dart @@ -5,6 +5,8 @@ import 'package:test/test.dart'; import 'package:rules_of_living/src/Simulation.dart'; +class MockGrid extends Mock implements Grid {} + void main() { Simulation sut; setUp(() { @@ -34,4 +36,13 @@ void main() { expect(sut.dirty, true); }, skip: "can not find a way to set dirty to true first yet"); }); + group("save&load", () { + test("saves the current map, can be loaded by loadSnapshot", () { + var snapshot = sut.map; + sut.saveSnapshot(); + sut.map = MockGrid(); + + expect(sut.loadSnapshot(), equals(snapshot)); + }); + }); } From 37bff59f83f7a4e08254ff9ec34e565df4dff7ff Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 19 Oct 2018 20:01:52 +0200 Subject: [PATCH 117/120] Remove clear function: Code Duplication --- lib/components/controls_component.dart | 2 +- lib/service/simulation_service.dart | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/components/controls_component.dart b/lib/components/controls_component.dart index 3f31741..1d7ee17 100644 --- a/lib/components/controls_component.dart +++ b/lib/components/controls_component.dart @@ -39,6 +39,6 @@ class ControlsComponent { } void onClearClicked() { - sim.clear(); + sim.reset(); } } diff --git a/lib/service/simulation_service.dart b/lib/service/simulation_service.dart index 396290b..5f538ec 100644 --- a/lib/service/simulation_service.dart +++ b/lib/service/simulation_service.dart @@ -24,10 +24,6 @@ class SimulationService { _sim.addRandomPattern(); } - void clear() { - _sim.reset(); - } - Point get gridSize => _sim.gridSize; void set gridSize(Point size) { _sim.gridSize = size; From 2ea974bbd53d99600678a5da7b46e0f31ff03c56 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 19 Oct 2018 20:49:59 +0200 Subject: [PATCH 118/120] Fix Snapshot Load and Save Functions Were just pointers to the map before. Fix to be actual clones of the map. --- lib/src/Simulation.dart | 8 ++++++-- test/simulation_test.dart | 10 ++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart index 5243b84..0955c9a 100644 --- a/lib/src/Simulation.dart +++ b/lib/src/Simulation.dart @@ -154,6 +154,10 @@ class Simulation { _dirty = true; } - void saveSnapshot() => _snapshot = map; - Grid loadSnapshot() => map = _snapshot; + void saveSnapshot() => _snapshot = Grid.from(map); + Grid loadSnapshot() { + map = Grid.from(_snapshot); + _dirty = true; + return map; + } } diff --git a/test/simulation_test.dart b/test/simulation_test.dart index d137f97..7b8bf82 100644 --- a/test/simulation_test.dart +++ b/test/simulation_test.dart @@ -37,12 +37,14 @@ void main() { }, skip: "can not find a way to set dirty to true first yet"); }); group("save&load", () { - test("saves the current map, can be loaded by loadSnapshot", () { - var snapshot = sut.map; + test( + "saves a copy of the map which does not change when the actual map changes", + () { sut.saveSnapshot(); - sut.map = MockGrid(); + sut.mergeStateChanges({1: true, 2: true}); + var snapshot = Grid.from(sut.map); - expect(sut.loadSnapshot(), equals(snapshot)); + expect(sut.loadSnapshot(), isNot(equals(snapshot))); }); }); } From 22dabda987fcc3217274831df8c2a6e42a60bd7d Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 19 Oct 2018 20:50:24 +0200 Subject: [PATCH 119/120] Add Save and Load Functions to SimService --- lib/service/simulation_service.dart | 8 ++++++-- test/service/simulation_service_test.dart | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 test/service/simulation_service_test.dart diff --git a/lib/service/simulation_service.dart b/lib/service/simulation_service.dart index 5f538ec..8e0c14f 100644 --- a/lib/service/simulation_service.dart +++ b/lib/service/simulation_service.dart @@ -9,9 +9,10 @@ class SimulationService { static final int DEFAULT_GRID_SIZE = 50; final EngineService _engine; - final Simulation _sim = Simulation(DEFAULT_GRID_SIZE, DEFAULT_GRID_SIZE); + final Simulation _sim; - SimulationService(this._engine) { + SimulationService(this._engine, [Simulation sim]) + : this._sim = sim ?? Simulation(DEFAULT_GRID_SIZE, DEFAULT_GRID_SIZE) { _engine.simulation = _sim; _sim.addRandomPattern(amount: 15, dispersal: 5); } @@ -36,4 +37,7 @@ class SimulationService { void toggleGrid() { _sim.renderEdges = !_sim.renderEdges; } + + void save() => _sim.saveSnapshot(); + void load() => _sim.loadSnapshot(); } diff --git a/test/service/simulation_service_test.dart b/test/service/simulation_service_test.dart new file mode 100644 index 0000000..3816099 --- /dev/null +++ b/test/service/simulation_service_test.dart @@ -0,0 +1,23 @@ +import 'package:rules_of_living/service/engine_service.dart'; +import 'package:rules_of_living/service/simulation_service.dart'; +import 'package:rules_of_living/src/Simulation.dart'; +import 'package:test/test.dart'; +import 'package:mockito/mockito.dart'; + +class MockSimulation extends Mock implements Simulation {} + +class MockEngineService extends Mock implements EngineService {} + +void main() { + SimulationService sut; + MockSimulation mockSim = MockSimulation(); + setUp(() => sut = SimulationService(MockEngineService(), mockSim)); + test("calling save calls through to Simulation.saveSnapshot", () { + sut.save(); + verify(mockSim.saveSnapshot()); + }); + test("calling load calls through to Simulation.loadSnapshot", () { + sut.load(); + verify(mockSim.loadSnapshot()); + }); +} From 92e147028e3a134fcbd64a3c0fdd396d07f47b43 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 19 Oct 2018 20:51:14 +0200 Subject: [PATCH 120/120] Add Save and Load Buttons to Interface Fully functional and tested. --- lib/components/controls_component.dart | 8 ++++++-- lib/components/controls_component.html | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/components/controls_component.dart b/lib/components/controls_component.dart index 1d7ee17..538bc27 100644 --- a/lib/components/controls_component.dart +++ b/lib/components/controls_component.dart @@ -29,8 +29,12 @@ class ControlsComponent { engine.step(); } - void onResetClicked() { - sim.reset(); + void onSaveClicked() { + sim.save(); + } + + void onLoadClicked() { + sim.load(); } void onRandomClicked() { diff --git a/lib/components/controls_component.html b/lib/components/controls_component.html index 42e79f7..764ca37 100644 --- a/lib/components/controls_component.html +++ b/lib/components/controls_component.html @@ -1,5 +1,6 @@
- + +