package rabbitescape.engine.util;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.CoreMatchers.*;
import static rabbitescape.engine.textworld.TextWorldManip.*;
import static rabbitescape.engine.util.Util.*;
import java.util.Collections;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import rabbitescape.engine.World;
public class WorldAssertions
{
public static void assertWorldEvolvesLike(
String initialState, String... laterStates )
{
doAssertWorldEvolvesLike( initialState, laterStates, false );
doAssertMirroredWorldEvolvesLike( initialState, laterStates );
}
private static void doAssertMirroredWorldEvolvesLike(
String initialState, String[] laterStates )
{
doAssertWorldEvolvesLike(
mirror( initialState ), mirror( laterStates ), true );
}
public static String[] mirror( String... states )
{
return map( new MirrorState(), states, new String[0] );
}
public static String mirror( String state )
{
return new MirrorState().apply( state );
}
private static class MirrorLine implements Function<String, String>
{
@Override
public String apply( String input )
{
if ( input.startsWith( ":*=" ) )
{
return (
input.substring( 0, 3 )
+ swapChars( input.substring( 3 ) )
);
}
else
{
return swapChars(
new StringBuilder( input ).reverse().toString() );
}
}
private String swapChars( String input )
{
char[] ret = new char[input.length()];
for( int i = 0; i < ret.length; ++i )
{
ret[i] = swapChar( input.charAt( i ) );
}
return new String( ret );
}
private char swapChar( char c )
{
switch ( c )
{
case 'r': return 'j'; case 'j': return 'r';
case '/': return '\\'; case '\\': return '/';
case '(': return ')'; case ')': return '(';
case '<': return '>'; case '>': return '<';
case '|': return '?'; case '?': return '|';
case '[': return ']'; case ']': return '[';
case '$': return '^'; case '^': return '$';
case '\'': return '!'; case '!': return '\'';
case '-': return '='; case '=': return '-';
case '@': return '%'; case '%': return '@';
case '_': return '+'; case '+': return '_';
case ',': return '.'; case '.': return ',';
case '&': return 'm'; case 'm': return '&';
case 'e': return 's'; case 's': return 'e';
case 'h': return 'a'; case 'a': return 'h';
case 'K': return 'W'; case 'W': return 'K';
case 'I': return 'J'; case 'J': return 'I';
case 'B': return 'E'; case 'E': return 'B';
case 'G': return 'T'; case 'T': return 'G';
case 'Y': return 'F'; case 'F': return 'Y';
case 'U': return 'L'; case 'L': return 'U';
case '{': return '}'; case '}': return '{';
case '~': return '`'; case '`': return '~';
default: return c;
}
}
}
private static class MirrorState implements Function<String, String>
{
@Override
public String apply( String state )
{
return join(
"\n",
map( new MirrorLine(), split( state, "\n" ), new String[0] )
);
}
}
private static void doAssertWorldEvolvesLike(
String initialState, String[] laterStates, boolean reverseOrder )
{
World world = createWorld( split( initialState, "\n" ) );
if ( reverseOrder )
{
Collections.reverse( world.rabbits );
}
for ( IdxObj<String> state : enumerate( laterStates ) )
{
world.step();
assertThat(
renderWorld( world, true, false ),
equalToState( split( state.object, "\n" ), state.index + 2 )
);
}
}
private static Matcher<String[]> equalToState(
final String[] expected, final int stateNum )
{
return new BaseMatcher<String[]>()
{
String[] other;
@Override
public boolean matches( Object objOther )
{
if ( !( objOther instanceof String[] ) )
{
return false;
}
other = (String[])objOther;
return equalTo( expected ).matches( other );
}
@Override
public void describeTo( Description description )
{
description.appendText(
" (at frame number " + stateNum + ")\n" );
description.appendText( join( "\n", expected ) );
description.appendText( "\nActual:\n" );
description.appendText( join( "\n", other ) );
}
};
}
/**
* @brief Note that this method steps the world, changing the input argument
* that is referenced.
*/
public static void assertWorldEvolvesLike(
World world,
int nSteps,
String[] finalWorld )
{
for ( int i = 0; i < nSteps; i++ )
{
world.step();
}
String[] steppedWorld = renderCompleteWorld( world, false );
try
{
assertThat( finalWorld.length, equalTo( steppedWorld.length ) );
assertThat(
finalWorld,
equalTo( steppedWorld )
);
}
catch ( AssertionError e )
{
// Output the stepped world in case it's helpful for building an
// assertion.
for ( String s : steppedWorld )
{
System.out.println( "\"" + s + "\"," );
}
throw e;
}
}
}