from mudlib.world.terrain import World def test_world_deterministic_from_seed(): """Same seed produces identical terrain.""" world1 = World(seed=42, width=100, height=100) world2 = World(seed=42, width=100, height=100) for y in range(100): for x in range(100): assert world1.get_tile(x, y) == world2.get_tile(x, y) def test_world_different_seeds_produce_different_terrain(): """Different seeds produce different terrain.""" world1 = World(seed=42, width=100, height=100) world2 = World(seed=99, width=100, height=100) different_tiles = 0 for y in range(100): for x in range(100): if world1.get_tile(x, y) != world2.get_tile(x, y): different_tiles += 1 # at least 10% should be different assert different_tiles > 1000 def test_world_dimensions(): """World has correct dimensions.""" world = World(seed=42, width=100, height=50) # should not raise for valid coordinates world.get_tile(0, 0) world.get_tile(99, 49) # coordinates wrap instead of raising assert world.get_tile(100, 0) == world.get_tile(0, 0) assert world.get_tile(0, 50) == world.get_tile(0, 0) assert world.get_tile(-1, 0) == world.get_tile(99, 0) assert world.get_tile(0, -1) == world.get_tile(0, 49) def test_get_tile_returns_valid_terrain(): """get_tile returns valid terrain characters.""" world = World(seed=42, width=100, height=100) valid_terrain = {".", "^", "~", "T", ":"} for y in range(100): for x in range(100): tile = world.get_tile(x, y) assert tile in valid_terrain def test_is_passable_mountains_impassable(): """Mountains are impassable.""" world = World(seed=42, width=100, height=100) for y in range(100): for x in range(100): tile = world.get_tile(x, y) if tile == "^": assert not world.is_passable(x, y) def test_is_passable_water_impassable(): """Water is impassable.""" world = World(seed=42, width=100, height=100) for y in range(100): for x in range(100): tile = world.get_tile(x, y) if tile == "~": assert not world.is_passable(x, y) def test_is_passable_grass_passable(): """Grass is passable.""" world = World(seed=42, width=100, height=100) for y in range(100): for x in range(100): tile = world.get_tile(x, y) if tile == ".": assert world.is_passable(x, y) def test_is_passable_forest_passable(): """Forest is passable.""" world = World(seed=42, width=100, height=100) for y in range(100): for x in range(100): tile = world.get_tile(x, y) if tile == "T": assert world.is_passable(x, y) def test_is_passable_sand_passable(): """Sand is passable.""" world = World(seed=42, width=100, height=100) for y in range(100): for x in range(100): tile = world.get_tile(x, y) if tile == ":": assert world.is_passable(x, y) def test_get_viewport_dimensions(): """get_viewport returns correct dimensions.""" world = World(seed=42, width=100, height=100) viewport = world.get_viewport(50, 50, width=10, height=8) assert len(viewport) == 8 assert len(viewport[0]) == 10 def test_get_viewport_centers_correctly(): """get_viewport centers on given coordinates.""" world = World(seed=42, width=100, height=100) viewport = world.get_viewport(50, 50, width=5, height=5) # center tile should be at position (2, 2) in viewport center_tile = viewport[2][2] assert center_tile == world.get_tile(50, 50) def test_get_viewport_wraps_at_edges(): """Viewport wraps around world boundaries.""" world = World(seed=42, width=100, height=100) # near top-left corner - viewport should wrap to bottom/right viewport = world.get_viewport(0, 0, width=5, height=5) assert len(viewport) == 5 assert len(viewport[0]) == 5 # top-left of viewport wraps to bottom-right of world assert viewport[0][0] == world.get_tile(98, 98) # near bottom-right corner - viewport should wrap to top/left viewport = world.get_viewport(99, 99, width=5, height=5) assert len(viewport) == 5 assert len(viewport[0]) == 5 # bottom-right of viewport wraps to top-left of world assert viewport[4][4] == world.get_tile(1, 1) def test_terrain_distribution_reasonable(): """Terrain has reasonable distribution (not all one type).""" world = World(seed=42, width=100, height=100) terrain_counts = {".": 0, "^": 0, "~": 0, "T": 0, ":": 0} for y in range(100): for x in range(100): tile = world.get_tile(x, y) terrain_counts[tile] += 1 # should have at least 3 different terrain types types_present = sum(1 for count in terrain_counts.values() if count > 0) assert types_present >= 3 # no single type should dominate completely (> 95%) total = sum(terrain_counts.values()) for terrain_type, count in terrain_counts.items(): assert count < 0.95 * total, f"{terrain_type} dominates with {count}/{total}" def test_rivers_exist(): """Terrain has some water tiles (rivers/lakes).""" world = World(seed=42, width=100, height=100) water_count = 0 for y in range(100): for x in range(100): if world.get_tile(x, y) == "~": water_count += 1 # should have at least some water assert water_count > 0 def test_terrain_tiles_seamlessly(): """Terrain at opposite edges matches for seamless wrapping.""" world = World(seed=42, width=100, height=100) # check that a strip along the right edge is continuous with the left edge # by verifying the elevation-derived terrain doesn't have a hard seam. # the noise is tileable, so adjacent tiles across the boundary should be # from the same smooth noise field (not identical, but not a cliff). # we verify the wrap helper itself works correctly: for y in range(100): assert world.get_tile(-1, y) == world.get_tile(99, y) assert world.get_tile(100, y) == world.get_tile(0, y) for x in range(100): assert world.get_tile(x, -1) == world.get_tile(x, 99) assert world.get_tile(x, 100) == world.get_tile(x, 0) def test_large_world_generation(): """Can generate a 1000x1000 world without errors.""" world = World(seed=42, width=1000, height=1000) # spot check some tiles assert world.get_tile(0, 0) in {".", "^", "~", "T", ":"} assert world.get_tile(500, 500) in {".", "^", "~", "T", ":"} assert world.get_tile(999, 999) in {".", "^", "~", "T", ":"}