def to_fumen(self): """Output setup + continuations in one fumen.""" if len(self.continuations) > 0: frames = [fumen.decode(self.solution.fumen)] for cont in self.continuations: field, _ = fumen.decode(cont.solution.fumen) comment = "%.2f%%" % cont.PC_rate if cont.PC_rate > 0 else "" frames.append((field, comment)) #print(frames) return fumen.encode(frames) else: return self.solution.fumen
def fields(): """Return a list of fields to be tested by unit tests.""" test_fumens = [ "v115@AhBtDewhQ4ywBti0whR4wwRpilg0whAeQ4AeRpglCe?whJeAgl", #albatross "v115@hghlQ4BeAtEeglR4BtAewhh0AeglA8Q4AtRpwhg0Be?D8Rpwhg0CeE8whB8AeI8AeG8JeAgH", #DT-cannon bag2 "v115@AhBtDewhQ4CeBti0whR4AeRpilg0whAeQ4AeRpglCe?whJeAgl", #albatross without T ] return [fumen.decode(test_fumen)[0] for test_fumen in test_fumens]
def get_solutions(fm): """Attempt to retrieve solutions from cache.""" fname = get_cache_file(fm) cache_file = Path(working_dir / fname) if cache_file.exists(): with cache_file.open() as f: sols = f.read().splitlines() # move to backup of old caches cache_file.rename(backup_dir / fname) solutions = [] for sol in sols: field, seq = fumen.decode(sol) solutions.append(TetSolution(TetField(from_list=field), sol, seq)) return solutions else: return None
def fumen_to_image(fumen_data, height, blocks): """Convert fumen encoded field to base64 encoded PNG image (for embedding in output.html). height can be used to expand the field to a certain height with blank rows, should not be less than field height. blocks is a numpy array of block images in PNG format. """ field, _ = fumen.decode(fumen_data) field_height = len(field) if (height > field_height): field.extend([[0] * 10 for _ in range(height - field_height)]) # fumen.decode returns blocks in reverse order # could potentially speed things up even more by going straight from fumen to the proper format for this # and have a separate function to turn fumen output to a TetField field.reverse() img_data = numpy.vstack( tuple(numpy.hstack(tuple(blocks[i] for i in row)) for row in field)) # for some reason optimize is giving me larger filesizes # imageio.imwrite("test.png", img_data, format="PNG", optimize=True png_data = imageio.imwrite(imageio.RETURN_BYTES, img_data, format="PNG") data_url = "data:image/png;base64," + base64.b64encode(png_data).decode() return data_url
def main(): #albatross without T piece test_field, _ = fumen.decode( "v115@AhBtDewhQ4CeBti0whR4AeRpilg0whAeQ4AeRpglCe?whJeAgl") print(is_bag_possible(test_field, "SOLIZJ"))
def test_is_harddrop_possible(): """ Unit tests for is_harddrop_possible. successes: for each placement, dropping onto blank ground in every position possible for that piece dropping onto ground raised a certain amount ground where only one point of piece makes contact: v115@CgywHewwA8ZeQ4BeQ4FeR4AeR4AezhA8Q4BeQ4DeA8?DeA8ieAgl dropping inbetween narrow gap: v115@1gB8CeA8AeA8BeB8CeA8whA8Q4AeB8CeA8whA8R4B8?AewwAeA8whA8AeQ4B8ywA8whA8JeAgl fails: piece out of bounds part of piece occupied floating pieces (test if bottom block in column makes contact for each column) (note: this wouldnt work with more complex shapes, but should work with every mino?) gap too narrow, or overhang above (for later: argument for height harddropped from) """ # attempt to place every piece/rotation in every possible spot on a blank field # should succeed for all in-bounds pieces, should fail for out-of-bounds blank_field = [[0] * 10 for __ in range(20)] for piece in "ILOZTJS": for rot in range(4): for y in range(-2, 0): for x in range(-2, 10): result = setupfinder.analysis.is_harddrop_possible( piece, (x, y, rot), blank_field) if x in list( setupfinder.analysis.VALID_X_PLACEMENTS[piece] [rot]) and y == setupfinder.analysis.MIN_Y_PLACEMENT[ piece][rot]: assert result == True else: assert result == False # test piece hanging off a single point, also hanging from the middle row of the piece # one floating dot at 5,2 test_field, __ = fumen.decode("v115@MhA8heAgH") for __ in range(20 - len(test_field)): test_field.append([0] * 10) supported_placements = [("I", (2, 2, 0)), ("I", (3, 3, 1)), ("L", (3, 2, 0))] floating_placements = [("I", (1, 2, 0)), ("I", (2, 3, 1)), ("L", (3, 3, 0))] for piece, placement in supported_placements: assert setupfinder.analysis.is_harddrop_possible( piece, placement, test_field) == True for piece, placement in floating_placements: assert setupfinder.analysis.is_harddrop_possible( piece, placement, test_field) == False # test harddropping into narrow gap # x = 0 is 3-wide, x = 4 is 2-wide, x = 7 is 1-wide test_field, __ = fumen.decode( "v115@AhA8BeA8AeB8CeA8BeA8AeB8CeA8BeA8AeB8CeA8Be?A8AeB8JeAgH") for __ in range(20 - len(test_field)): test_field.append([0] * 10) # test every piece/rotation in each spot # OCCUPIED_COLS is set up the same way as PIECES, for each rotation it's a list of which cols contain a block for piece, rot_cols in setupfinder.analysis.OCCUPIED_COLS.items(): for rotation, cols in enumerate(rot_cols): rotation_width = len(cols) # first column with a block in it (to align piece) rotation_x_offset = cols[0] # bottom of the piece so we don't try placing out of bounds rotation_y = setupfinder.analysis.MIN_Y_PLACEMENT[piece][rotation] fits_in_3_wide_gap = setupfinder.analysis.is_harddrop_possible( piece, (0 - rotation_x_offset, rotation_y, rotation), test_field) fits_in_2_wide_gap = setupfinder.analysis.is_harddrop_possible( piece, (4 - rotation_x_offset, rotation_y, rotation), test_field) fits_in_1_wide_gap = setupfinder.analysis.is_harddrop_possible( piece, (7 - rotation_x_offset, rotation_y, rotation), test_field) assert fits_in_3_wide_gap == (rotation_width <= 3) assert fits_in_2_wide_gap == (rotation_width <= 2) assert fits_in_1_wide_gap == (rotation_width <= 1) # test places where piece fits but spot covered # same field as before but entire thing is covered test_field, __ = fumen.decode( "v115@zgJ8CeA8BeA8AeB8CeA8BeA8AeB8CeA8BeA8AeB8Ce?A8BeA8AeB8JeAgH") for __ in range(20 - len(test_field)): test_field.append([0] * 10) for piece, rot_cols in setupfinder.analysis.OCCUPIED_COLS.items(): for rotation, cols in enumerate(rot_cols): # first column with a block in it (to align piece) rotation_x_offset = cols[0] # bottom of the piece so we don't try placing out of bounds rotation_y = setupfinder.analysis.MIN_Y_PLACEMENT[piece][rotation] covered_3_wide_gap = setupfinder.analysis.is_harddrop_possible( piece, (0 - rotation_x_offset, rotation_y, rotation), test_field) assert covered_3_wide_gap == False # make sure flat i piece can't be placed with blocks covering row 1 # (this tests covering blocks inside the piece's bounding box) test_field, __ = fumen.decode("v115@RhJ8DeF8JeAgl") for __ in range(20 - len(test_field)): test_field.append([0] * 10) covered_i_piece = setupfinder.analysis.is_harddrop_possible( "I", (0, -1, 0), test_field) assert covered_i_piece == False