Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.FileReader;
- import java.io.IOException;
- import java.util.*;
- import java.util.stream.Stream;
- public final class Bricks {
- static final boolean IS_DEBUG = false;
- static final String BRICKS_FILE = "bricks.txt";
- public static void main( String[] sArgs ) {
- SortedSet<Brick> S_Bks,
- S_Bks1 = loadBricks( new File( BRICKS_FILE ), PillarPreference.LEFT ),
- S_Bks2 = loadBricks( new File( BRICKS_FILE ), PillarPreference.RIGHT ),
- S_Bks3 = loadBricks( new File( BRICKS_FILE ), PillarPreference.STRAIGHT );
- int iScore,
- iScore1 = runOnce( S_Bks1 ),
- iScore2 = runOnce( S_Bks2 ),
- iScore3 = runOnce( S_Bks3 );
- if( iScore1 <= iScore2 && iScore1 <= iScore3 ) {
- S_Bks = S_Bks1;
- iScore = iScore1;
- } else if( iScore2 <= iScore3 ) {
- S_Bks = S_Bks2;
- iScore = iScore2;
- } else {
- S_Bks = S_Bks3;
- iScore = iScore3;
- }
- System.out.println( "Best solution requires " + iScore + " block(s).\n\n" );
- dumpBricks( S_Bks );
- }
- private static int runOnce( SortedSet<Brick> S_Bks ) {
- if( IS_DEBUG ) {
- System.out.println( "Initial configuration for " + S_Bks.first().BkC.PPr.name() +
- " pillar preference:\n" );
- dumpBricks( S_Bks );
- }
- int nInit = nonemptyBrickCount( S_Bks );
- Stream<Brick> SmBksProc = S_Bks.stream().filter( Brick::isNonempty );
- while( true ) {
- SortedSet<Brick> S_BksMod = new TreeSet<>();
- SmBksProc.forEach( Bk -> S_BksMod.addAll( Bk.stabilize() ) );
- if( IS_DEBUG ) {
- System.out.println( "Stabilization step yielded " + S_BksMod.size() + " new brick(s).\n" );
- dumpBricks( S_Bks );
- }
- if( S_BksMod.isEmpty() )
- break;
- SmBksProc = S_BksMod.stream();
- }
- while( true ) {
- int iMod = S_Bks.stream().filter( Brick::isAdded ).mapToInt( Brick::jenga ).sum();
- if( IS_DEBUG ) {
- System.out.println( "Jenga step removed " + iMod + " brick(s).\n" );
- dumpBricks( S_Bks );
- }
- if( iMod == 0 )
- break;
- }
- int nFinal = nonemptyBrickCount( S_Bks );
- return nFinal - nInit;
- }
- static SortedSet<Brick> loadBricks( File F, PillarPreference PPr ) {
- List<char[]> chsAs = new LinkedList<>(),
- chsBs = new LinkedList<>();
- boolean isA = true;
- int nCharsPerTier = 0;
- try( BufferedReader BR = new BufferedReader( new FileReader( F ) ) ) {
- while( BR.ready() ) {
- String s = BR.readLine();
- if( s.isEmpty() ) {
- BR.close();
- return new TreeSet<>();
- }
- char[] chs = s.toCharArray();
- if( chsAs.isEmpty() ) {
- char[] chsBlank = new char[chs.length];
- nCharsPerTier = chs.length;
- Arrays.fill( chsBlank, '.' );
- chsAs.add( chsBlank );
- isA = false;
- }
- if( isA )
- chsAs.add( chs );
- else chsBs.add( chs );
- isA = !isA;
- }
- BR.close();
- } catch( IOException ioe ) {
- System.err.println( "Unable to read contents of bricks file: " + F );
- System.exit( 1 );
- }
- final boolean isWideA = chsAs.parallelStream().anyMatch( chs -> {
- for( int i = 0; i < chs.length; i += 4 )
- if( chs[i] == '[' )
- return true;
- return false;
- } );
- SortedSet<Brick> S_Bks = new TreeSet<>();
- int nTiers = chsAs.size() + chsBs.size();
- Brick[][] Bks = new Brick[nTiers][];
- BrickContext BkC = new BrickContext( nTiers, nCharsPerTier, isWideA, PPr );
- brickify( chsAs, Bks, S_Bks, 0, BkC );
- brickify( chsBs, Bks, S_Bks, 1, BkC );
- for( Brick Bk : S_Bks )
- Bk.initFrom( Bks );
- return S_Bks;
- }
- private static void brickify( List<char[]> chss, Brick[][] Bks, Set<Brick> S_Bks, int iTier0, BrickContext BkC ) {
- int iTier = iTier0;
- for( char[] chs : chss ) {
- int nBrk, i0;
- if( BkC.isWide( iTier ) ) {
- nBrk = chs.length/4;
- i0 = 0;
- } else {
- nBrk = chs.length/4 - 1;
- i0 = 2;
- }
- Brick[] BksTier = new Brick[nBrk];
- for( int i = i0, iOrd = 0; i < chs.length - 2; i += 4, iOrd++ ) {
- Brick Bk = new Brick( iTier, iOrd, chs[i] == '[' ? Type.FIXED : Type.EMPTY, BkC );
- BksTier[iOrd] = Bk;
- S_Bks.add( Bk );
- }
- Bks[iTier] = BksTier;
- iTier += 2;
- }
- }
- static void dumpBricks( SortedSet<Brick> S_Bks ) {
- BrickContext BkC = S_Bks.first().BkC;
- char[] chsOut = new char[BkC.nTiers*(1 + BkC.nCharsPerTier)];
- Arrays.fill( chsOut, '.' );
- for( int i = BkC.nCharsPerTier; i < chsOut.length; i += BkC.nCharsPerTier + 1 )
- chsOut[i] = '\n';
- S_Bks.stream().filter( Brick::isNonempty ).forEach(
- Bk -> System.arraycopy( Bk.Ty.chsGfx, 0, chsOut, Bk.iOrd*4 + (1 + BkC.nCharsPerTier)*Bk.iTier +
- (BkC.isWide( Bk.iTier ) ? 0 : 2), 4 ) );
- System.out.print( new String( chsOut ) );
- }
- static int nonemptyBrickCount( Set<Brick> S_Bks ) {
- return (int)S_Bks.parallelStream().filter( Brick::isNonempty ).count();
- }
- static final class Brick implements Comparable<Brick> {
- final int iTier;
- final int iOrd;
- final BrickContext BkC;
- Brick BkTL;
- Brick BkTR;
- Brick BkBL;
- Brick BkBR;
- Type Ty;
- Brick( int iTier, int iOrd, Type Ty, BrickContext BkC ) {
- this.iTier = iTier;
- this.iOrd = iOrd;
- this.Ty = Ty;
- this.BkC = BkC;
- }
- void initFrom( Brick[][] Bks ) {
- boolean isWide = BkC.isWide( iTier );
- if( iTier != 0 && (!isWide || iOrd != 0) )
- BkTL = Bks[iTier - 1][iOrd - (isWide ? 1 : 0)];
- if( iTier != 0 && (!isWide || iOrd != Bks[iTier].length-1) )
- BkTR = Bks[iTier - 1][iOrd + (isWide ? 0 : 1)];
- if( iTier != Bks.length-1 && (!isWide || iOrd != 0) )
- BkBL = Bks[iTier + 1][iOrd - (isWide ? 1 : 0)];
- if( iTier != Bks.length-1 && (!isWide || iOrd != Bks[iTier].length-1) )
- BkBR = Bks[iTier + 1][iOrd + (isWide ? 0 : 1)];
- }
- boolean isStable() {
- if( isOnBottom() )
- return true;
- boolean isR = isFlushRight(),
- isL = isFlushLeft(),
- isT = isOnTop();
- return !isR && !isL && BkBR.isNonempty() && BkBL.isNonempty() ||
- !isR && !isT && BkBR.isNonempty() && BkTR.isNonempty() ||
- !isL && !isT && BkBL.isNonempty() && BkTL.isNonempty();
- }
- Set<Brick> stabilize() {
- if( isStable() )
- return Collections.emptySet();
- SortedSet<Brick> S = new TreeSet<>();
- if( isFlushRight() ) {
- if( !BkBL.isNonempty() ) {
- BkBL.Ty = Type.ADDED;
- S.add( BkBL );
- }
- if( !BkTL.isNonempty() ) {
- BkTL.Ty = Type.ADDED;
- S.add( BkTL );
- }
- } else if( isFlushLeft() ) {
- if( !BkBR.isNonempty() ) {
- BkBR.Ty = Type.ADDED;
- S.add( BkBR );
- }
- if( !BkTR.isNonempty() ) {
- BkTR.Ty = Type.ADDED;
- S.add( BkTR );
- }
- } else {
- if( !BkBL.isNonempty() ) {
- BkBL.Ty = Type.ADDED;
- S.add( BkBL );
- }
- if( !BkBR.isNonempty() ) {
- BkBR.Ty = Type.ADDED;
- S.add( BkBR );
- }
- }
- return S;
- }
- boolean registerFundamentalDependencies( Set<Brick> S_DepsIn ) {
- S_DepsIn.add( this );
- Ty = Type.EMPTY;
- if( addDependenciesFor( S_DepsIn, BkBL ) ) {
- Ty = Type.ADDED;
- return true;
- }
- if( addDependenciesFor( S_DepsIn, BkBR ) ) {
- Ty = Type.ADDED;
- return true;
- }
- if( addDependenciesFor( S_DepsIn, BkTL ) ) {
- Ty = Type.ADDED;
- return true;
- }
- if( addDependenciesFor( S_DepsIn, BkTR ) ) {
- Ty = Type.ADDED;
- return true;
- }
- Ty = Type.ADDED;
- return false;
- }
- private static boolean addDependenciesFor( Set<Brick> S_DepsIn, Brick Bk ) {
- return Bk != null &&
- Bk.isNonempty() &&
- !S_DepsIn.contains( Bk ) &&
- !Bk.isStable() &&
- (!Bk.isAdded() || Bk.registerFundamentalDependencies( S_DepsIn ));
- }
- int jenga() {
- if( !isAdded() )
- return 0;
- Set<Brick> S = new TreeSet<>();
- boolean isMod = !registerFundamentalDependencies( S );
- if( isMod )
- S.stream().forEach( Bk -> Bk.Ty = Type.EMPTY );
- return isMod ? S.size() : 0;
- }
- boolean isNonempty() {
- return Ty != Type.EMPTY;
- }
- boolean isAdded() {
- return Ty == Type.ADDED;
- }
- boolean isOnBottom() {
- return BkBL == null && BkBR == null;
- }
- boolean isOnTop() {
- return BkTL == null && BkTR == null;
- }
- boolean isFlushRight() {
- return BkTR == null && BkBR == null;
- }
- boolean isFlushLeft() {
- return BkTL == null && BkBL == null;
- }
- @Override public int compareTo( Brick Bk ) {
- int iOrdSign = BkC.PPr == PillarPreference.RIGHT ? -1 :
- (BkC.PPr == PillarPreference.LEFT ? 1 : (BkC.isWide( iTier ) ? 1 : -1) );
- return iTier < Bk.iTier ? -1 : (iTier > Bk.iTier ? 1 :
- (iOrd < Bk.iOrd ? -1 : (iOrd > Bk.iOrd ? 1 : 0))*iOrdSign);
- }
- public boolean equals( Object o ) {
- if( !(o instanceof Brick) )
- return false;
- Brick Bk = (Brick)o;
- return Bk.iTier == iTier && Bk.iOrd == iOrd;
- }
- public int hashCode() {
- return iTier*13189 + iOrd;
- }
- }
- static final class BrickContext {
- final int nTiers;
- final int nCharsPerTier;
- final boolean isTier0Wide;
- final PillarPreference PPr;
- BrickContext( int nTiers, int nCharsPerTier, boolean isTier0Wide, PillarPreference PPr ) {
- this.nTiers = nTiers;
- this.nCharsPerTier = nCharsPerTier;
- this.isTier0Wide = isTier0Wide;
- this.PPr = PPr;
- }
- boolean isWide( int iTier ) {
- return ((iTier &1) == 0) == isTier0Wide;
- }
- }
- enum Type {
- FIXED( "[XX]" ),
- ADDED( "[ ]" ),
- EMPTY( "...." );
- final char[] chsGfx;
- Type( String sGfx ) {
- chsGfx = sGfx.toCharArray();
- }
- }
- enum PillarPreference {
- RIGHT,
- LEFT,
- STRAIGHT
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement