Camera View, Rotate, Trim and Pad a Map in Dart
Jump to navigation
Jump to search
Dart Implementation of Map Transformations
The code below is versatile in that it is map engine agnostic.
It will trim, pad, copy and rotate about any list-of-lists.
Usage
Rotate Right
final map = '''
##########
###....###
###....###
###....###
###....###
###....###
######.###
######▒▒▒#''';
List<List<String>> mapList =
map.trim().split('\n').map((row) => row.split('')).toList();
List<List<String>> result = Transform.rotateRight<String>(mapList);
String mapString = result.map((e) => e.join('')).join('\n');
print(mapString);
// ########
// ########
// ########
// ##.....#
// ##.....#
// ##.....#
// ▒......#
// ▒#######
// ▒#######
// ########
Pad
final map = '''
##########
###....###
###....###
###....###
###....###
###....###
######.###
######▒▒▒#''';
List<List<String>> mapList =
map.trim().split('\n').map((row) => row.split('')).toList();
String getWall() => '#';
List<List<String>> result = Transform.pad<String>(mapList, 2, getWall);
String mapString = result.map((e) => e.join('')).join('\n');
print(mapString);
// ##############
// ##############
// ##############
// #####....#####
// #####....#####
// #####....#####
// #####....#####
// #####....#####
// ########.#####
// ########▒▒▒###
// ##############
// ##############
Trim
final map = '''
##############
##############
##############
#####....#####
#####....#####
#####....#####
#####....#####
#####....#####
########.#####
########▒▒▒###
##############
##############''';
List<List<String>> mapList =
map.trim().split('\n').map((row) => row.split('')).toList();
bool isOuterWall(dynamic str) => str == '#';
List<List<String>> result = Transform.trim<String>(mapListPadded, isOuterWall);
String mapString = result.map((e) => e.join('')).join('\n');
print(mapString);
// ########
// #....###
// #....###
// #....###
// #....###
// #....###
// ####.###
// ####▒▒▒#
// ########
Copy
final map = '''
##########
###....###
###....###
###....###
###....###
###....###
######.###
######▒▒▒#''';
List<List<String>> mapList =
map.trim().split('\n').map((row) => row.split('')).toList();
List<List<String>> result = Transform.copy<String>(mapList, 0, 0, 5, 5);
String mapString = result.map((e) => e.join('')).join('\n');
print(mapString);
// ######
// ###...
// ###...
// ###...
// ###...
// ###...
Dart Implementation
import 'dart:math';
/// Allows for rotating, padding and trimming a list-of-lists.
class Transform {
// -----------------------------------------------------------------------
// ROTATE
// -----------------------------------------------------------------------
/// Rotates to the right.
static List<List<T>> rotateRight<T>(List<List<T>> target) {
List<List<T>> rotatedList = [];
final width = target.first.length;
final height = target.length - 1;
for (int column = 0; column < width; column++) {
final List<T> lineNew = [];
for (int row = height; row >= 0; row--) {
lineNew.add(target[row][column]);
}
rotatedList.add(lineNew);
}
return rotatedList;
}
// -----------------------------------------------------------------------
// PAD
// -----------------------------------------------------------------------
/// Pads with WALL tiles returned by [getWall].
static List<List<T>> pad<T>(
List<List<T>> mapShape, int padding, T Function() getWall) {
List<List<T>> padded = _padTop(mapShape, padding, getWall);
padded = rotateRight(padded);
padded = _padTop(padded, padding, getWall);
padded = rotateRight(padded);
padded = _padTop(padded, padding, getWall);
padded = rotateRight(padded);
padded = _padTop(padded, padding, getWall);
padded = rotateRight(padded);
return padded;
}
/// Pads a WALL at the top
static List<List<T>> _padTop<T>(
List<List<T>> other, int padding, T Function() getWall) {
final width = other.first.length;
final List<List<T>> mapNew = [];
mapNew.addAll(List<List<T>>.generate(padding, (index) {
return List<T>.generate(width, (index) => getWall.call());
}));
mapNew.addAll(other);
return mapNew;
}
// -----------------------------------------------------------------------
// TRIM
// -----------------------------------------------------------------------
/// Trims all outer WALLS down to a single outer wall.
static List<List<T>> trim<T>(
List<List<T>> mapShape, bool Function(T e) isOuterWall) {
List<List<T>> trimmed = _trimTopInternal(mapShape, isOuterWall);
trimmed = rotateRight(trimmed);
trimmed = _trimTopInternal(trimmed, isOuterWall);
trimmed = rotateRight(trimmed);
trimmed = _trimTopInternal(trimmed, isOuterWall);
trimmed = rotateRight(trimmed);
trimmed = _trimTopInternal(trimmed, isOuterWall);
trimmed = rotateRight(trimmed);
return trimmed;
}
/// Trims WALL tiles from the top of the other elements, leaves ony one WALL.
static List<List<T>> _trimTopInternal<T>(
List<List<T>> other, bool Function(T e) isOuterWall) {
final List<List<T>> rows = [];
int trimTop = 0;
for (int row = 0; row < other.length; row++) {
final List<T> line = other.elementAt(row);
final isOnlyWallsInternal =
line.where((T e) => isOuterWall.call(e)).length == line.length;
if (isOnlyWallsInternal == false) {
break;
}
trimTop = row;
}
rows.addAll(other.getRange(trimTop, other.length));
return rows;
}
// -----------------------------------------------------------------------
// COPY
// -----------------------------------------------------------------------
/// Copies the given coordinates.
///
/// `x1` and `y1` are inclusive.
static List<List<T>> copy<T>(
List<List<T>> target, int x0, int y0, int x1, int y1) {
assert(x0 >= 0 && x1 < target.first.length);
assert(y0 >= 0 && y1 < target.length);
final List<List<T>> copy = [];
for (int y = y0; y <= y1; y++) {
final List<T> copyRow = [];
for (int x = x0; x <= x1; x++) {
copyRow.add(target[y][x]);
}
copy.add(copyRow);
}
return copy;
}
// -----------------------------------------------------------------------
// CENTER TILE
// -----------------------------------------------------------------------
/// Returns the center tile of shapes with uneven `width` and `height`.
///
/// Undefined for other shapes.
///
/// Will throw if width or height are 1.
static (Point<int> position, T tile) getCenterTile<T>(
int x, int y, List<List<T>> target) {
final int targetHeight = target.length;
final int targetWidth = target.first.length;
if (targetHeight == 1 || targetWidth == 1) {
throw Exception('Not implemented');
}
final y0 = (targetHeight / 2).ceil() - 1;
final x0 = (targetWidth / 2).ceil() - 1;
final tile = target[y0][x0];
return (Point<int>(x + x0, y + y0), tile);
}
// -----------------------------------------------------------------------
// FILTER
// -----------------------------------------------------------------------
static List<(Point<int> position, T tile)> filter<T>(
List<List<T>> target, bool Function(T tile) doFilter) {
final List<(Point<int> position, T tile)> ret = [];
final int height = target.length;
final int width = target.first.length;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (doFilter.call(target[y][x])) {
ret.add((Point<int>(x, y), target[y][x]));
}
}
}
return ret;
}
}