/* * -------------------------------------------------------------------------- * $Id: expand2x.c 11578 2009-02-23 22:02:27Z lalo $ * * ALGORITHM * * ... (TBW) */ /** * @file * Expands a layout by 2x in each dimension. * * H. S. Teoh */ #include /* just in case */ #include /* use compiler to do sanity check */ /* PROTOTYPES */ static void expand_misc(char **newlayout, int i, int j, char **layout); static void expand_wall(char **newlayout, int i, int j, char **layout, int xsize, int ysize); static void expand_door(char **newlayout, int i, int j, char **layout, int xsize, int ysize); /* FUNCTIONS */ /** * Expands the layout be a factor 2. Doors and walls are taken care of. * @param layout * layout to expand. Memory is free()d at the end, so pointer becomes invalid. * @param xsize * @param ysize * layout size. * @return * new layout. Must be free()d by caller. */ char **expand2x(char **layout, int xsize, int ysize) { int i, j; int nxsize = xsize*2-1; int nysize = ysize*2-1; /* Allocate new layout */ char **newlayout = (char **)calloc(sizeof(char *), nxsize); for (i = 0; i < nxsize; i++) { newlayout[i] = (char *)calloc(sizeof(char), nysize); } for (i = 0; i < xsize; i++) { for (j = 0; j < ysize; j++) { switch (layout[i][j]) { case '#': expand_wall(newlayout, i, j, layout, xsize, ysize); break; case 'D': expand_door(newlayout, i, j, layout, xsize, ysize); break; default: expand_misc(newlayout, i, j, layout); } } } /* Dump old layout */ for (i = 0; i < xsize; i++) { free(layout[i]); } free(layout); return newlayout; } /** * Copy the old tile X into the new one at location (i*2, j*2) and * fill up the rest of the 2x2 result with 0: * X ---> X 0 * 0 0 * @param newlayout * map layout. * @param i * @param j * spot to expand. * @param layout * map layout. */ static void expand_misc(char **newlayout, int i, int j, char **layout) { newlayout[i*2][j*2] = layout[i][j]; /* (Note: no need to reset rest of 2x2 area to \0 because calloc does that * for us.) */ } /** * Returns a bitmap that represents which squares on the right and bottom * edges of a square (i,j) match the given character. * * @param ch * character to look for. * @param layout * map. * @param i * @param j * spot where to look. * @param xsize * @param ysize * layout size. * @return * combination of the following values: * - 1 means match on (i+1, j). * - 2 means match on (i, j+1). * - 4 means match on (i+1, j+1). */ static int calc_pattern(char ch, char **layout, int i, int j, int xsize, int ysize) { int pattern = 0; if (i+1 < xsize && layout[i+1][j] == ch) pattern |= 1; if (j+1 < ysize) { if (layout[i][j+1] == ch) pattern |= 2; if (i+1 < xsize && layout[i+1][j+1] == ch) pattern |= 4; } return pattern; } /** * Expand a wall. This function will try to sensibly connect the resulting * wall to adjacent wall squares, so that the result won't have disconnected * walls. * @param newlayout * map layout. * @param i * @param j * coordinates of wall to expand in non expanded layout. * @param layout * current (non expanded) layout. * @param xsize * @param ysize * sizes of layout. */ static void expand_wall(char **newlayout, int i, int j, char **layout, int xsize, int ysize) { int wall_pattern = calc_pattern('#', layout, i, j, xsize, ysize); int door_pattern = calc_pattern('D', layout, i, j, xsize, ysize); int both_pattern = wall_pattern|door_pattern; newlayout[i*2][j*2] = '#'; if (i+1 < xsize) { if (both_pattern&1) { /* join walls/doors to the right */ newlayout[i*2+1][j*2] = layout[i+1][j]; } } if (j+1 < ysize) { if (both_pattern&2) { /* join walls/doors to the bottom */ newlayout[i*2][j*2+1] = layout[i][j+1]; } if (wall_pattern == 7) { /* if orig layout is a 2x2 wall block, * we fill the result with walls. */ newlayout[i*2+1][j*2+1] = '#'; } } } /** * Expand a door. This function will try to sensibly connect doors so that they meet up with * adjacent walls. Note that it will also presumptuously delete (ignore) doors * that it doesn't know how to correctly expand. * @param newlayout * expanded layout. * @param i * @param j * coordinates of door to expand in non expanded layout. * @param layout * non expanded layout. * @param xsize * @param ysize * size of non expanded layout. */ static void expand_door(char **newlayout, int i, int j, char **layout, int xsize, int ysize) { int wall_pattern = calc_pattern('#', layout, i, j, xsize, ysize); int door_pattern = calc_pattern('D', layout, i, j, xsize, ysize); int join_pattern; /* Doors "like" to connect to walls more than other doors. If there is * a wall and another door, this door will connect to the wall and * disconnect from the other door. */ if (wall_pattern&3) { join_pattern = wall_pattern; } else { join_pattern = door_pattern; } newlayout[i*2][j*2] = 'D'; if (i+1 < xsize) { if (join_pattern&1) { /* there is a door/wall to the right */ newlayout[i*2+1][j*2] = 'D'; } } if (j+1 < ysize) { if (join_pattern&2) { /* there is a door/wall below */ newlayout[i*2][j*2+1] = 'D'; } } }