public DenseGrid Flip_WE()
    {
        DenseGrid new_grid = new DenseGrid(this.width, this.height, 0);
        DenseGrid.BlitFromAOntoB(this, new_grid, 0, 0);

        // Starting with the outmost and working towards center,
        // swap the contents of each paired vertical strip.
        for (int W_xx = 0; W_xx < new_grid.center_x(); W_xx++)  // VERIFY: is this correct for even widths?
            {
            int E_xx = new_grid.max_x() - W_xx;
            for (int yy = 0; yy <= new_grid.max_y(); yy++) {
                int W_value = contents_at_XY(W_xx, yy);
                int E_value = contents_at_XY(E_xx, yy);
                new_grid.set_contents_at_XY(W_xx, yy, E_value);
                new_grid.set_contents_at_XY(E_xx, yy, W_value);
            } // for(yy)
        } // for(xx)
        return new_grid;
    }
    public static DenseGrid BlitFromAOntoB(DenseGrid from_A, int from_x, int from_y,
                                           DenseGrid to_B,   int to_x,   int to_y,
                                           int blit_width,   int blit_height)
    {
        // Blit from A onto B, with as many method arguments as possible.
        if (from_A == null)
            return null;
        if (to_B == null)
            return null;

        // The from_x,y are relative to the origin of from_A.
        if (from_x < from_A.min_x())
            return null; // At least somewhat off-edge to the left
        if (from_x > from_A.max_x())
            return null; // Entirely to the right
        if (from_y < from_A.min_y())
            return null; // At least somewhat off-edge above
        if (from_y > from_A.max_y())
            return null; // Entirely below

        // The to_x,y are relative to the origin of to_B.
        if (to_x + blit_width < to_B.min_x())
            return null; // Entirely to the left
        if (to_x > to_B.max_x())
            return null; // Entirely to the right
        if (to_y + blit_height < to_B.min_y())
            return null; // Entirely above
        if (to_y > to_B.max_y())
            return null; // Entirely below

        // The blit width/height are clipped to avoid needless looping.
        // Blit calls which overlap from_A or to_B are thus harmless.
        // Indeed, calls overlapping to_B are common and ordinary,
        // one reason being that from_A and to_B are often of different sizes.
        int max_from_w = Math.Min(from_A.max_x(), from_x + blit_width);
        int max_to_w   = Math.Min(to_B.max_x(), to_x + blit_width);
        int max_width  = Math.Min(max_from_w, max_to_w);
        blit_width = GridUtility2D.Clamp(blit_width, 1, max_width);

        int max_from_h = Math.Min(from_A.max_y(), from_y + blit_height);
        int max_to_h   = Math.Min(to_B.max_y(), to_y + blit_height);
        int max_height = Math.Min(max_from_h, max_to_h);
        blit_height = GridUtility2D.Clamp(blit_height, 1, max_height);

        // Iterate over the cells of from_A, and copy non-blank cells onto to_B:
        for (int yy = 0; yy <= blit_height; yy++) {
            for (int xx = 0; xx <= blit_width; xx++) {
                // To find the from/to blit coordinates,
                // add in the x,y offsets for from_A and to_B:
                int from_ii = GridUtility2D.indexForXYW(from_x + xx, from_y + yy, from_A.width);
                int   to_ii = GridUtility2D.indexForXYW(to_x + xx, to_y + yy, to_B.width);

                int contents = from_A.contents_at_XY(from_x + xx, from_y + yy);
                if (contents != 0) {
                    // Non-zero, not a blank cell (blank cells are skipped)
                    to_B.set_contents_at_XY(to_x + xx, to_y + yy, contents);
                }
            } // for (xx)
        } // for (yy)

        return to_B;  // to_B has been modified
    }
    public DenseGrid Flip_NS()
    {
        DenseGrid new_grid = new DenseGrid(this.width, this.height, 0);
        DenseGrid.BlitFromAOntoB(this, new_grid, 0, 0);

        // Starting with the outmost and working towards center,
        // swap the contents of each paired horizontal strip.
        for (int N_yy = 0; N_yy < new_grid.center_y(); N_yy++)  // VERIFY: is this correct for even heights?
            {
            int S_yy = new_grid.max_y() - N_yy;
            for (int xx = 0; xx <= new_grid.max_x(); xx++) {
                int N_value = contents_at_XY(xx, N_yy);
                int S_value = contents_at_XY(xx, S_yy);
                new_grid.set_contents_at_XY(xx, N_yy, S_value);
                new_grid.set_contents_at_XY(xx, S_yy, N_value);
            } // for(yy)
        } // for(xx)
        return new_grid;
    }