package rabbitescape.engine.solution; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import rabbitescape.engine.Entrance; import rabbitescape.engine.Exit; import rabbitescape.engine.Fire; import rabbitescape.engine.IgnoreWorldStatsListener; import rabbitescape.engine.Pipe; import rabbitescape.engine.Rabbit; import rabbitescape.engine.Thing; import rabbitescape.engine.Token; import rabbitescape.engine.VoidMarkerStyle; import rabbitescape.engine.World; import rabbitescape.engine.textworld.Comment; /** * A completely sandboxed game that can be edited and have solutions run against * without affecting the real game. */ public class SandboxGame { /** * The token type that is currently 'selected' by whatever is interacting * with the sandbox. */ private Token.Type selectedType = null; /** The world object that is contained in the game. */ private final World world; /** * Create a sandbox game based on a given world. This allows playing with * the sandbox game without affecting the world in any way. * * @param world * The world to copy. */ public SandboxGame( World world ) { List<Rabbit> clonedRabbits = makeClonedRabbits( world.rabbits ); List<Thing> clonedThings = makeClonedThings( world.things ); this.world = new World( world.size, world.blockTable.getListCopy(), clonedRabbits, clonedThings, world.getWaterContents(), new HashMap<>( world.abilities ), world.name, world.description, world.author_name, world.author_url, Arrays.copyOf( world.hints, world.hints.length ), Arrays.copyOf( world.solutions, world.solutions.length ), world.num_rabbits, world.num_to_save, world.rabbit_delay, world.music, world.num_saved, world.num_killed, world.num_waiting, world.getRabbitIndexCount(), world.paused, new Comment[] {}, new IgnoreWorldStatsListener(), VoidMarkerStyle.Style.HIGHLIGHTER ); } /** * Create a clone of the list of a given list of things. * * @param things * The things to clone. * @return The cloned list of things. */ private List<Thing> makeClonedThings( List<Thing> things ) { List<Thing> clonedThings = new ArrayList<>(); for ( Thing thing : things ) { if ( thing instanceof Entrance ) { clonedThings.add( new Entrance( thing.x, thing.y ) ); } else if ( thing instanceof Exit ) { clonedThings.add( new Exit( thing.x, thing.y ) ); } else if ( thing instanceof Rabbit ) { Rabbit rabbit = (Rabbit)thing; clonedThings.add( cloneRabbit( rabbit ) ); } else if ( thing instanceof Token ) { Token token = (Token)thing; clonedThings.add( new Token( token.x, token.y, token.type ) ); } else if ( thing instanceof Fire ) { Fire fire = (Fire)thing; clonedThings.add( new Fire( fire.x, fire.y ) ); } else if ( thing instanceof Pipe ) { Pipe pipe = (Pipe)thing; clonedThings.add( new Pipe( pipe.x, pipe.y ) ); } else { // We've created a new type of Thing, but haven't updated the // code here to cope with it. throw new IllegalStateException( "Unrecognised type of Thing: " + thing ); } } return clonedThings; } /** * Make a clone of a list of rabbits. * * @param rabbits * The list of rabbits to clone. * @return The cloned list. */ private List<Rabbit> makeClonedRabbits( List<Rabbit> rabbits ) { List<Rabbit> clonedRabbits = new ArrayList<>(); for ( Rabbit rabbit : rabbits ) { clonedRabbits.add( cloneRabbit( rabbit ) ); } return clonedRabbits; } /** * Clone a single rabbit. * * @param rabbit * The rabbit to be cloned. * @return The cloned rabbit. */ private Rabbit cloneRabbit( Rabbit rabbit ) { return new Rabbit( rabbit.x, rabbit.y, rabbit.dir ); } /** * Get the currently selected token type. * * @return The token type selected. */ public Token.Type getSelectedType() { return selectedType; } /** * Select a token type to place next. * * @param selectedType * The type to select. */ public void setSelectedType( Token.Type selectedType ) { this.selectedType = selectedType; } /** * Get the current world. * * @return The sandboxed world. */ public World getWorld() { return world; } }