From 0c487f3427ec76ee675e8c9b63ce62eeedecf57a Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Wed, 29 Aug 2018 20:11:56 +0200 Subject: [PATCH 01/15] 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 02/15] 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 03/15] 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 04/15] 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 05/15] 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 06/15] 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 07/15] 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 08/15] 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 09/15] 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 10/15] 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 11/15] 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 12/15] 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 13/15] 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 14/15] 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 15/15] 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; }