001package squidpony.squidgrid.mapping; 002 003import squidpony.squidmath.GreasedRegion; 004 005/** 006 * Tools for constructing patterns using box-drawing characters. 007 * <br> 008 * Created by Tommy Ettinger on 1/6/2018. 009 */ 010public class LineKit { 011 public static final char[] lightAlt = " ╴╵┘╶─└┴╷┐│┤┌┬├┼".toCharArray(), 012 heavyAlt = " ╸╹┛╺━┗┻╻┓┃┫┏┳┣╋".toCharArray(), 013 light = " ─│┘──└┴│┐│┤┌┬├┼".toCharArray(), 014 heavy = " ━┃┛━━┗┻┃┓┃┫┏┳┣╋".toCharArray(); 015 // 0123456789ABCDEF 016 017 /** 018 * A constant that represents the encoded pattern for a 4x4 square with all lines possible except those that 019 * would extend to touch cells adjacent to the 4x4 area. Meant to restrict cells within the square area by using 020 * bitwise AND with an existing encoded pattern as another long, as with {@code LineKit.interiorSquare & encoded}. 021 * If you limit the area to the square with this, you may sometimes want to add a border, and for that you can use 022 * {@link #exteriorSquare} and bitwise OR that with the restricted area. 023 * <br>This looks like: 024 * <pre> 025 * "┌┬┬┐" 026 * "├┼┼┤" 027 * "├┼┼┤" 028 * "└┴┴┘" 029 * </pre> 030 */ 031 public final static long interiorSquare = 0x3776BFFEBFFE9DDCL, 032 /** 033 * A constant that represents the encoded pattern for a 4x4 square with only the lines along the border. Meant to 034 * either restrict cells to the border by using bitwise AND with an existing encoded pattern as another long, as 035 * with {@code LineKit.exteriorSquare & encoded}, or to add a border to an existing pattern with bitwise OR, as with 036 * {@code LineKit.exteriorSquare | encoded}. 037 * <br>This looks like: 038 * <pre> 039 * "┌──┐" 040 * "│ │" 041 * "│ │" 042 * "└──┘" 043 * </pre> 044 */ 045 exteriorSquare = 0x3556A00AA00A955CL, 046 /** 047 * A constant that represents the encoded pattern for a 4x4 plus pattern with only the lines along the border. This 048 * pattern has no lines in the corners of the 4x4 area, but has some lines in all other cells, though none that 049 * would touch cells adjacent to this 4x4 area. Meant to restrict cells to the border by using bitwise AND with an 050 * existing encoded pattern as another long, as with {@code LineKit.interiorPlus & encoded}. 051 * <br>This looks like: 052 * <pre> 053 * " ┌┐ " 054 * "┌┼┼┐" 055 * "└┼┼┘" 056 * " └┘ " 057 * </pre> 058 */ 059 interiorPlus = 0x03603FF69FFC09C0L, 060 /** 061 * A constant that represents the encoded pattern for a 4x4 plus pattern with only the lines along the border. This 062 * pattern has no lines in the corners of the 4x4 area, but has some lines in all other cells, though none that 063 * would touch cells adjacent to this 4x4 area. Meant to either restrict cells to the border by using bitwise AND 064 * with an existing encoded pattern as another long, as with {@code LineKit.exteriorPlus & encoded}, or to add a 065 * border to an existing pattern with bitwise OR, as with {@code LineKit.exteriorPlus | encoded}. 066 * <br>This looks like: 067 * <pre> 068 * " ┌┐ " 069 * "┌┘└┐" 070 * "└┐┌┘" 071 * " └┘ " 072 * </pre> 073 */ 074 exteriorPlus = 0x03603C96963C09C0L, 075 /** 076 * A constant that represents the encoded pattern for the upper left 4x4 area of an 8x8 square. No lines will touch 077 * the upper or left borders, but they do extend into the lower and right borders. This is expected to be flipped 078 * using {@link #flipHorizontal4x4(long)} and/or {@link #flipVertical4x4(long)} to make the other corners. If middle 079 * pieces are wanted that touch everything but the upper border, you can use 080 * {@code (LineKit.interiorSquareLarge | LineKit.flipHorizontal4x4(LineKit.interiorSquareLarge))}. If you want it to 081 * touch everything but the left border, you can use 082 * {@code (LineKit.interiorSquareLarge | LineKit.flipVertical4x4(LineKit.interiorSquareLarge))}. 083 * <br>This looks like: 084 * <pre> 085 * "┌┬┬┬" 086 * "├┼┼┼" 087 * "├┼┼┼" 088 * "├┼┼┼" 089 * </pre> 090 * @see #interiorSquare The docs here cover how to use this as a mask with bitwise AND. 091 */ 092 interiorSquareLarge = 0xFFFEFFFEFFFEDDDCL, 093 /** 094 * A constant that represents the encoded pattern for the upper left 4x4 area of an 8x8 square border. No lines will 095 * touch the upper or left borders, but they do extend into the lower and right borders. The entirety of this 096 * pattern is one right-angle. This is expected to be flipped using {@link #flipHorizontal4x4(long)} and/or 097 * {@link #flipVertical4x4(long)} to make the other corners. 098 * <br>This looks like: 099 * <pre> 100 * "┌───" 101 * "│ " 102 * "│ " 103 * "│ " 104 * </pre> 105 * @see #exteriorSquare The docs here cover how to use this as a mask with bitwise AND or to insert it with OR. 106 */ 107 exteriorSquareLarge = 0x000A000A000A555CL, 108 /** 109 * A constant that represents the encoded pattern for the upper left 4x4 area of a 6x6 square centered in an 8x8 110 * space. A 3x3 square will be filled of the 4x4 area this represents. No lines will touch the upper or left 111 * borders, but they do extend into the lower and right borders. This is expected to be flipped using 112 * {@link #flipHorizontal4x4(long)} and/or {@link #flipVertical4x4(long)} to make other corners. 113 * <br>This looks like: 114 * <pre> 115 * " " 116 * " ┌┬┬" 117 * " ├┼┼" 118 * " ├┼┼" 119 * </pre> 120 * @see #interiorSquare The docs here cover how to use this as a mask with bitwise AND. 121 * 122 */ 123 shallowInteriorSquareLarge = 0xFFE0FFE0DDC00000L, 124 /** 125 * A constant that represents the encoded pattern for the upper left 4x4 area of a 6x6 square border centered in an 126 * 8x8 space. This consists of a 3-cell-long vertical line and a 3-cell-long horizontal line. No lines will touch 127 * the upper or left borders, but they do extend into the lower and right borders. The entirety of this 128 * pattern is one right-angle. This is expected to be flipped using {@link #flipHorizontal4x4(long)} and/or 129 * {@link #flipVertical4x4(long)} to make the other corners. 130 * <br>This looks like: 131 * <pre> 132 * " " 133 * " ┌──" 134 * " │ " 135 * " │ " 136 * </pre> 137 * @see #exteriorSquare The docs here cover how to use this as a mask with bitwise AND or to insert it with OR. 138 */ 139 shallowExteriorSquareLarge = 0x00A000A055C00000L, 140 /** 141 * A constant that represents the encoded pattern for the upper left 4x4 area of a 4x4 square centered in an 8x8 142 * space. A 2x2 square will be filled of the 4x4 area this represents. No lines will touch the upper or left 143 * borders, but they do extend into the lower and right borders. This is expected to be flipped using 144 * {@link #flipHorizontal4x4(long)} and/or {@link #flipVertical4x4(long)} to make other corners. 145 * <br>This looks like: 146 * <pre> 147 * " " 148 * " " 149 * " ┌┬" 150 * " ├┼" 151 * </pre> 152 * @see #interiorSquare The docs here cover how to use this as a mask with bitwise AND. 153 */ 154 shallowerInteriorSquareLarge = 0xFE00DC0000000000L, 155 /** 156 * A constant that represents the encoded pattern for the upper left 4x4 area of a 4x4 square border centered in an 157 * 8x8 space. This consists of a 2-cell-long vertical line and a 2-cell-long horizontal line. No lines will touch 158 * the upper or left borders, but they do extend into the lower and right borders. The entirety of this 159 * pattern is one right-angle. This is expected to be flipped using {@link #flipHorizontal4x4(long)} and/or 160 * {@link #flipVertical4x4(long)} to make the other corners. 161 * <br>This looks like: 162 * <pre> 163 * " " 164 * " " 165 * " ┌─" 166 * " │ " 167 * </pre> 168 * @see #exteriorSquare The docs here cover how to use this as a mask with bitwise AND or to insert it with OR. 169 */ 170 shallowerExteriorSquareLarge = 0x0A005C0000000000L, 171 /** 172 * A constant that represents the encoded pattern for the upper left 4x4 area of an 8x8 plus shape. No lines will 173 * touch the upper or left borders, but they do extend into the lower and right borders. This pattern leaves the 174 * upper left 2x2 area blank, and touches all of the lower and right borders. This is expected to be flipped using 175 * {@link #flipHorizontal4x4(long)} and/or {@link #flipVertical4x4(long)} to make other corners. 176 * @see #interiorPlus The docs here cover how to use this as a mask with bitwise AND. 177 * <br>This looks like: 178 * <pre> 179 * " ┌┬" 180 * " ├┼" 181 * "┌┬┼┼" 182 * "├┼┼┼" 183 * </pre> 184 */ 185 interiorPlusLarge = 0xFFFEFFDCFE00DC00L, 186 /** 187 * A constant that represents the encoded pattern for the upper left 4x4 area of an 8x8 plus shape border. No lines 188 * will touch the upper or left borders, but they do extend into the lower and right borders. This pattern leaves 189 * the upper left 2x2 area blank, as well as all but one each of the bottom and right border cells. This is expected 190 * to be flipped using {@link #flipHorizontal4x4(long)} and/or {@link #flipVertical4x4(long)} to make other corners. 191 * <br>This looks like: 192 * <pre> 193 * " ┌─" 194 * " │ " 195 * "┌─┘ " 196 * "│ " 197 * </pre> 198 * @see #exteriorPlus The docs here cover how to use this as a mask with bitwise AND or to insert it with OR. 199 */ 200 exteriorPlusLarge = 0x000A035C0A005C00L, 201 /** 202 * A constant that represents the encoded pattern for the upper left 4x4 area of an 8x8 circle shape. No lines will 203 * touch the upper or left borders, but they do extend into the lower and right borders. This is expected to be 204 * flipped using {@link #flipHorizontal4x4(long)} and/or {@link #flipVertical4x4(long)} to make other corners. 205 * <br>This looks like: 206 * <pre> 207 * " ┌┬" 208 * " ┌┼┼" 209 * "┌┼┼┼" 210 * "├┼┼┼" 211 * </pre> 212 * @see #interiorPlus The docs here cover how to use this as a mask with bitwise AND. 213 */ 214 interiorCircleLarge = 0xFFFEFFFCFFC0DC00L, 215 /** 216 * A constant that represents the encoded pattern for the upper left 4x4 area of an 8x8 circular border. No lines 217 * will touch the upper or left borders, but they do extend into the lower and right borders. The entirety of this 218 * pattern is one curving line. This is expected to be flipped using {@link #flipHorizontal4x4(long)} and/or 219 * {@link #flipVertical4x4(long)} to make other corners. 220 * <br>This looks like: 221 * <pre> 222 * " ┌─" 223 * " ┌┘ " 224 * "┌┘ " 225 * "│ " 226 * </pre> 227 * @see #exteriorPlus The docs here cover how to use this as a mask with bitwise AND or to insert it with OR. 228 */ 229 exteriorCircleLarge = 0x000A003C03C05C00L, 230 /** 231 * A constant that represents the encoded pattern for the upper left 4x4 area of an 8x8 diamond shape. No lines will 232 * touch the upper or left borders, but they do extend into the lower and right borders. This pattern leaves the 233 * upper left 2x2 area blank, and touches all of the lower and right borders. This is expected to be flipped using 234 * {@link #flipHorizontal4x4(long)} and/or {@link #flipVertical4x4(long)} to make other corners. This has more of a 235 * fine angle than {@link #interiorPlusLarge}, which is otherwise similar. 236 * <br>This looks like: 237 * <pre> 238 * " ┌" 239 * " ┌┼" 240 * " ┌┼┼" 241 * "┌┼┼┼" 242 * </pre> 243 * @see #interiorPlus The docs here cover how to use this as a mask with bitwise AND. 244 */ 245 interiorDiamondLarge = 0xFFFCFFC0FC00C000L, 246 /** 247 * A constant that represents the encoded pattern for the upper left 4x4 area of an 8x8 diamond shape border. No 248 * lines will touch the upper or left borders, but they do extend into the lower and right borders. This pattern 249 * leaves the upper left 2x2 area blank, as well as all but one each of the bottom and right border cells. This is 250 * expected to be flipped using {@link #flipHorizontal4x4(long)} and/or {@link #flipVertical4x4(long)} to make other 251 * corners. This has more of a fine angle than {@link #exteriorPlusLarge}, which is otherwise similar. 252 * <br>This looks like: 253 * <pre> 254 * " ┌" 255 * " ┌┘" 256 * " ┌┘ " 257 * "┌┘ " 258 * </pre> 259 * @see #exteriorPlus The docs here cover how to use this as a mask with bitwise AND or to insert it with OR. 260 */ 261 exteriorDiamondLarge = 0x003C03C03C00C000L; 262 263 /** 264 * Produces a 4x4 2D char array by interpreting the bits of the given long as line information. Uses the box drawing 265 * chars from {@link #light}, which are compatible with most fonts. 266 * @param encoded a long, which can be random, that encodes some pattern of (typically box drawing) characters 267 * @return a 4x4 2D char array containing elements from symbols assigned based on encoded 268 */ 269 public static char[][] decode4x4(long encoded) 270 { 271 return decode4x4(encoded, light); 272 } 273 /** 274 * Produces a 4x4 2D char array by interpreting the bits of the given long as line information. Uses the given char 275 * array, which must have at least 16 elements and is usually one of {@link #light}, {@link #heavy}, 276 * {@link #lightAlt}, or {@link #heavyAlt}, with the last two usable only if using a font that supports the chars 277 * {@code ╴╵╶╷} (this is true for Iosevka and Source Code Pro, for instance, but not Inconsolata or GoMono). 278 * @param encoded a long, which can be random, that encodes some pattern of (typically box drawing) characters 279 * @param symbols a 16-element-or-larger char array; usually a constant in this class like {@link #light} 280 * @return a 4x4 2D char array containing elements from symbols assigned based on encoded 281 */ 282 public static char[][] decode4x4(long encoded, char[] symbols) 283 { 284 char[][] v = new char[4][4]; 285 for (int i = 0; i < 16; i++) { 286 v[i & 3][i >> 2] = symbols[(int) (encoded >>> (i << 2) & 15L)]; 287 } 288 return v; 289 } 290 /** 291 * Fills a 4x4 area of the given 2D char array {@code into} by interpreting the bits of the given long as line 292 * information. Uses the given char array {@code symbols}, which must have at least 16 elements and is usually one 293 * of {@link #light}, {@link #heavy}, {@link #lightAlt}, or {@link #heavyAlt}, with the last two usable only if 294 * using a font that supports the chars {@code ╴╵╶╷} (this is true for Iosevka and Source Code Pro, for instance, 295 * but not Inconsolata or GoMono). 296 * @param encoded a long, which can be random, that encodes some pattern of (typically box drawing) characters 297 * @param symbols a 16-element-or-larger char array; usually a constant in this class like {@link #light} 298 * @param into a 2D char array that will be modified in a 4x4 area 299 * @param startX the first x position to modify in into 300 * @param startY the first y position to modify in into 301 * @return into, after modification 302 */ 303 public static char[][] decodeInto4x4(long encoded, char[] symbols, char[][] into, int startX, int startY) 304 { 305 for (int i = 0; i < 16; i++) { 306 into[(i & 3) + startX][(i >> 2) + startY] = symbols[(int) (encoded >>> (i << 2) & 15L)]; 307 } 308 return into; 309 } 310 311 /** 312 * Reads a 2D char array {@code decoded}, which must be at least 4x4 in size, and returns a long that encodes the cells from 0,0 to 313 * 3,3 in a way that this class can interpret and manipulate. The 2D array {@code decoded} must contain box drawing 314 * symbols, which can be any of those from {@link #light}, {@link #heavy}, {@link #lightAlt}, or {@link #heavyAlt}. 315 * Valid chars are {@code ╴╵┘╶─└┴╷┐│┤┌┬├┼╸╹┛╺━┗┻╻┓┃┫┏┳┣╋}; any other chars will be treated as empty space. 316 * @param decoded a 2D char array that must be at least 4x4 and should usually contain box drawing characters 317 * @return a long that encodes the box drawing information in decoded so this class can manipulate it 318 */ 319 public static long encode4x4(char[][] decoded) 320 { 321 long v = 0L; 322 for (int i = 0; i < 16; i++) { 323 switch (decoded[i & 3][i >> 2]) 324 { 325 // ╴╵┘╶─└┴╷┐│┤┌┬├┼ 326 // ╸╹┛╺━┗┻╻┓┃┫┏┳┣╋ 327 //0123456789ABCDEF 328 case '─': 329 case '━': 330 v |= 5L << (i << 2); 331 break; 332 case '│': 333 case '┃': 334 v |= 10L << (i << 2); 335 break; 336 case '┘': 337 case '┛': 338 v |= 3L << (i << 2); 339 break; 340 case '└': 341 case '┗': 342 v |= 6L << (i << 2); 343 break; 344 case '┐': 345 case '┓': 346 v |= 9L << (i << 2); 347 break; 348 case '┌': 349 case '┏': 350 v |= 12L << (i << 2); 351 break; 352 case '┴': 353 case '┻': 354 v |= 7L << (i << 2); 355 break; 356 case '┤': 357 case '┫': 358 v |= 11L << (i << 2); 359 break; 360 case '┬': 361 case '┳': 362 v |= 13L << (i << 2); 363 break; 364 case '├': 365 case '┣': 366 v |= 14L << (i << 2); 367 break; 368 case '┼': 369 case '╋': 370 v |= 15L << (i << 2); 371 break; 372 case '╴': 373 case '╸': 374 v |= 1L << (i << 2); 375 break; 376 case '╵': 377 case '╹': 378 v |= 2L << (i << 2); 379 break; 380 case '╶': 381 case '╺': 382 v |= 4L << (i << 2); 383 break; 384 case '╷': 385 case '╻': 386 v |= 8L << (i << 2); 387 break; 388 } 389 } 390 return v; 391 } 392 393 /** 394 * Makes a variant on the given encoded 4x4 pattern so the left side is flipped to the right side and vice versa. 395 * @param encoded an encoded pattern long that represents a 4x4 area 396 * @return a different encoded pattern long that represents the argument flipped left-to-right 397 */ 398 public static long flipHorizontal4x4(long encoded) 399 { 400 long v = 0L; 401 for (int i = 0, i4 = 0; i < 16; i++, i4 += 4) { 402 v |= ((encoded >>> i4 & 10L) | ((encoded >>> i4 & 1) << 2L) | ((encoded >>> i4 & 4L) >>> 2)) << (i + 3 - ((i & 3) << 1) << 2); 403 } 404 return v; 405 } 406 /** 407 * Makes a variant on the given encoded 4x4 pattern so the top side is flipped to the bottom side and vice versa. 408 * @param encoded an encoded pattern long that represents a 4x4 area 409 * @return a different encoded pattern long that represents the argument flipped top-to-bottom 410 */ 411 public static long flipVertical4x4(long encoded) 412 { 413 long v = 0L; 414 for (int i = 0, i4 = 0; i < 16; i++, i4 += 4) { 415 v |= ((encoded >>> i4 & 5L) | ((encoded >>> i4 & 2L) << 2) | ((encoded >>> i4 & 8L) >>> 2)) << (i + 12 - ((i >> 2) << 3) << 2); 416 } 417 return v; 418 } 419 420 /** 421 * Makes a variant on the given encoded 4x4 pattern so the x and y axes are interchanged, making the top side become 422 * the left side and vice versa, while the bottom side becomes the right side and vice versa. 423 * @param encoded an encoded pattern long that represents a 4x4 area 424 * @return a different encoded pattern long that represents the argument transposed top-to-left and bottom-to-right 425 */ 426 public static long transpose4x4(long encoded) 427 { 428 long v = 0L; 429 for (int i4 = 0; i4 < 64; i4 += 4) { 430 v |= (((encoded >>> i4 & 5L) << 1) | ((encoded >>> i4 & 10L) >>> 1)) << ((i4 >>> 2 & 12L) | ((i4 & 12L) << 2)); 431 } 432 return v; 433 } 434 /** 435 * Makes a variant on the given encoded 4x4 pattern so the lines are rotated 90 degrees clockwise, changing their 436 * positions as well as what chars they will decode to. This can be called twice to get a 180 degree rotation, but 437 * {@link #rotateCounterclockwise(long)} should be used for a 270 degree rotation. 438 * @param encoded an encoded pattern long that represents a 4x4 area 439 * @return a different encoded pattern long that represents the argument rotated 90 degrees clockwise 440 */ 441 public static long rotateClockwise(long encoded) 442 { 443 // this is functionally equivalent to, but faster than, the following: 444 // return flipHorizontal4x4(transpose4x4(encoded)); 445 long v = 0L; 446 for (int i4 = 0; i4 < 64; i4 += 4) { 447 v |= (((encoded >>> i4 & 7L) << 1) | ((encoded >>> i4 & 8L) >>> 3)) << ((~i4 >>> 2 & 12L) | ((i4 & 12L) << 2)); 448 } 449 return v; 450 } 451 /** 452 * Makes a variant on the given encoded 4x4 pattern so the lines are rotated 90 degrees counterclockwise, changing 453 * their positions as well as what chars they will decode to. This can be called twice to get a 180 degree rotation, 454 * but {@link #rotateClockwise(long)} should be used for a 270 degree rotation. 455 * @param encoded an encoded pattern long that represents a 4x4 area 456 * @return a different encoded pattern long that represents the argument rotated 90 degrees counterclockwise 457 */ 458 public static long rotateCounterclockwise(long encoded) 459 { 460 // this is functionally equivalent to, but faster than, the following: 461 // return flipVertical4x4(transpose4x4(encoded)); 462 long v = 0L; 463 for (int i4 = 0; i4 < 64; i4 += 4) { 464 v |= ((encoded >>> (i4 + 1) & 7L) | ((encoded >>> i4 & 1L) << 3)) << ((i4 >>> 2 & 12L) | ((~i4 & 12L) << 2)); 465 } 466 return v; 467 } 468 469 /** Adjusts an existing map that uses box-drawing characters so non-visible line segments aren't rendered. 470 * Takes a map that was produced using {@link DungeonUtility#hashesToLines(char[][])} and a GreasedRegion that 471 * stores already-seen cells, and writes an altered version of the 2D char array {@code map} to {@code writeInto}, 472 * leaving non-box-drawing chars unchanged. This method modifies writeInto in-place, and also returns it after those 473 * changesare made. The way this works is explained well with an example: if the player is north of a T-junction 474 * wall, '┬', then unless he has already explored the area south of his position, the bottom segment of the wall 475 * isn't visible to him, and so '─' should be rendered instead of '┬'. If a cell has already been seen, it is 476 * considered still visible for the purpose of calculating shown segments (it won't change once you leave an area). 477 * @param map a 2D char array that should have been produced by {@link DungeonUtility#hashesToLines(char[][])} 478 * @param seen a GreasedRegion where "on" cells are visible now or were visible in the past 479 * @param writeInto a 2D char array that must have at least the dimensions of map; will be modified 480 * @return writeInto, after modifications 481 */ 482 public static char[][] pruneLines(char[][] map, GreasedRegion seen, char[][] writeInto) 483 { 484 return pruneLines(map, seen, light, writeInto); 485 } 486 487 /** Adjusts an existing map that uses box-drawing characters so non-visible line segments aren't rendered. 488 * Takes a map that was produced using {@link DungeonUtility#hashesToLines(char[][])} a GreasedRegion that stores 489 * already-seen cells, an optional char array that refers to a line drawing style constant in this class (defaults 490 * to {@link #light}, and writes an altered version of the 2D char array {@code map} to {@code writeInto}, leaving 491 * non-box-drawing chars unchanged. This method modifies writeInto in-place, and also returns it after those changes 492 * are made. The way this works is explained well with an example: if the player is north of a T-junction wall, '┬', 493 * then unless he has already explored the area south of his position, the bottom segment of the wall isn't visible 494 * to him, and so '─' should be rendered instead of '┬'. If a cell has already been seen, it is considered still 495 * visible for the purpose of calculating shown segments (it won't change once you leave an area). 496 * @param map a 2D char array that should have been produced by {@link DungeonUtility#hashesToLines(char[][])} 497 * @param seen a GreasedRegion where "on" cells are visible now or were visible in the past 498 * @param symbols a char array that should be {@link #light} or {@link #heavy} unless you know your font supports 499 * the chars "╴╵╶╷", in which case you can use {@link #lightAlt}, or the heavy-weight versions of 500 * those chars, in which case you can use {@link #heavyAlt} 501 * @param writeInto a 2D char array that must have at least the dimensions of map; will be modified 502 * @return writeInto, after modifications 503 */ 504 public static char[][] pruneLines(char[][] map, GreasedRegion seen, char[] symbols, char[][] writeInto) 505 { 506 final int width = map.length, height = map[0].length; 507 int mask; 508 for (int x = 0; x < width; x++) { 509 for (int y = 0; y < height; y++) { 510 if(seen.contains(x, y)) 511 { 512 mask = 15; 513 if(!seen.contains(x-1, y)) 514 mask ^= 1; 515 if(!seen.contains(x+1, y)) 516 mask ^= 4; 517 if(!seen.contains(x, y-1)) 518 mask ^= 2; 519 if(!seen.contains(x, y+1)) 520 mask ^= 8; 521 switch (map[x][y]) { 522 case '─': 523 case '━': 524 writeInto[x][y] = symbols[5 & mask]; 525 break; 526 case '│': 527 case '┃': 528 writeInto[x][y] = symbols[10 & mask]; 529 break; 530 case '┘': 531 case '┛': 532 writeInto[x][y] = symbols[3 & mask]; 533 break; 534 case '└': 535 case '┗': 536 writeInto[x][y] = symbols[6 & mask]; 537 break; 538 case '┐': 539 case '┓': 540 writeInto[x][y] = symbols[9 & mask]; 541 break; 542 case '┌': 543 case '┏': 544 writeInto[x][y] = symbols[12 & mask]; 545 break; 546 case '┴': 547 case '┻': 548 writeInto[x][y] = symbols[7 & mask]; 549 break; 550 case '┤': 551 case '┫': 552 writeInto[x][y] = symbols[11 & mask]; 553 break; 554 case '┬': 555 case '┳': 556 writeInto[x][y] = symbols[13 & mask]; 557 break; 558 case '├': 559 case '┣': 560 writeInto[x][y] = symbols[14 & mask]; 561 break; 562 case '┼': 563 case '╋': 564 writeInto[x][y] = symbols[15 & mask]; 565 break; 566 case '╴': 567 case '╸': 568 writeInto[x][y] = symbols[1 & mask]; 569 break; 570 case '╵': 571 case '╹': 572 writeInto[x][y] = symbols[2 & mask]; 573 break; 574 case '╶': 575 case '╺': 576 writeInto[x][y] = symbols[4 & mask]; 577 break; 578 case '╷': 579 case '╻': 580 writeInto[x][y] = symbols[8 & mask]; 581 break; 582 } 583 } 584 } 585 } 586 return writeInto; 587 } 588 589// public static void main(String[] args) 590// { 591// System.out.printf("interiorSquare = 0x%016XL\n", LineKit.encode4x4(DungeonUtility.transposeLines(new char[][] 592// { 593// {'┌', '┬', '┬', '┐'}, 594// {'├', '┼', '┼', '┤'}, 595// {'├', '┼', '┼', '┤'}, 596// {'└', '┴', '┴', '┘'}, 597// }))); 598// System.out.printf("exteriorSquare = 0x%016XL\n", LineKit.encode4x4(DungeonUtility.transposeLines(new char[][] 599// { 600// {'┌', '─', '─', '┐'}, 601// {'│', ' ', ' ', '│'}, 602// {'│', ' ', ' ', '│'}, 603// {'└', '─', '─', '┘'}, 604// }))); 605// System.out.printf("interiorPlus = 0x%016XL\n", LineKit.encode4x4(DungeonUtility.transposeLines(new char[][] 606// { 607// {' ', '┌', '┐', ' '}, 608// {'┌', '┼', '┼', '┐'}, 609// {'└', '┼', '┼', '┘'}, 610// {' ', '└', '┘', ' '}, 611// }))); 612// System.out.printf("exteriorPlus = 0x%016XL\n", LineKit.encode4x4(DungeonUtility.transposeLines(new char[][] 613// { 614// {' ', '┌', '┐', ' '}, 615// {'┌', '┘', '└', '┐'}, 616// {'└', '┐', '┌', '┘'}, 617// {' ', '└', '┘', ' '}, 618// }))); 619// System.out.printf("interiorSquareLarge = 0x%016XL\n", LineKit.encode4x4(DungeonUtility.transposeLines(new char[][] 620// { 621// {'┌', '┬', '┬', '┬'}, 622// {'├', '┼', '┼', '┼'}, 623// {'├', '┼', '┼', '┼'}, 624// {'├', '┼', '┼', '┼'}, 625// }))); 626// System.out.printf("exteriorSquareLarge = 0x%016XL\n", LineKit.encode4x4(DungeonUtility.transposeLines(new char[][] 627// { 628// {'┌', '─', '─', '─'}, 629// {'│', ' ', ' ', ' '}, 630// {'│', ' ', ' ', ' '}, 631// {'│', ' ', ' ', ' '}, 632// }))); 633// System.out.printf("interiorPlusLarge = 0x%016XL\n", LineKit.encode4x4(DungeonUtility.transposeLines(new char[][] 634// { 635// {' ', ' ', '┌', '┬'}, 636// {' ', ' ', '├', '┼'}, 637// {'┌', '┬', '┼', '┼'}, 638// {'├', '┼', '┼', '┼'}, 639// }))); 640// System.out.printf("exteriorPlusLarge = 0x%016XL\n", LineKit.encode4x4(DungeonUtility.transposeLines(new char[][] 641// { 642// {' ', ' ', '┌', '─'}, 643// {' ', ' ', '│', ' '}, 644// {'┌', '─', '┘', ' '}, 645// {'│', ' ', ' ', ' '}, 646// }))); 647// System.out.printf("interiorCircleLarge = 0x%016XL\n", LineKit.encode4x4(DungeonUtility.transposeLines(new char[][] 648// { 649// {' ', ' ', '┌', '┬'}, 650// {' ', '┌', '┼', '┼'}, 651// {'┌', '┼', '┼', '┼'}, 652// {'├', '┼', '┼', '┼'}, 653// }))); 654// System.out.printf("exteriorCircleLarge = 0x%016XL\n", LineKit.encode4x4(DungeonUtility.transposeLines(new char[][] 655// { 656// {' ', ' ', '┌', '─'}, 657// {' ', '┌', '┘', ' '}, 658// {'┌', '┘', ' ', ' '}, 659// {'│', ' ', ' ', ' '}, 660// }))); 661// System.out.printf("interiorDiamondLarge = 0x%016XL\n", LineKit.encode4x4(DungeonUtility.transposeLines(new char[][] 662// { 663// {' ', ' ', ' ', '┌'}, 664// {' ', ' ', '┌', '┼'}, 665// {' ', '┌', '┼', '┼'}, 666// {'┌', '┼', '┼', '┼'}, 667// }))); 668// System.out.printf("exteriorDiamondLarge = 0x%016XL\n", LineKit.encode4x4(DungeonUtility.transposeLines(new char[][] 669// { 670// {' ', ' ', ' ', '┌'}, 671// {' ', ' ', '┌', '┘'}, 672// {' ', '┌', '┘', ' '}, 673// {'┌', '┘', ' ', ' '}, 674// }))); 675// System.out.printf("shallowInteriorSquareLarge = 0x%016XL\n", LineKit.encode4x4(DungeonUtility.transposeLines(new char[][] 676// { 677// {' ', ' ', ' ', ' '}, 678// {' ', '┌', '┬', '┬'}, 679// {' ', '├', '┼', '┼'}, 680// {' ', '├', '┼', '┼'}, 681// }))); 682// System.out.printf("shallowExteriorSquareLarge = 0x%016XL\n", LineKit.encode4x4(DungeonUtility.transposeLines(new char[][] 683// { 684// {' ', ' ', ' ', ' '}, 685// {' ', '┌', '─', '─'}, 686// {' ', '│', ' ', ' '}, 687// {' ', '│', ' ', ' '}, 688// }))); 689// System.out.printf("shallowerInteriorSquareLarge = 0x%016XL\n", LineKit.encode4x4(DungeonUtility.transposeLines(new char[][] 690// { 691// {' ', ' ', ' ', ' '}, 692// {' ', ' ', ' ', ' '}, 693// {' ', ' ', '┌', '┬'}, 694// {' ', ' ', '├', '┼'}, 695// }))); 696// System.out.printf("shallowerExteriorSquareLarge = 0x%016XL\n", LineKit.encode4x4(DungeonUtility.transposeLines(new char[][] 697// { 698// {' ', ' ', ' ', ' '}, 699// {' ', ' ', ' ', ' '}, 700// {' ', ' ', '┌', '─'}, 701// {' ', ' ', '│', ' '}, 702// }))); 703// } 704}