Example Code

Othello - A demonstration of Inheritance in LVOOP

Code and Documents

Attachment

Download All

   Game Category Winner


Category: Games

Summary:

This example project aims to demonstrate the basics of inheritance in LVOOP.  The included classes model a 2 player board game on a common 8x8 board, the board used for Checkers and Chess, etc.  There are a number of games played with similar rules on a similar board, so inheriting the general methods of the Board Game to the specific cases of particular games seemed like a natural fit for OO inheritance. LVOOP has some catching up to do with traditional LabVIEW in terms of the quantity and diversity of examples available. Having more LVOOP examples should help bring new users into the OO-in-LV fold.

For the example, I've chosen to implement one of my favorites: Othello. ( http://en.wikipedia.org/wiki/Reversi ). Othello is played with a set of pieces that are white on one side and black on the other.  Players take turns placing pieces on the board, any of the opponents pieces that form a line between the new piece and an existing current players' piece get flipped.  A player must make a move if any exist.  If you have no available moves, play passes back to the other player. The winner has the most pieces when neither player has legal moves.

The example game gives players the option to select between 2-player Othello and 1-Player vs. a computer opponent.  The class hierarchy could conceivably be extended to make other games available.  I'll leave an implementation of Chess as an exercise for the reader .

This code was written over the course of the last week and a half expressly for this contest.

Function:

The top level VI coordinates the public methods of "8x8 Board Game.lvclass".  Since Othello is a special case of an 8x8 Board Game class, an Othello class inherits from Board Game. A special case of Othello would be a 1-player vs. computer version, so the Othello-AI class inherits from Othello.

When the program runs, an object of the Board Game class is written to a shift register in the main loop.  When the user selects a game, the object on the class wire is replaced with an object for the selected game.

Methods in the parent class (Board Game) are mostly overridden, but only where necessary: "Forfeit" and "Next Player" take pretty much the same form in all games, so the general case is coded into the parent class and children can override it if necessary.   On the other hand, "Handle Move" has no meaning in the parent class, and is so dependent on a particular game's rules, that it is an empty method in the parent and must be overridden in child classes.

I try to highlight a few features of LVOOP and LV2010 in the code:

  • I make pretty extensive use of data member access through property nodes.  I find that when accessing multiple data members at once, the block diagram gets pretty messy and the property nodes (can) really help fight block diagram sprawl.
  • Where possible, overriding methods call the parent method first, this prevents unnecessary duplication of existing code and speeds development.

I make a few compromises from the full-on LVOOP implementation.  Clearly "Player" and "Turn" would make pretty good classes, and there are other possibilities as well.  I wanted to keep the number of classes to a minimum to focus the attention on the inheritance structure that the Game/Othello/Othello plus AI classes revolve around.

This project is written in LV2010, due to use of new features for LVOOP in 2010 (esp. property node accessors).

**Updated to add LV2009SP1 source code**

Steps to execute code:

To play the game:

  1. Download and unzip the project, and run "Main Example - Play a board game.vi"

To inspect the classes:

  • Open the project and select View->Labview Class Hierarchy from the menu bar.
  • Right click on each class and select Properties.  Take a look at Inheritance especially.
  • click on a Board Game member VI on the Main block diagram to open the VI: see how you get the option to also open override VIs of the child classes.
  • check out how easy it is to extend a class by calling the parent method in the override VI: see New Game.vi in all three main classes.


Screenshots:

FP Screenshot.png

VI Snippet:

Othello - Main snippet.png

A producer-consumer (events) architecture coordinates the game logic around the method calls.

Project attached below

-Barrett
CLD

Example code from the Example Code Exchange in the NI Community is licensed with the MIT license.

Comments
FraggerFox
Active Participant Active Participant
Active Participant
on

Cool man!

This one is really good. Though I don't have LV2010, from the explanation you've given, this one really seems good.

I think its not, but is it still possible to post this in LV2009?

-FraggerFox!
Certified LabVIEW Architect, Certified TestStand Developer
"What you think today is what you live tomorrow"
altenbach
Knight of NI Knight of NI
Knight of NI
on

Are you sure about the rule: "A player must make a move if any exist, and the winner has the most pieces when one player has no legal moves."

This is different to the wikipedia article, that states: "Players take alternate turns. If one player cannot make a valid move, play passes back to the other player. When neither player can move, the game ends."

The AI does not seem to handle the situation where the computer cannot move and must pass. Here's a situation on my first try: the AI cannot move but white has plenty of moves left. Still, the AI thinks that all white moves are now illegal.

According to "your" rule, this should be a win for white and according to the wikipedia rule, it should be white's move.

Instead, the program simply no longer accepts any moves.

Othello.png

I haven't looked at the code, but the AI seems to move pretty randomly. Is there any intelligence?

blawson
Active Participant
Active Participant
on

Fraggerfox -

I think I will save it back to 2009.  I did a quick conversion and it works, I just need to find some free time to clean up the mess from converting.

Altenbach -

Thanks for the constructive criticism, I appreciate it.  The ruleset I used is what I wrote down in my notes... I think I used a site that was less clear than Wikipedia when I started out.  I've updated the code to follow the official rules.

By all means, please look at the code, this is an *example* contest, after all. Keep in mind that the focus is on the LVOOP structures, not challenging AI opponents.

-Barrett

-Barrett
CLD
altenbach
Knight of NI Knight of NI
Knight of NI
on

blawson wrote:


                       

The ruleset I used is what I wrote down in my notes... I think I used a site that was less clear than Wikipedia when I started out.


                   

Well I still have an original Othello board from the seventies and played it once in a while back then.

I was under the impression that the difference between Othello and Reversi was the starting position, with Reversi having the same color pieces next to each other and Othello having the colors crossed. The wikipedia article is less clear about that, though, but what do they know?

Anyway, good luck.

blawson
Active Participant
Active Participant
on

Mine's from the eighties, out at the family vacation cabin, even got to play against my wife this weekend.  She prefers scrabble .  I thought from what I read that reversi's starting position is empty, but the players are limited to the central 2x2 on their first turn or possibly first two turns.  I also read something about each player starts Reversi with 32 two-color chips and must stop playing if they run out, where Othello rules are essentially that chips are communal.  I suspect that MS shipped Reversi with Windows rather than Othello for trademark reasons.

Well, I had fun writing it, I hope people have fun poking around with it.

Thanks!

-Barrett

-Barrett
CLD
wirebirdlabs
Member
Member
on

The Board Tile class has a member called "Get Entire Board" - wouldn't this method's functionality be better collapsed into "Read whole board" in the Board Game class? Use of Typecast inside "Array index from CtlRef.vi" is sensitive to datatype and not robust - use Coerce to Type instead. Using typecast between U32 and I32, I know, I know, is not that bad, and it's highly unlikely the representation of either property will change to 64-bit anytime soon. In "Write Element of Possible Moves.vi", syntactically I prefer a nested IPE structure (this is style, performance is not an issue). Finally, I saw several places where "8" was hard-coded (for 8x8). Instead, you could more generically name the class "Othello" (rather than "Othello 8x8") and have board size as a private data member. Five stars for impeccable style and a great demo.

blawson
Active Participant
Active Participant
on

-The original intent of BoardTile was to keep BoardGame unencumbered by the actual board's implementation, but then I would need to make some child classes of BoardTile for each game... And I felt that was too complicated for my intended demonstration.  So the game classes in this design do get saddled with supplying their own piece images.

-I hadn't seen the Coerce to Type discussion, thanks for the pointer.

-IPE's are very nice for prettying up code, and I'll probably use them more frequently now that I have stbe's IPE QD plugin.

-8's: Again, a decision to keep the code simple for better readability.  It's not the only thing that would need changing to support different board sizes.  Naming the class with "8x8" was an attempt to be super explicit about the board shape, and hint at the other games which would be easy to implement.

Thanks for the review, I learned something new!

-Barrett

-Barrett
CLD
Contributors