diff --git a/LICENSE.md b/LICENSE.md
index 2246719..86a595d 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,21 +1,2 @@
-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
+
+Copyright (C) 2018
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 78fb282..caef4c8 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:
diff --git a/dart_test.yaml b/dart_test.yaml
deleted file mode 100644
index a7c6d02..0000000
--- a/dart_test.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-platforms: [chrome]
-
-tags:
- nobrowser:
-
- bad:
-
- sad:
-
- happy:
diff --git a/lib/app_component.css b/lib/app_component.css
deleted file mode 100644
index 2e1a6f4..0000000
--- a/lib/app_component.css
+++ /dev/null
@@ -1,11 +0,0 @@
-#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 1656739..e5ece87 100644
--- a/lib/app_component.dart
+++ b/lib/app_component.dart
@@ -1,35 +1,47 @@
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/engine_service.dart';
-import 'package:rules_of_living/service/simulation_service.dart';
+
+import 'dart:html' as html;
+import 'package:rules_of_living/src/App.dart';
@Component(
selector: 'my-app',
templateUrl: "app_component.html",
- directives: [
- coreDirectives,
- MaterialButtonComponent,
- MaterialIconComponent,
- MaterialSliderComponent,
- HeaderComponent,
- SimulationComponent,
- ControlsComponent,
- ConfigurationComponent
- ],
- providers: [
- materialProviders,
- ClassProvider(EngineService),
- ClassProvider(SimulationService)
- ],
- styleUrls: const [
- 'package:angular_components/app_layout/layout.scss.css',
- 'app_component.css'
- ],
+ directives: [coreDirectives]
)
-class AppComponent {
+class AppComponent implements OnInit {
var name = "World";
+
+ App engine;
+
+ @ViewChild("caCanvas")
+ html.CanvasElement canvas;
+
+ @override
+ void ngOnInit() {
+ canvas.context2D.setFillColorRgb(255, 0, 0);
+ canvas.context2D.fillRect(0, 0, 200, 150);
+ engine = new App(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.running = false;
+ engine.update();
+ }
+
+ void onResetClicked() {
+ engine.reset();
+ }
+
+ void onRandomClicked() {}
}
diff --git a/lib/app_component.html b/lib/app_component.html
index 8b57941..366ce7b 100644
--- a/lib/app_component.html
+++ b/lib/app_component.html
@@ -1,10 +1,20 @@
-
-
-
-
-
-
-
+
Cellular Automata - The Rules of Life
+
+ Ruleset:
+
+
+
+
+
+
+
+
+
+
+ Speed:
\ No newline at end of file
diff --git a/lib/components/configuration_component.css b/lib/components/configuration_component.css
deleted file mode 100644
index 2108951..0000000
--- a/lib/components/configuration_component.css
+++ /dev/null
@@ -1,4 +0,0 @@
-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
deleted file mode 100644
index abbd2e5..0000000
--- a/lib/components/configuration_component.dart
+++ /dev/null
@@ -1,54 +0,0 @@
-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';
-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/engine_service.dart';
-import 'package:rules_of_living/service/simulation_service.dart';
-
-@Component(
- selector: "configuration",
- templateUrl: "configuration_component.html",
- styleUrls: [
- "configuration_component.css"
- ],
- directives: [
- MaterialButtonComponent,
- MaterialIconComponent,
- MaterialSliderComponent,
- MaterialTooltipDirective,
- materialInputDirectives,
- materialNumberInputDirectives,
- NgModel
- ])
-class ConfigurationComponent {
- final EngineService engine;
- final SimulationService sim;
-
- int get width => sim.gridSize.x;
- void set width(num value) {
- if (value == null || value <= 0) return;
- sim.gridSize = Point(value, sim.gridSize.y);
- }
-
- int get height => sim.gridSize.y;
- void set height(num value) {
- if (value == null || value <= 0) return;
- sim.gridSize = Point(sim.gridSize.x, value);
- }
-
- int get simSpeed => engine.simSpeed;
- void set simSpeed(int value) => engine.simSpeed = value;
-
- String get speedSliderTooltip => "Simulation Speed: $simSpeed";
-
- ConfigurationComponent(this.engine, this.sim);
-
- void onEdgesClicked() {
- sim.toggleGrid();
- }
-}
diff --git a/lib/components/configuration_component.html b/lib/components/configuration_component.html
deleted file mode 100644
index d8a3e8b..0000000
--- a/lib/components/configuration_component.html
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
- Ruleset:
-
-
-
-
\ No newline at end of file
diff --git a/lib/components/controls_component.css b/lib/components/controls_component.css
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/components/controls_component.dart b/lib/components/controls_component.dart
deleted file mode 100644
index 538bc27..0000000
--- a/lib/components/controls_component.dart
+++ /dev/null
@@ -1,48 +0,0 @@
-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',
- templateUrl: "controls_component.html",
- directives: [
- coreDirectives,
- MaterialButtonComponent,
- MaterialIconComponent,
- MaterialTooltipDirective
- ],
- providers: [],
- styleUrls: const ["controls_component.css"],
-)
-class ControlsComponent {
- final EngineService engine;
- final SimulationService sim;
-
- ControlsComponent(this.engine, this.sim);
-
- void onStartClicked() {
- engine.toggleRunning();
- }
-
- void onStepClicked() {
- engine.step();
- }
-
- void onSaveClicked() {
- sim.save();
- }
-
- void onLoadClicked() {
- sim.load();
- }
-
- void onRandomClicked() {
- sim.addRandomPattern();
- engine.stop();
- }
-
- void onClearClicked() {
- sim.reset();
- }
-}
diff --git a/lib/components/controls_component.html b/lib/components/controls_component.html
deleted file mode 100644
index 764ca37..0000000
--- a/lib/components/controls_component.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/lib/components/header_component.dart b/lib/components/header_component.dart
deleted file mode 100644
index 83970fd..0000000
--- a/lib/components/header_component.dart
+++ /dev/null
@@ -1,16 +0,0 @@
-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
deleted file mode 100644
index 2f87a66..0000000
--- a/lib/components/header_component.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
\ No newline at end of file
diff --git a/lib/components/simulation_component.dart b/lib/components/simulation_component.dart
deleted file mode 100644
index 1fcef71..0000000
--- a/lib/components/simulation_component.dart
+++ /dev/null
@@ -1,36 +0,0 @@
-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',
- templateUrl: "simulation_component.html",
- directives: [coreDirectives],
- providers: [],
-)
-class SimulationComponent implements OnInit {
- final EngineService engine;
- final SimulationService sim;
-
- SimulationComponent(this.engine, this.sim);
-
- @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
-
- the canvas did not load correctly :(
- ''', canvas.width / 2 - 50, canvas.height / 2);
- sim.canvas = canvas;
- }
-}
diff --git a/lib/components/simulation_component.html b/lib/components/simulation_component.html
deleted file mode 100644
index 1e5f113..0000000
--- a/lib/components/simulation_component.html
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/lib/service/engine_service.dart b/lib/service/engine_service.dart
deleted file mode 100644
index b276d28..0000000
--- a/lib/service/engine_service.dart
+++ /dev/null
@@ -1,48 +0,0 @@
-import 'package:rules_of_living/src/Engine.dart';
-import 'package:rules_of_living/src/Simulation.dart';
-
-class EngineService {
- Engine _uncachedEngineAccess;
-
- EngineService() {
- simSpeed = 5;
- }
-
- Engine get engine => _uncachedEngineAccess ?? _setCachedAndReturn(Engine());
- void set engine(Engine newEngine) {
- _uncachedEngineAccess = newEngine;
- }
-
- Engine _setCachedAndReturn(Engine newEngine) {
- engine = newEngine;
- return newEngine;
- }
-
- void run() {
- engine.running = true;
- }
-
- void stop() {
- engine.running = false;
- }
-
- void toggleRunning() {
- engine.running = !engine.running;
- }
-
- void step() {
- 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;
-
- 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
deleted file mode 100644
index 8e0c14f..0000000
--- a/lib/service/simulation_service.dart
+++ /dev/null
@@ -1,43 +0,0 @@
-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 {
- // DEFAULT VALUES
- static final int DEFAULT_GRID_SIZE = 50;
-
- final EngineService _engine;
- final Simulation _sim;
-
- SimulationService(this._engine, [Simulation sim])
- : this._sim = sim ?? Simulation(DEFAULT_GRID_SIZE, DEFAULT_GRID_SIZE) {
- _engine.simulation = _sim;
- _sim.addRandomPattern(amount: 15, dispersal: 5);
- }
-
- void reset() {
- _sim.reset();
- }
-
- void addRandomPattern() {
- _sim.addRandomPattern();
- }
-
- Point
get gridSize => _sim.gridSize;
- void set gridSize(Point size) {
- _sim.gridSize = size;
- }
-
- //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() {
- _sim.renderEdges = !_sim.renderEdges;
- }
-
- void save() => _sim.saveSnapshot();
- void load() => _sim.loadSnapshot();
-}
diff --git a/lib/src/App.dart b/lib/src/App.dart
new file mode 100644
index 0000000..a571dba
--- /dev/null
+++ b/lib/src/App.dart
@@ -0,0 +1,66 @@
+import 'dart:html' as html;
+
+import 'package:rules_of_living/src/Grid.dart';
+
+class App {
+ // Elapsed Time Counter - useful for Safety Timeout
+ Stopwatch _elapsed = new Stopwatch();
+
+ // Game Tick Rate - *does* impact game speed
+ int _MS_PER_STEP = 1000 ~/ 3;
+
+ // Max Frame (i.e. Rendering) rate - does *not* impact game speed
+ final int _MS_PER_FRAME = 1000 ~/ 30;
+
+ // ms stuck in updateloop after which game will declare itself unresponsive
+ final int SAFETY_TIMEOUT = 2000;
+
+ num _updateLag = 0.0;
+ num _drawLag = 0.0;
+
+
+ final html.CanvasElement canvas;
+ Grid grid = new Grid(100,100);
+ bool running = false;
+
+ App(this.canvas) {
+ _elapsed.start();
+ }
+
+ void reset () {
+ grid = new Grid(100, 100);
+ running = false;
+ }
+
+ void process(num now) {
+ _drawLag+= _elapsed.elapsedMilliseconds;
+ _updateLag += _elapsed.elapsedMilliseconds;
+ _elapsed.reset();
+
+ 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();
+ _updateLag -= _MS_PER_STEP;
+ }
+
+ if (_drawLag >= _MS_PER_FRAME) {
+ render(_updateLag / _MS_PER_STEP);
+ _drawLag = 0;
+ }
+ }
+
+ void update() {
+// print("updating");
+ 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
new file mode 100644
index 0000000..5301fb6
--- /dev/null
+++ b/lib/src/Cell.dart
@@ -0,0 +1,32 @@
+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;
+
+ void advanceState() {
+ this.state = this.nextState;
+ this.nextState = false;
+
+ this.dirty = true;
+ }
+
+ 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/Engine.dart b/lib/src/Engine.dart
deleted file mode 100644
index 5653bb9..0000000
--- a/lib/src/Engine.dart
+++ /dev/null
@@ -1,116 +0,0 @@
-import 'dart:html' as html;
-
-import 'package:rules_of_living/src/Simulation.dart';
-
-class Engine {
- // Elapsed Time Counter - useful for Safety Timeout
- Stopwatch _elapsed = new Stopwatch();
-
- /// 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;
-
- // Max Frame (i.e. Rendering) rate - does *not* impact game speed
- final int _MS_PER_FRAME = 1000 ~/ 30;
-
- // ms stuck in updateloop after which game will declare itself unresponsive
- final int SAFETY_TIMEOUT = 2000;
-
- 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;
- Simulation _simulation;
- bool running = false;
-
- Engine() {
- _elapsed.start();
- html.window.animationFrame.then(animFrame);
- }
-
- void animFrame(num now) {
- int elapsed = _elapsed.elapsedMilliseconds;
- _elapsed.reset();
- process(elapsed, SAFETY_TIMEOUT, update: this.update, render: this.render);
- html.window.animationFrame.then(animFrame);
- }
-
- void process(int elapsed, int timeOut, {Function update, Function render}) {
- _drawLag += elapsed;
- _updateLag += elapsed;
-
- while (running == true &&
- _shouldUpdate(_updateLag, elapsed, timeOut) == true) {
- _updateLag -= _MS_PER_STEP;
- if (update == null) break;
- update();
- }
-
- if (_drawLag >= _MS_PER_FRAME) {
- _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
- /// 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);
-
- if (simulationUpdate.length == 0) 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() {
- update();
- running = false;
- }
-
- /// 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 || _simulation == null) return;
-
- _simulation.render(canvas, interp);
- }
-
- void set simulation(Simulation value) => _simulation = value;
-}
diff --git a/lib/src/Grid.dart b/lib/src/Grid.dart
index e2a62fc..b0d7e9f 100644
--- a/lib/src/Grid.dart
+++ b/lib/src/Grid.dart
@@ -1,68 +1,136 @@
-import 'dart:core';
-import 'dart:math';
+import 'dart:html' as html;
-import 'package:collection/collection.dart';
+import 'package:rules_of_living/src/Cell.dart';
+import 'package:rules_of_living/src/Rule.dart';
-class Grid extends DelegatingList {
- final List _internal;
- final width;
- final height;
+class Grid {
+ final int w;
+ final int h;
+ final List> map;
- Grid(int width, int height) : this._(List(width * height), width, height);
+ bool _dirty = true;
- Grid.fill(int width, int height, E fillValue)
- : this._(List.filled(width * height, fillValue), width, height);
+ Grid(int w, int h)
+ : this.w = w,
+ this.h = h,
+ this.map = new List() {
+ map.addAll(_buildGrid(w, h));
- Grid.from(Grid l)
- : this._(List.from(l.getRange(0, l.length)), l.width, l.height);
+ // 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;
- Grid.fromList(List l, int width) : this._(l, width, l.length ~/ width);
+ // 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);
- Grid._(l, int w, int h)
- : _internal = l,
- width = w,
- 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);
- return _internal[i];
+ print("Grid creation finished");
}
- /// 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 || x > width - 1) throw RangeError.index(i, this);
- _internal[i] = value;
+ void setState(int x, int y, bool state) {
+ if (y < map.length && x < map[y].length) map[y][x].state = state;
}
- /// 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;
+ 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;
+ });
- /// 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);
+ // 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(coagSurvive);
+ cell.birthRules.add(coagBirth);
+
+ grid[y][x] = cell;
+ }
+ }
+ return grid;
+ }
+
+ void update() {
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ // DEFAULTS TO CONWAY GAME OF LIFE RANGE OF ONE
+ map[y][x].update(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();
+ }
+ }
+ }
+
+ 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.length &&
+ ix < map[iy].length &&
+ map[iy][ix].state == true &&
+ !(x == ix && y == iy)) {
+ count++;
+ }
+ }
+ }
+ return count;
+ }
+
+ void render(html.CanvasElement canvas, [num interp]) {
+ // only renders if any cells changed between renders
+ if (!_dirty) return;
+
+ html.CanvasRenderingContext2D ctx = canvas.getContext('2d');
+ int brickW = (canvas.width ~/ map[0].length);
+ int brickH = (canvas.height ~/ map.length);
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ for (int y = 0; y < map.length; y++) {
+ for (int x = 0; x < map[y].length; x++) {
+ Cell c = map[y][x];
+ if (c.state == true)
+ ctx.setFillColorRgb(155, 155, 255);
+ else
+ ctx.setFillColorRgb(0, 0, 0);
+ ctx.fillRect(x * brickW, y * brickH, brickW, brickH);
+ }
+ }
+
+ _dirty = false;
+ }
}
diff --git a/lib/src/Rule.dart b/lib/src/Rule.dart
new file mode 100644
index 0000000..3a5eb1a
--- /dev/null
+++ b/lib/src/Rule.dart
@@ -0,0 +1,5 @@
+class Rule {
+ final Function evaluate;
+
+ Rule(this.evaluate);
+}
\ No newline at end of file
diff --git a/lib/src/Simulation.dart b/lib/src/Simulation.dart
deleted file mode 100644
index 0955c9a..0000000
--- a/lib/src/Simulation.dart
+++ /dev/null
@@ -1,163 +0,0 @@
-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';
-import 'package:rules_of_living/src/rules/RuleSet.dart';
-
-enum CellPattern { SpaceShip, Blinker }
-
-class Simulation {
- Grid map;
- Grid _snapshot;
-
- RuleSet rules = GameOfLife();
-
- bool _dirty = true;
- bool get dirty => _dirty;
-
- bool _renderEdges = true;
- bool get renderEdges => _renderEdges;
-
- int _amount;
- int _dispersal;
-
- 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");
- map = Grid(value.x, value.y);
- }
-
- Simulation(int w, int h) : this.map = new Grid(w, h) {
- this.map = reset();
- }
-
- 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}) {
- int _startingSeed = DateTime.now().millisecondsSinceEpoch;
- math.Random rng = new math.Random(_startingSeed);
- _amount = amount ?? rng.nextInt(20);
- _dispersal = dispersal ?? 10;
- 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++) {
- sanityCheck++;
- getCellState(cx, cy)
- ? i--
- : setCellState(
- cx + rng.nextInt(_dispersal), cy + rng.nextInt(_dispersal), true);
- if (sanityCheck > 100 && sanityCheck > i * 3) break;
- }
-
- _dirty = true;
- }
-
- void setCellState(int x, int y, bool state) {
- if (y >= map.height || x >= map.width) return 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);
- }
-
- 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);
- 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();
-
- 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, rules.range);
- if (cell == false && rules.checkBirth(neighbors) == true) {
- stateChanges[i] = true;
- } else if (cell == true && rules.checkSurvival(neighbors) == false) {
- stateChanges[i] = false;
- }
- }
- return stateChanges;
- }
-
- 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++) {
- if (ix >= 0 &&
- iy >= 0 &&
- ix < map.width &&
- iy < map.height &&
- getCellState(ix, iy) == true &&
- !(x == ix && y == iy)) count++;
- }
- }
- return count;
- }
-
- void render(html.CanvasElement canvas, [num interp]) {
- // only renders if any cells changed between renders
- if (!_dirty) return;
-
- html.CanvasRenderingContext2D ctx = canvas.getContext('2d');
- int brickW = (canvas.width ~/ map.width);
- int brickH = (canvas.height ~/ map.height);
- ctx.clearRect(0, 0, canvas.width, canvas.height);
- for (int i = 0; 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] == true)
- ctx.setFillColorRgb(155, 155, 255);
- else
- ctx.setFillColorRgb(0, 0, 0);
- ctx.fillRect(p.x * brickW, p.y * brickH, brickW, brickH);
- }
- _dirty = false;
- }
-
- void set renderEdges(bool on) {
- _renderEdges = on;
- _dirty = true;
- }
-
- void saveSnapshot() => _snapshot = Grid.from(map);
- Grid loadSnapshot() {
- map = Grid.from(_snapshot);
- _dirty = true;
- return map;
- }
-}
diff --git a/lib/src/rules/CellPattern.dart b/lib/src/rules/CellPattern.dart
deleted file mode 100644
index ed4cae7..0000000
--- a/lib/src/rules/CellPattern.dart
+++ /dev/null
@@ -1,17 +0,0 @@
-import 'dart:math';
-
-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;
-
- @override
- String toString() {
- return "$name: ${super.toString()}";
- }
-}
diff --git a/lib/src/rules/GameOfLife.dart b/lib/src/rules/GameOfLife.dart
deleted file mode 100644
index edb2dde..0000000
--- a/lib/src/rules/GameOfLife.dart
+++ /dev/null
@@ -1,38 +0,0 @@
-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 range = 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
deleted file mode 100644
index 03aeb36..0000000
--- a/lib/src/rules/RuleSet.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-import 'package:rules_of_living/src/rules/CellPattern.dart';
-
-abstract class RuleSet {
- int range;
- List patterns;
-
- bool checkSurvival(int neighbors);
- bool checkBirth(int neighbors);
-}
diff --git a/pubspec.yaml b/pubspec.yaml
index a63ea9a..9dc2faa 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -5,16 +5,14 @@ author: Marty Oehme
homepage: https://www.martyoehme.org/
environment:
- sdk: '>=2.0.0'
+ sdk: '>=2.0.0-dev.66.0 <2.0.0'
dependencies:
angular: ^5.0.0-beta
- angular_components: ^0.9.0-beta
dev_dependencies:
angular_test: ^2.0.0-beta
build_runner: ^0.9.0
- build_test: ^0.10.3+1
+ build_test: ^0.10.2
build_web_compilers: ^0.4.0
- test: ^1.3.0
- mockito: ^3.0.0
+ test: ^1.0.0
diff --git a/test/app_test_disable.dart b/test/app_test.dart
similarity index 100%
rename from test/app_test_disable.dart
rename to test/app_test.dart
diff --git a/test/service/engine_service_test.dart b/test/service/engine_service_test.dart
deleted file mode 100644
index a792b93..0000000
--- a/test/service/engine_service_test.dart
+++ /dev/null
@@ -1,41 +0,0 @@
-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';
-
-class MockEngine extends Mock implements Engine {}
-
-void main() {
- EngineService sut;
- MockEngine me;
- setUp(() {
- me = MockEngine();
- sut = EngineService();
- });
- group("Dependency Injection", () {
- test("EngineService can be passed a custom Engine", () {
- sut.engine = me;
-
- 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", () {
- Engine result = sut.engine;
- expect(sut.engine, equals(result));
- });
- test("caching can be overriden by providing a custom engine", () {
- Engine first = sut.engine;
- sut.engine = me;
- Engine second = sut.engine;
- expect(second, isNot(equals(first)));
- });
- });
-}
diff --git a/test/service/simulation_service_test.dart b/test/service/simulation_service_test.dart
deleted file mode 100644
index 3816099..0000000
--- a/test/service/simulation_service_test.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-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());
- });
-}
diff --git a/test/simulation_test.dart b/test/simulation_test.dart
deleted file mode 100644
index 7b8bf82..0000000
--- a/test/simulation_test.dart
+++ /dev/null
@@ -1,50 +0,0 @@
-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';
-
-class MockGrid extends Mock implements Grid {}
-
-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");
- });
- group("save&load", () {
- test(
- "saves a copy of the map which does not change when the actual map changes",
- () {
- sut.saveSnapshot();
- sut.mergeStateChanges({1: true, 2: true});
- var snapshot = Grid.from(sut.map);
-
- expect(sut.loadSnapshot(), isNot(equals(snapshot)));
- });
- });
-}
diff --git a/test/src/engine_test.dart b/test/src/engine_test.dart
deleted file mode 100644
index f602069..0000000
--- a/test/src/engine_test.dart
+++ /dev/null
@@ -1,125 +0,0 @@
-import 'dart:html' as html;
-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';
-
-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));
- });
-
- 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("setCanvas allows setting a canvas for an engine at any point", () {
- sut.canvas = new html.CanvasElement();
- expect(sut.canvas, isNotNull);
- });
- });
-}
diff --git a/test/src/grid_test.dart b/test/src/grid_test.dart
deleted file mode 100644
index fce1b3f..0000000
--- a/test/src/grid_test.dart
+++ /dev/null
@@ -1,189 +0,0 @@
-import 'dart:math';
-
-import 'package:rules_of_living/src/Grid.dart';
-import 'package:test/test.dart';
-
-@Tags(const ["nobrowser"])
-void main() {
- 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);
- }, 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"]);
- 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.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[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(".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;
- setUp(() {
- sut = Grid(3, 3);
- });
- 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"]);
- });
- 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"]);
- });
- 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"]);
- });
- 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"]);
- });
-}
diff --git a/test/src/rules/cellpattern_test.dart b/test/src/rules/cellpattern_test.dart
deleted file mode 100644
index a7989f5..0000000
--- a/test/src/rules/cellpattern_test.dart
+++ /dev/null
@@ -1,19 +0,0 @@
-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
deleted file mode 100644
index 565e4e1..0000000
--- a/test/src/rules/gameoflife_test.dart
+++ /dev/null
@@ -1,27 +0,0 @@
-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));
- });
-}
diff --git a/web/index.html b/web/index.html
index d5432b4..35bd3cb 100644
--- a/web/index.html
+++ b/web/index.html
@@ -15,10 +15,11 @@
-
-
+
+
+
diff --git a/web/styles.css b/web/styles.css
index e0b0d35..ef7a186 100644
--- a/web/styles.css
+++ b/web/styles.css
@@ -1,126 +1,117 @@
@import url(https://fonts.googleapis.com/css?family=Roboto);
@import url(https://fonts.googleapis.com/css?family=Material+Icons);
-html, body {
- height: 100%;
- margin: 0;
- padding: 0;
- width: 100%;
- font-family: 'Roboto', 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;
}
-/*!* 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;*/
-/*}*/
+/* 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;
+}