cellular-automata/lib/src/Grid.dart

69 lines
2.4 KiB
Dart

import 'dart:core';
import 'dart:math';
import 'package:collection/collection.dart';
class Grid<E> extends DelegatingList<E> {
final List<E> _internal;
final width;
final height;
Grid(int width, int height) : this._(List<E>(width * height), width, height);
Grid.fill(int width, int height, E fillValue)
: this._(List<E>.filled(width * height, fillValue), width, height);
Grid.from(Grid<E> l)
: this._(List<E>.from(l.getRange(0, l.length)), l.width, l.height);
Grid.fromList(List<E> l, int width) : this._(l, width, l.length ~/ width);
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];
}
/// 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;
}
/// 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;
/// 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<int> toCoordinates(int index) => (index < 0)
? throw RangeError("Index for Grid Coordinates must not be negative")
: Point<int>(index % width, index ~/ width);
}