May 01, 2025

Dynamic Programming Modules

I’m a big fan of object-oriented programming and also like functional programming. Take a look at this article on NodeJS in the enterprise. I am strong advocate of polyglot systems and that you want to design a system for the various roles and you need to consider technologies often associated with those roles.

A truly modular system will enable you to “shove together” modules and the system will appropriately handle them. This was left quite ambiguous because depending on the type of components it is possible that in any given system you only may have a single instance. Like for instance a logger. If you have some experience with Java logging libraries you may find seen issues when more than one implementation is found on the classpath. Similarly, you may have issues with regular packages that don’t interact well together because they have conflicting dependency versions. Having the ability to have the system determine at runtime based on a whole bunch of priority parameters that impact the functionality. If you are familiar with Spring Boot you should be extremely familiar with this sort of flexibility. When you get used to that customization you get this feeling that you can do anything with your code. This functional capacity is an extension of traditional polymorphism. Having the ability to assume multiple traits of an interface is fairly limited when you pin down the code that is available. Creating your modules to be truly self contained is the basis of good enterprise architecture and the key to most problems you run into. The recent version of Java 9 takes this approach and improves some of the challenges. Providing clear definitions as to what the module requires and what it contains is what the new modularity functionality provides. It’s very nice, but you can accomplish a lot without that.

A jar is just a compressed archive with whatever content you put into it.
Traditionally utilizing a manifest was the way you had to specify if you want to directly invoke a jar what class should be invoked. That is still of course the case. However, you can have a jar that only holds classes without any main class.

There is a great library that can facilitates scanning the classpath in addition to many other things like a jar sitting on a local or remote file-system. This library is extremely fast because it reads the java class files interpreting the bytecode without actually loading the files.

Let’s say I have an enterprise system that connects event-driven applications. I want to allow the user to be able to upload a new jar file to s3. From that jar the system may dynamically load and unload modules and subscribe/unsubscribe to specific events.
With java I can dynamically pull the jar object.

While not everyone loves the ins and outs of the JVM classpath, the ability to dynamically load modules or executable code is an extremely valuable capability.

I’ve created a tic-tac-toe application that is available here. I specifically wrote this code to be as functional and procedural as possible. I wanted to make the design very “simple” and only focused on the simplest tic-tac-toe game. You can say there isn’t anything wrong with this code, it is well documented.

This is the board of a 3×3. This is how the indicies are numbered. They are zero index based.

3×3

0 1 2
3 4 5
6 7 8

4×4

0  1  2  3
4  5  6  7
8  9  10 11
12 13 14 15 

5×5

0  1  2  3  4
5  6  7  8  9
10 11 12 13 14
15 16 17 18 19
20 21 22 23 24

The only configurable option is the size of the board. It defaults to a 3×3 board, but you can create the board with a different size. The approach used for calculating if their is a win or a draw is not the most efficient method. I decided to favor cleaner more readable code over efficiency that would be negligible. In fact, unless the board were to be several thousands larger than a traditional board the difference would be minuscule. Let’s look at the getWinner() function:

public char getWinner() {
    // Iterate through each winning algorithm
    // For most of them then iterate for each row
    for(int x=0; x < size; x++) {
        char[] chars = getCells(WinningPath.HORIZONTAL, x);
        char c = getCharIfAllSame(chars);

        if(c != empty) {
            return c;
        }

        chars = getCells(WinningPath.VERTICAL, x);
        c = getCharIfAllSame(chars);

        if(c != empty) {
            return c;
        }
    }

    char[] chars = getDiagonal1();
    char c = getCharIfAllSame(chars);
    if(c != empty) {
        return c;
    }

    chars = getDiagonal2();
    c = getCharIfAllSame(chars);
    if(c != empty) {
        return c;
    }

    return empty;
}

For both horizontal and vertical we iterate through each algorithm one time per dimension. The other two calls are for the two diagonals. The getCells(WinningPath path, Integer offset) call returns back an array of chars according to the specified algorithm. Following that call the getCharIfAllSame(char[] chars) function is invoked to evaluate whether or not the returns chars are all the same or not. These two steps make the code longer but much more flexible and easier to understand. Here is the getCells() call. It’s a very simple dispatcher pattern.

public char[] getCells(WinningPath wp, int... args) {
    char[] t = new char[size];
    for(int x=0; x < size; x++) {
        int c = 0;
        switch(wp) {
            case HORIZONTAL:
                c = getRow(args[0], x);
                break;
            case VERTICAL:
                c = getColumn(args[0], x);
                break;
            case DIAGONAL:
                c = getDiagonal(args[0], x);
                break;
        }
        t[x] = board[c];
    }
    return t;
}

The actual individual algorithm is broken down based on the strategy.

The getRow() function looks like this:

// Row 0 -> 0 1 2
// Row 1 -> 3 4 5
// Row 2 -> 6 7 8
public int getRow(int row, int offset) {
    return offset + (row * size);
}

// Column 0 -> 0 3 6
// Column 1 -> 1 4 7
// Column 2 -> 2 5 8
public int getColumn(int column, int offset) {
    return column + (size * offset);
}

public int getDiagonal(int diag, int offset) {
    if(diag == 0) {
        if(offset == 0) {
            return 0;
        } else {
            return (size+1) * offset;
        }
    } else {
        if(offset == 0) {
            return size - 1;
        } else {
            return (size - 1) * (offset + 1);
        }
    }
}

This quite simply is a function that will return the index of the row cells for the inputted row and offset. This function will handle different sized boards, not just the standard 3×3.

I haven’t made the time to continue the more advanced version of this. I began working on a very generalized architecture. Even-though the implementation is not complete, I am very happy with the architecture thus far and know when the time is there to complete it, it will be very modular and powerful.

Let’s start looking at the major packages and their interfaces and classes of the oop package:

  • oop
    • class Main
    • class TicTacToe extends SequentialTurnBasedBoardGameImpl
  • oop/board - Relating to the physical board
    • interface Board
    • interface TicTacToeBoard extends Board
    • class TwoDimensionalTicTacToeBoard implements TicTacToeBoard
  • oop/game - Relating to the game state
    • status
      • enum GameStatus
      • interface GameEvent extends GameStatusDetails
    • turn
    • interface Game extends Serializable, TurnHistory, GameOutcome
    • interface SequentialTurnBasedBoardGame extends BoardGame - Adds the notion of a single player for the Turn.
  • oop/player
    • interface Player extends Serializable
    • interface PlaySelector - Essentially a Iterator<Player>. Determines the initial Player and subsequent Player. Allows for games where the players would rotate who goes first.
  • oop/position
  • oop/strategy - Relates to different ways to evaluate a winner or loser or other game state
    • interface WinningStrategy extends Comparable
    • class DiagonalStrategy implements WinningStrategy
    • class DrawStrategy implements WinningStrategy
    • class HorizontalStrategy implements WinningStrategy
    • class VerticalStrategy implements WinningStrategy
    • interface StrategyScanner - Used to find and handle the strategies

The first thing that was clear to me was that I wanted to define a Game.

public interface Game extends
	Serializable,
	TurnHistory,
	GameOutcome {

	UUID getId();

	LocalDateTime getCreated();

	LocalDateTime getUpdated();

	Turn start();

	void stop();
}

I thought about games and wanted to separate the game play from the rules and the state of the game. Most games are turn-based. Meaning that one player goes and then another, etc. What defined the order of the turns or who goes first is something entirely different. The TurnHistory interface is quite simple:

public interface TurnHistory {
	List<Turn> getTurns();
}

It is a container to hold all references to a Game’s Turn.

public interface Turn<T extends Action> extends Serializable, Comparable<Turn> {
	UUID getId();

	LocalDateTime getCreated();

	LocalDateTime getUpdated();

	Optional<T> getAction();

	Player getPlayer();

	default boolean turnCompleted() {
		return getAction().isPresent();
	}
}

A Turn is created and updated when the Turn is acted or updated. A Turn has a reference to its defined Player and the Action if it has been invoked or not.

public interface Action<T extends Action> extends Serializable, Comparable<T> {
	UUID getId();

	LocalDateTime getCreated();
}

An Action is simply a defined entity that is created and uniquely defined. With Tic-Tac-Toe or many BoardGame in mind I created a Move which is a type of Action.

public interface Move<T extends Move> extends Action<T> {
	UUID getId();

	Position getPosition();

	Player getPlayer();
}

The Move interface adds the Position that the Player moved. A general Position interface is:

public interface Position extends Serializable {
	boolean isEmpty();

	boolean isOccupied();

	<T> T getOccupant();

	<T> void setOccupant(T occupant);

	void clearOccupant();
}

This is built on the premise that only a single occupant may occupy a Position at any given moment. For Tic-Tac-Toe I have created a concrete class called TwoDimensionalPosition which is based on a traditional euclidian coordinate system.

The BoardGame interface extends the Game interface. Of course the BoardGame interface also extends the Board interface which is actually a marker or empty interface. I decided that a Board would be a generic entity on its own outside of the context of the Game. Also, the Board doesn’t actually define its coordinates or game. The TicTacToeBoard extends the BoardGame interface. The concrete class TwoDimensionalTicTacToeBoard extends the TicTacToeBoard. This was specifically designed to handle a typical game of Tic-Tac-Toe.

Now let’s look at the TicTacToe class. It extends the SequentialTurnBasedGame interface. Quite simply the TicTacToe implementation binds together the rules dictated by the WinningStrategy implementations. The rest of the system functions with a publish/subscribe event model. The idea is to generalize the system to enable listening for certain event types and react to them. This approach makes it very easy to create custom rules. I ran into the classic overthinking problem. I was making this project for instructional purposes and therefore had very flimsy requirements. I wanted to allow for even complex games like realtime strategy games and the like. I could easily “finish” this if I set some concrete restrictions, but it was challenging to correctly identify the exact nature of the interfaces.

The sequential part ensures that every turn occurs in order one after the other. Traditional rules of Tic-Tac-Toe as far as I know doesn’t have a time limit on a turn. I wanted it to be possible that a Turn should be capable of having a time limitation. How would the game handle? It should be possible to say that the Turn was either forfeited or timed-out. Ideally the model shouldn’t require changes to the base classes. Proper design should allow for the Turn to be modular enough. Certain turn based games like card games or Catan have entire sets of logic that are subject to that turn. We need a way to have nested turns that would separate the actions in the turn from the turn itself. You see this can get very complex. My rule of thumb has been and always been if you are accurate enough to the reality you are almost never wrong. This logic forced me to rethink a Turn and separate it from an Action. A Turn was a container for the current player. I even forgot after some time why did the Action also have a Player getPlayer() method on its interface. The idea is that the Action may be invoked by a different Player than the parent Turn. Suffice to say this can get very complex. The major thing that is well designed is the pub/sub approach.

http://blog.cleancoder.com/uncle-bob/2018/04/13/FPvsOO.html