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: diff --git a/lib/app_component.dart b/lib/app_component.dart index ae8a931..1656739 100644 --- a/lib/app_component.dart +++ b/lib/app_component.dart @@ -4,9 +4,8 @@ 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/control_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,8 +23,7 @@ import 'package:rules_of_living/service/engine_service.dart'; providers: [ materialProviders, ClassProvider(EngineService), - ClassProvider(ConfigurationService), - ClassProvider(ControlService) + ClassProvider(SimulationService) ], styleUrls: const [ 'package:angular_components/app_layout/layout.scss.css', diff --git a/lib/components/configuration_component.dart b/lib/components/configuration_component.dart index cc1ecd1..abbd2e5 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(); + sim.toggleGrid(); } } diff --git a/lib/components/controls_component.dart b/lib/components/controls_component.dart index 954d94b..3f31741 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/control_service.dart'; +import 'package:rules_of_living/service/engine_service.dart'; +import 'package:rules_of_living/service/simulation_service.dart'; @Component( selector: 'sim-controls', @@ -15,27 +16,29 @@ import 'package:rules_of_living/service/control_service.dart'; styleUrls: const ["controls_component.css"], ) class ControlsComponent { - final ControlService ctrl; + final EngineService engine; + final SimulationService sim; - ControlsComponent(this.ctrl); + ControlsComponent(this.engine, this.sim); void onStartClicked() { - ctrl.toggleRunning(); + engine.toggleRunning(); } void onStepClicked() { - ctrl.step(); + engine.step(); } void onResetClicked() { - ctrl.reset(); + sim.reset(); } void onRandomClicked() { - ctrl.addRandomPattern(); + sim.addRandomPattern(); + engine.stop(); } void onClearClicked() { - ctrl.clear(); + sim.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 @@
- + diff --git a/lib/components/simulation_component.dart b/lib/components/simulation_component.dart index 312eef4..1fcef71 100644 --- a/lib/components/simulation_component.dart +++ b/lib/components/simulation_component.dart @@ -1,7 +1,8 @@ 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'; +import 'package:rules_of_living/service/simulation_service.dart'; @Component( selector: 'gol-simulation', @@ -10,9 +11,10 @@ import 'package:rules_of_living/service/configuration_service.dart'; providers: [], ) class SimulationComponent implements OnInit { - final ConfigurationService config; + final EngineService engine; + final SimulationService sim; - SimulationComponent(this.config); + 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); - config.canvas = canvas; + sim.canvas = canvas; } } diff --git a/lib/service/configuration_service.dart b/lib/service/configuration_service.dart deleted file mode 100644 index e11a5e8..0000000 --- a/lib/service/configuration_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'; - -class ConfigurationService { - final EngineService _es; - - bool showGrid; - - int _simSpeed; - - ConfigurationService(this._es) { - 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; - _es.engine.stepsPerSecond = simSpeed; - } - - void set canvas(html.CanvasElement canvas) => _es.engine.canvas = canvas; - html.CanvasElement get canvas => _es.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); - } - - Point get gridSize => _es.engine.gridSize; -} 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..b276d28 100644 --- a/lib/service/engine_service.dart +++ b/lib/service/engine_service.dart @@ -1,8 +1,13 @@ 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; @@ -12,4 +17,32 @@ 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(); + } + + /// 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 new file mode 100644 index 0000000..396290b --- /dev/null +++ b/lib/service/simulation_service.dart @@ -0,0 +1,43 @@ +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 = Simulation(DEFAULT_GRID_SIZE, DEFAULT_GRID_SIZE); + + SimulationService(this._engine) { + _engine.simulation = _sim; + _sim.addRandomPattern(amount: 15, dispersal: 5); + } + + void reset() { + _sim.reset(); + } + + void addRandomPattern() { + _sim.addRandomPattern(); + } + + void clear() { + _sim.reset(); + } + + 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; + } +} 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/service/configuration_service_test.dart b/test/service/configuration_service_test.dart deleted file mode 100644 index 44e23b2..0000000 --- a/test/service/configuration_service_test.dart +++ /dev/null @@ -1,46 +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/src/Engine.dart'; -@TestOn('browser') -import 'package:test/test.dart'; - -class MockEngine extends Mock implements Engine {} - -void main() { - ConfigurationService sut; - EngineService engineService; - MockEngine me; - setUp(() { - me = MockEngine(); - engineService = EngineService(); - engineService.engine = me; - sut = ConfigurationService(engineService); - }); - - 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)); - }); - }); -} 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); - }); - }); }