Difference between revisions of "Camera View, Rotate, Trim and Pad a Map in Dart"
Jump to navigation
Jump to search
(initial) |
(added generic types) |
||
Line 23: | Line 23: | ||
map.trim().split('\n').map((row) => row.split('')).toList(); | map.trim().split('\n').map((row) => row.split('')).toList(); | ||
List<List< | List<List<String>> result = Transform.rotateRight<String>(mapList); | ||
String mapString = result.map((e) => e.join('')).join('\n'); | String mapString = result.map((e) => e.join('')).join('\n'); | ||
Line 59: | Line 59: | ||
String getWall() => '#'; | String getWall() => '#'; | ||
List<List< | List<List<String>> result = Transform.pad<String>(mapList, 2, getWall); | ||
String mapString = result.map((e) => e.join('')).join('\n'); | String mapString = result.map((e) => e.join('')).join('\n'); | ||
Line 101: | Line 101: | ||
bool isOuterWall(dynamic str) => str == '#'; | bool isOuterWall(dynamic str) => str == '#'; | ||
List<List< | List<List<String>> result = Transform.trim<String>(mapListPadded, isOuterWall); | ||
String mapString = result.map((e) => e.join('')).join('\n'); | String mapString = result.map((e) => e.join('')).join('\n'); | ||
Line 134: | Line 134: | ||
map.trim().split('\n').map((row) => row.split('')).toList(); | map.trim().split('\n').map((row) => row.split('')).toList(); | ||
List<List< | List<List<String>> result = Transform.copy<String>(mapList, 0, 0, 5, 5); | ||
String mapString = result.map((e) => e.join('')).join('\n'); | String mapString = result.map((e) => e.join('')).join('\n'); | ||
Line 151: | Line 151: | ||
<syntaxhighlight lang="dart" line> | <syntaxhighlight lang="dart" line> | ||
import 'dart:math'; | |||
/// Allows for rotating, padding and trimming a list-of-lists. | |||
class Transform { | class Transform { | ||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||
Line 157: | Line 160: | ||
/// Rotates to the right. | /// Rotates to the right. | ||
static List<List< | static List<List<T>> rotateRight<T>(List<List<T>> target) { | ||
List<List< | List<List<T>> rotatedList = []; | ||
final width = target.first.length; | final width = target.first.length; | ||
final height = target.length - 1; | final height = target.length - 1; | ||
for (int column = 0; column < width; column++) { | for (int column = 0; column < width; column++) { | ||
final List< | final List<T> lineNew = []; | ||
for (int row = height; row >= 0; row--) { | for (int row = height; row >= 0; row--) { | ||
Line 180: | Line 183: | ||
/// Pads with WALL tiles returned by [getWall]. | /// Pads with WALL tiles returned by [getWall]. | ||
static List<List< | static List<List<T>> pad<T>( | ||
List<List< | List<List<T>> mapShape, int padding, T Function() getWall) { | ||
List<List< | List<List<T>> padded = _padTop(mapShape, padding, getWall); | ||
padded = rotateRight(padded); | padded = rotateRight(padded); | ||
padded = _padTop(padded, padding, getWall); | padded = _padTop(padded, padding, getWall); | ||
Line 195: | Line 199: | ||
/// Pads a WALL at the top | /// Pads a WALL at the top | ||
static List<List< | static List<List<T>> _padTop<T>( | ||
List<List< | List<List<T>> other, int padding, T Function() getWall) { | ||
final width = other.first.length; | final width = other.first.length; | ||
final List<List< | final List<List<T>> mapNew = []; | ||
mapNew.addAll(List<List< | mapNew.addAll(List<List<T>>.generate(padding, (index) { | ||
return List< | return List<T>.generate(width, (index) => getWall.call()); | ||
})); | })); | ||
mapNew.addAll(other); | mapNew.addAll(other); | ||
Line 213: | Line 217: | ||
/// Trims all outer WALLS down to a single outer wall. | /// Trims all outer WALLS down to a single outer wall. | ||
static List<List< | static List<List<T>> trim<T>( | ||
List<List< | List<List<T>> mapShape, bool Function(T e) isOuterWall) { | ||
List<List< | List<List<T>> trimmed = _trimTopInternal(mapShape, isOuterWall); | ||
trimmed = rotateRight(trimmed); | trimmed = rotateRight(trimmed); | ||
trimmed = _trimTopInternal(trimmed, isOuterWall); | trimmed = _trimTopInternal(trimmed, isOuterWall); | ||
Line 228: | Line 232: | ||
/// Trims WALL tiles from the top of the other elements, leaves ony one WALL. | /// Trims WALL tiles from the top of the other elements, leaves ony one WALL. | ||
static List<List< | static List<List<T>> _trimTopInternal<T>( | ||
List<List< | List<List<T>> other, bool Function(T e) isOuterWall) { | ||
final List<List< | final List<List<T>> rows = []; | ||
int trimTop = 0; | int trimTop = 0; | ||
for (int row = 0; row < other.length; row++) { | for (int row = 0; row < other.length; row++) { | ||
final List< | final List<T> line = other.elementAt(row); | ||
final isOnlyWallsInternal = | final isOnlyWallsInternal = | ||
line.where(( | line.where((T e) => isOuterWall.call(e)).length == line.length; | ||
if (isOnlyWallsInternal == false) { | if (isOnlyWallsInternal == false) { | ||
Line 256: | Line 260: | ||
/// | /// | ||
/// `x1` and `y1` are inclusive. | /// `x1` and `y1` are inclusive. | ||
static List<List< | static List<List<T>> copy<T>( | ||
List<List< | List<List<T>> target, int x0, int y0, int x1, int y1) { | ||
assert(x0 >= 0 && x1 < target.first.length); | assert(x0 >= 0 && x1 < target.first.length); | ||
assert(y0 >= 0 && y1 < target.length); | assert(y0 >= 0 && y1 < target.length); | ||
final List<List< | final List<List<T>> copy = []; | ||
for (int y = y0; y <= y1; y++) { | for (int y = y0; y <= y1; y++) { | ||
final List< | final List<T> copyRow = []; | ||
for (int x = x0; x <= x1; x++) { | for (int x = x0; x <= x1; x++) { | ||
copyRow.add(target[y][x]); | copyRow.add(target[y][x]); | ||
Line 272: | Line 276: | ||
return copy; | 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; | |||
} | } | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> |
Revision as of 09:41, 19 October 2023
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;
}
}