All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.refcodes.checkerboard.ConsoleCheckerboardViewer Maven / Gradle / Ivy

Go to download

Artifact for providing some easy means to visualize (state of) board games or (state of) cellular automatons.

There is a newer version: 3.3.8
Show newest version
// /////////////////////////////////////////////////////////////////////////////
// REFCODES.ORG
// /////////////////////////////////////////////////////////////////////////////
// This code is copyright (c) by Siegfried Steiner, Munich, Germany and licensed
// under the following (see "http://en.wikipedia.org/wiki/Multi-licensing")
// licenses:
// -----------------------------------------------------------------------------
// GNU General Public License, v3.0 ("http://www.gnu.org/licenses/gpl-3.0.html")
// -----------------------------------------------------------------------------
// Apache License, v2.0 ("http://www.apache.org/licenses/TEXT-2.0")
// -----------------------------------------------------------------------------
// Please contact the copyright holding author(s) of the software artifacts in
// question for licensing issues not being covered by the above listed licenses,
// also regarding commercial licensing models or regarding the compatibility
// with other open source licenses.
// /////////////////////////////////////////////////////////////////////////////

package org.refcodes.checkerboard;

import org.refcodes.component.InitializeException;
import org.refcodes.exception.VetoException;
import org.refcodes.mixin.ColumnWidthAccessor.ColumnWidthBuilder;
import org.refcodes.mixin.ColumnWidthAccessor.ColumnWidthProperty;
import org.refcodes.textual.HorizAlignTextMode;
import org.refcodes.textual.TableBuilder;
import org.refcodes.textual.TableStyle;

/**
 * 
 * Extends the interface {@link CheckerboardViewer} with functionality required
 * for console output: Most basic implementation of the
 * {@link CheckerboardViewer} interface printing the current checkerboard as
 * good as it gets. Call {@link #initialize()} when everything is setup
 * correctly. When a redraw time <= 0 is set upon construction, then the
 * {@link Checkerboard} is printed out upon any according events from the
 * underlying {@link Checkerboard} or, in case the refresh time is > 0 the
 * {@link Checkerboard} is redrawn as of the refresh loop time. Attention: The
 * {@link Checkerboard} is only redrawn in case the {@link Checkerboard} changed
 * compared to the last redraw process.
 * 
 * @param 

the generic type of the {@link Player} * @param The type which's instances represent a {@link Player} state. */ public class ConsoleCheckerboardViewer

, S> extends AbstractCheckerboardViewer, ConsoleCheckerboardViewer> implements CheckerboardViewer>, ColumnWidthProperty, ColumnWidthBuilder> { // ///////////////////////////////////////////////////////////////////////// // STATICS: // ///////////////////////////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////////////////// // CONSTANTS: // ///////////////////////////////////////////////////////////////////////// private static final int DEFAULT_REFRESH_LOOP_TIME_MILLIS = 100; private static final int DEFAULT_COLUMN_WIDTH = 3; // ///////////////////////////////////////////////////////////////////////// // VARIABLES: // ///////////////////////////////////////////////////////////////////////// private ConsoleSpriteFactory _spriteFactory; private int _redrawLoopTimeMillis; private int _oldState = -1; private int _columnWidth; // ///////////////////////////////////////////////////////////////////////// // CONSTRUCTORS: // ///////////////////////////////////////////////////////////////////////// /** * Constructs the {@link ConsoleCheckerboardViewer} with the provided * {@link SpriteFactory} creating "Sprites" (in this case {@link String} * instances) for visualizing the playground's state. The * {@link ConsoleCheckerboardViewer} is initialized with a redraw loop time * of 100 ms. Attention: The {@link Checkerboard} is only redrawn in case * the {@link Checkerboard} changed compared to the last redraw process. * * @param aCheckerboard The {@link Checkerboard} for which to construct the * viewer. * @param aSpriteFactory The {@link SpriteFactory} to be used. */ public ConsoleCheckerboardViewer( Checkerboard aCheckerboard, ConsoleSpriteFactory aSpriteFactory ) { this( aCheckerboard, aSpriteFactory, DEFAULT_REFRESH_LOOP_TIME_MILLIS ); } /** * Constructs the {@link ConsoleCheckerboardViewer} with the provided * {@link SpriteFactory} creating "Sprites" (in this case {@link String} * instances) for visualizing the playground's state. The * {@link ConsoleCheckerboardViewer} is initialized with the according * redraw loop time. When a redraw time <= 0 is set upon construction, * then the {@link Checkerboard} is printed out upon any according events * from the underlying {@link Checkerboard} or, in case the refresh time is * > 0 the {@link Checkerboard} is redrawn as of the refresh loop time. * Attention: The {@link Checkerboard} is only redrawn in case the * {@link Checkerboard} changed compared to the last redraw process. A * default column width of 3 is configured. * * @param aRedrawLoopTimeMillis The redraw loop time to work with. * @param aCheckerboard The {@link Checkerboard} for which to construct the * viewer. * @param aSpriteFactory The {@link SpriteFactory} to be used. */ public ConsoleCheckerboardViewer( Checkerboard aCheckerboard, ConsoleSpriteFactory aSpriteFactory, int aRedrawLoopTimeMillis ) { this( aCheckerboard, aSpriteFactory, DEFAULT_COLUMN_WIDTH, aRedrawLoopTimeMillis ); } /** * Constructs the {@link ConsoleCheckerboardViewer} with the provided * {@link SpriteFactory} creating "Sprites" (in this case {@link String} * instances) for visualizing the playground's state. The * {@link ConsoleCheckerboardViewer} is initialized with the according * redraw loop time. When a redraw time <= 0 is set upon construction, * then the {@link Checkerboard} is printed out upon any according events * from the underlying {@link Checkerboard} or, in case the refresh time is * > 0 the {@link Checkerboard} is redrawn as of the refresh loop time. * Attention: The {@link Checkerboard} is only redrawn in case the * {@link Checkerboard} changed compared to the last redraw process. * * @param aRedrawLoopTimeMillis The redraw loop time to work with. * @param aCheckerboard The {@link Checkerboard} for which to construct the * viewer. * @param aColumnWidth The column width to be used when drawing the * {@link Checkerboard} table. * @param aSpriteFactory The {@link SpriteFactory} to be used. */ public ConsoleCheckerboardViewer( Checkerboard aCheckerboard, ConsoleSpriteFactory aSpriteFactory, int aColumnWidth, int aRedrawLoopTimeMillis ) { super( aCheckerboard ); aCheckerboard.subscribeObserver( this ); _spriteFactory = aSpriteFactory; _redrawLoopTimeMillis = aRedrawLoopTimeMillis; _columnWidth = aColumnWidth; } // ///////////////////////////////////////////////////////////////////////// // INJECTION: // ///////////////////////////////////////////////////////////////////////// /** * {@inheritDoc} */ @Override public void initialize() throws InitializeException { if ( _redrawLoopTimeMillis > 0 ) { Thread t = new Thread( this::printPlaygroundDaemon ); t.setDaemon( true ); t.start(); } } // ///////////////////////////////////////////////////////////////////////// // LIFECYLE: // ///////////////////////////////////////////////////////////////////////// /** * {@inheritDoc} */ @Override public synchronized void onCheckerboardEvent( CheckerboardEvent aCheckerboardEvent ) { onEventPrintPlayground(); } /** * {@inheritDoc} */ @Override public void onPlayerAddedEvent( PlayerAddedEvent aCheckerboardEvent ) {} /** * {@inheritDoc} */ @Override public void onPlayerRemovedEvent( PlayerRemovedEvent aCheckerboardEvent ) {} /** * {@inheritDoc} */ @Override public void onGridModeChangedEvent( GridModeChangedEvent aCheckerboardEvent ) {} /** * {@inheritDoc} */ @Override public void onGridDimensionChangedEvent( GridDimensionChangedEvent aCheckerboardEvent ) {} /** * {@inheritDoc} */ @Override public void onViewportOffsetChangedEvent( ViewportOffsetChangedEvent aCheckerboardEvent ) {} /** * {@inheritDoc} */ @Override public void onViewportDimensionChangedEvent( ViewportDimensionChangedEvent aCheckerboardEvent ) {} /** * {@inheritDoc} */ @Override public synchronized void onPlayerEvent( PlayerEvent

aPlayerEvent, Checkerboard aSource ) { onEventPrintPlayground(); } /** * {@inheritDoc} */ @Override public void onChangePositionEvent( ChangePositionEvent

aPlayerEvent, Checkerboard aSource ) throws VetoException {} /** * {@inheritDoc} */ @Override public void onPositionChangedEvent( PositionChangedEvent

aPlayerEvent, Checkerboard aSource ) {} /** * {@inheritDoc} */ @Override public synchronized void onStateChangedEvent( StateChangedEvent aPlayerEvent, Checkerboard aSource ) { onEventPrintPlayground(); } /** * {@inheritDoc} */ @Override public void onVisibilityChangedEvent( VisibilityChangedEvent

aPlayerEvent, Checkerboard aSource ) {} /** * {@inheritDoc} */ @Override public void onDraggabilityChangedEvent( DraggabilityChangedEvent

aPlayerEvent, Checkerboard aSource ) {} // ///////////////////////////////////////////////////////////////////////// // METHODS: // ///////////////////////////////////////////////////////////////////////// /** * Retrieves the refresh loop time between two redraw cycles of the * {@link Checkerboard}. This is the delay time between succeeding print * outs of the {@link Checkerboard} states to the console. If the refresh * loop time is > 0, then the {@link Checkerboard} is redrawn at most * with intervals of the given refresh loop time. Attention: The * {@link Checkerboard} is only redrawn in case the {@link Checkerboard} * changed compared to the last redraw process. * * @return The according time in milliseconds. */ public int getRedrawLoopTimeMillis() { return _redrawLoopTimeMillis; } /** * Determines whether the {@link Checkerboard} is printed out upon any * according events from the underlying {@link Checkerboard} or as of the * refresh loop time (see {@link #getRedrawLoopTimeMillis()}). Attention: * The {@link Checkerboard} is only redrawn in case the {@link Checkerboard} * changed compared to the last redraw process. * * @return True in case the {@link Checkerboard} is redrawn upon an event * from the {@link Checkerboard} or upon the refresh loop time. */ public boolean isRedrawOnEvent() { return _redrawLoopTimeMillis <= 0; } // ///////////////////////////////////////////////////////////////////////// // HOOKS: // ///////////////////////////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////////////////// // HELPER: // ///////////////////////////////////////////////////////////////////////// /** * Loops the playground printing via {@link #printPlayground()}. */ protected void printPlaygroundDaemon() { while ( true ) { printPlayground(); try { Thread.sleep( _redrawLoopTimeMillis ); } catch ( InterruptedException ignore ) {} } } /** * Prints the playground upon an according {@link Checkerboard} event in * case the */ protected void onEventPrintPlayground() { if ( _redrawLoopTimeMillis <= 0 ) { printPlayground(); } } /** * Prints the playground to the console with hop counts. */ private synchronized void printPlayground() { if ( _oldState != toState( _checkerboard ) ) { int the1stWidth = (_checkerboard.getGridHeight() + "").length() + 2; TableBuilder theBuilder = new TableBuilder().withTableStyle( TableStyle.SINGLE_HEADER_SINGLE_BODY ).withRowWidth( -1 ); theBuilder.addColumn().withColumnHorizAlignTextMode( HorizAlignTextMode.CENTER ).withColumnWidth( the1stWidth ); for ( int x = 0; x < getGridWidth(); x++ ) { theBuilder.addColumn().withColumnHorizAlignTextMode( HorizAlignTextMode.CENTER ).withColumnWidth( _columnWidth ); } String[] theRows = new String[getGridWidth() + 1]; theRows[0] = ""; for ( int x = 0; x < getGridWidth(); x++ ) { theRows[x + 1] = "" + x; } theBuilder.printHeader( theRows ); String[] theColumns = new String[getGridWidth() + 1]; P ePlayer; for ( int y = 0; y < getGridHeight(); y++ ) { theColumns[0] = "" + Character.valueOf( (char) ('a' + y) ); for ( int x = 0; x < getGridWidth(); x++ ) { ePlayer = _checkerboard.atPosition( x, y ); if ( ePlayer != null ) { theColumns[x + 1] = _spriteFactory.createInstance( ePlayer.getStatus(), this ); } else { theColumns[x + 1] = ""; } } theBuilder.printRow( theColumns ); } theBuilder.printTail(); System.out.println(); _oldState = toState( _checkerboard ); } } /** * Creates a pseudo hash code from the current {@link Checkerboard} status. * * @param aCheckerboard The {@link Checkerboard} for which to create the * hash code. * * @return The according hash code. */ private int toState( Checkerboard aCheckerboard ) { StringBuilder theBuilder = new StringBuilder(); for ( P ePlayer : _checkerboard.getPlayers() ) { theBuilder.append( ePlayer.getPositionX() ); theBuilder.append( ePlayer.getPositionY() ); theBuilder.append( ePlayer.getStatus() ); if ( ePlayer.getStatus() != null ) { theBuilder.append( ePlayer.getStatus().hashCode() ); } } return theBuilder.toString().hashCode(); } /** * {@inheritDoc} */ @Override public int getColumnWidth() { return _columnWidth; } /** * {@inheritDoc} */ @Override public void setColumnWidth( int aColumnWidth ) { _columnWidth = aColumnWidth; } /** * {@inheritDoc} */ @Override public ConsoleCheckerboardViewer withColumnWidth( int aColumnWidth ) { setColumnWidth( aColumnWidth ); return this; } // ///////////////////////////////////////////////////////////////////////// // INNER CLASSES: // ///////////////////////////////////////////////////////////////////////// }