• Post Reply Bookmark Topic Watch Topic
  • New Topic

Object Oriented Logic Operation Simulator  RSS feed

 
Dennis Von Valkenburgh
Ranch Hand
Posts: 126
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello all,
I have to create a program that simulates Logic Operations (AND, OR, XOR, etc.) that is based on a Grid (My idea was to use an array). There are Logic Blocks that I have to construct as objects, which have to be placed onto the Grid to then Simulate the outcome. Each Block has connections to other blocks once placed on the grid, depending on how they are situated. These connections are defined for each block in its object definition. Some blocks have one input on the left side, and an output on the right side. Other blocks have one input on the left, and only outputs on all other sides, etc. Another attribute of the Blocks is their Orientation which is defined by 0, 1, 2, 3. 0 is the natural state of the blocks, 1 is rotated 90 degrees left, 2 is rotated 180 degrees to the left and so on. When they are rotated the connections obviously have to follow suit.

So far, based on the Blocks I have to create, I created an abstract parent class that incorporates the attributes that ALL Blocks have, such as the state of their connections (either 0, 1, or "open". I was thinking of using 9 for "open" to be able to use int datatype). Then I created another layer of 4 different classes that separate the blocks further into transport blocks (only transport the condition of the input to all outputs), modifier blocks (modify inputs), Constant blocks (Blocks that are always either 0 or 1), and InOut Blocks (an Input Block, the start of simulation path, and an Output Block, the end of the simulation path).
Why so many layers of classes? Its required in the assignment.

Is my thinking a good start for this project?
And what could a viable concept for the Rotation of the blocks be?
 
Stephan van Hulst
Saloon Keeper
Posts: 7932
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I wouldn't use ints to represent the rotation. Use an enum, maybe with values such as ROTATE_0, ROTATE_90, ROTATE_180 and ROTATE_270. Give them rotateClockwise() and rotateCounterClockwise() methods that return the appropriate value for a specific constant. You can also add an enum Side with values LEFT, RIGHT, TOP, BOTTOM, which you can use to query a Gate for its in- and output pins. The result is obviously dependent on the type of gate, and the rotation of a gate. Make use of the Optional class to indicate that a pin is present on a specific side.
 
Stephan van Hulst
Saloon Keeper
Posts: 7932
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I imagine you could also have an enum Signal, with values LOW and HIGH, and even an enum PinType with values INPUT and OUTPUT.

You will find that enums are far more expressive and convey the intent of the application much better than primitives like int do.
 
Dennis Von Valkenburgh
Ranch Hand
Posts: 126
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
For some context this is the code we were given to start with:
First the Interface:



Then the Class GridFactory:



From these we are to build our own Simulator.
I now created the following Enum:



And here my own implementation class:



Does this look right so far? How do I integrate the Enum with the RealizeGrid class?
 
Dennis Von Valkenburgh
Ranch Hand
Posts: 126
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephan van Hulst wrote:I wouldn't use ints to represent the rotation.

Thats the thing, it is required by our assignment to use ints...
 
Stephan van Hulst
Saloon Keeper
Posts: 7932
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The class EnumRotation has no use. Use Rotation directly. I don't know what Ober represents.

The fact that you have to implement some interface, doesn't mean you can't use an internal representation that makes more sense. You can just adapt the internals to the interface whenever needed. For now, forget the interface, and just focus on how you would implement a grid like this.




You can then implement different kinds of cells, and wrap them in RotatedCell to rotate them correctly. This is how an AND-gate could look like:
 
Dennis Von Valkenburgh
Ranch Hand
Posts: 126
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ober is the parent class of all logic blocks (Cell in your example)



One question:
Your Method "hasPin()", is it supposed to check whether a connection is made by an input and output of 2 blocks?
 
Stephan van Hulst
Saloon Keeper
Posts: 7932
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
No. It simply checks whether a single cell has a connector or a given side. The responsibility of checking for connections between two cells lies with the Grid class.

You shouldn't use names like Ober, because they only express structural relationships, and have no actual semantic value. Organism is a super type of Animal, but there is no value in naming it SuperType.
 
Dennis Von Valkenburgh
Ranch Hand
Posts: 126
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Where does private final Map<Side, Signal> pinValues; from the AndGate Class fit in?
I know from the form that it is a generic, but how is it used here?

The Side variable in the Interface, should I create an Enum for that to hold the different possible inputs/outputs?

And would you say it would be better to use an Inerface to define Cell and not a class like I did?
 
Dennis Von Valkenburgh
Ranch Hand
Posts: 126
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
And how do I initialize input1, input2 and output?
 
Campbell Ritchie
Marshal
Posts: 56223
171
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Don't declare three variables all on the same line. You can declare them as three lines. You didn't show your Side class so I don't know the details.… only your spelling will have to be better than mine.
There is something very wrong with methods which set something on a SideHow do you know the Side reference passed will point to a Side in this Cell object? The following code definitely requires that:-
 
Stephan van Hulst
Saloon Keeper
Posts: 7932
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You need a way of remembering what signal was set for a given input pin. This is what the map is for. Here's an implementation to give you an idea:

At some point you'll find that many gates have a lot in common, so you may make a base AbstractGate class that implements all the Cell methods, and has an abstract Map<Side, Signal> applyLogic(Map<Side, Signal> inputs) method that converts input signals to output signals.

The Side enum is simple and only contains constants for LEFT, RIGHT, TOP and BOTTOM. The Signal enum contains LOW and HIGH, and some logical operators like not(), and(Signal), or(Signal), xor(Signal), etc... If you want, you can use a boolean instead of Signal, but I think Signal is more expressive. It's probably easier to use if your Signal enum has a way to convert between the two types: boolean toBoolean() and static Signal forBoolean(boolean).

I used an interface for Cell, because it makes your application flexible. When you write an abstract base class, you should almost always write an interface it implements, and use the interface in your code wherever you can. For instance, most of the Cells will be some implementation of AbstractGate, but the Grid should contain a Cell[][] field, because you never know if you want to implement your Cell in a completely different way than the AbstractGate class does.
 
Stephan van Hulst
Saloon Keeper
Posts: 7932
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Campbell Ritchie wrote:How do you know the Side reference passed will point to a Side in this Cell object?


The reason I did that, is because Side is stateless. Cells need to check whether they have a pin on the given side.
 
Campbell Ritchie
Marshal
Posts: 56223
171
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think I ought to shut up then, rather than coming to this thread late.
 
Stephan van Hulst
Saloon Keeper
Posts: 7932
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, I agree with what you wrote (and I'll take the part about having fields on separate lines to heart), but in this case the setSignal() method is more similar to a mapping operation, where the Side is a simple key. This is not a requirement, but my own design. If instead of Side, a Cell would have stateful Pins, I agree that a method setSignal(Pin pin, Signal sig) would be horrendous.
 
Campbell Ritchie
Marshal
Posts: 56223
171
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I like the idea of a Map, but didn't see any Maps in the code, which might be what confused me. Is the any way to signal that a side is shared between adjacent cells, or am I causing confusion again?
 
Stephan van Hulst
Saloon Keeper
Posts: 7932
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
My idea was to make that the responsibility of the Grid. Side can have an opposite() method, and when the Grid wants to check if two Cells connect, it matches side x with side x.opposite() of the cell on side x.
 
Dennis Von Valkenburgh
Ranch Hand
Posts: 126
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Is the following right?



Each connection (Input/output) can have 3 states: 0, 1, and open.
Connections are open when they have not yet been assigned either the 0 or 1 value.
Does it then make sense to map all the sides to open in the beginning?
And then have the methods run over the cell to map the correct values?
 
Stephan van Hulst
Saloon Keeper
Posts: 7932
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Let's say you call pinValues.get(side). What does it mean when you get null? What does it mean when you get OPEN? What's the difference?

Try to relate to real world concepts. A digital signal is either 0 or 1, what is an 'open' signal?.
 
Dennis Von Valkenburgh
Ranch Hand
Posts: 126
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This, so far, is my Signal Enum:


Is it ok?
 
Dennis Von Valkenburgh
Ranch Hand
Posts: 126
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
In the Side Enum you used top, right, left, bottom.
Yet in the ANDGate Class you call on the Side Variables "input1Side, input2Side, outputSide".

How did you mean to connect these? Or did you mean top instead of input1Side and so on.
 
Stephan van Hulst
Saloon Keeper
Posts: 7932
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Note that your methods are not static, so your logic can be directly applied to 'this' enum. They also seem needlessly complex. Just compare the current enum to the argument. You can also use boolean operators directly if you associate Signals with a boolean value:

The AndGate is just a loose component. It's like a chip that has pins on some sides. It doesn't know about other components, it just wants to know where its own pins are. input1Side stores the side of the first input pin. Naming a variable after its value is not useful: Side top = Side.TOP; doesn't tell us anything interesting.

This might make it more clear. Calling new AndGate(LEFT, RIGHT, TOP); will create a new AND gate with an input pin on the left of the component, an input pin on the right of the component, and an output pin on the top of the component. Does that make more sense?

Making the actual connection between two components is not the responsibility of the components in this case, Grid is going to be responsible for that.
 
Dennis Von Valkenburgh
Ranch Hand
Posts: 126
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
For the Signal Enum I used ints: LOW(0), HIGH(1), OPEN(9).
The reason for that is that it is required by the assignment to declare them as "0, 1, Open (For the Open I just use the number 9 to be able to use ints)".

Also: our AND Gate has 3 Inputs. Most of the time it will just have two active inputs with the third input doing nothing. But we also have to have the capability to have the AND gate react to 3 inputs (1, 1, 1 => 1 | 1, 1, 0 => 0 | etc.)

Now my question would be: Since I do not use boolean for LOW and HIGH, is the comparison still possible? for example in this:



Can I still use the exclamation mark on ints as well?
 
Stephan van Hulst
Saloon Keeper
Posts: 7932
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If you really want to go this way (and I really would discourage you from using the OPEN constant, or integer values), then you can use the bitwise operators:
 
It is sorta covered in the JavaRanch Style Guide.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!