Battleship Puzzle

[Home]   [Puzzles & Projects]    [Delphi Techniques]   [Math topics]   [Library]   [Utilities]

 

Search

Search WWW

Search DelphiForFun.org

As of October, 2016, Embarcadero is offering a free release of Delphi (Delphi 10.1 Berlin Starter Edition ).     There are a few restrictions, but it is a welcome step toward making more programmers aware of the joys of Delphi.  They do say "Offer may be withdrawn at any time", so don't delay if you want to check it out.  Please use the feedback link to let me know if the link stops working.

 

Support DFF - Shop

 If you shop at Amazon anyway,  consider using this link. 

     

We receive a few cents from each purchase.  Thanks

 


Support DFF - Donate

 If you benefit from the website,  in terms of knowledge, entertainment value, or something otherwise useful, consider making a donation via PayPal  to help defray the costs.  (No PayPal account necessary to donate via credit card.)  Transaction is secure.

Mensa Daily Puzzlers

For over 15 years Mensa Page-A-Day calendars have provided several puzzles a year for my programming pleasure.  Coding "solvers" is most fun, but many programs also allow user solving, convenient for "fill in the blanks" type.  Below are Amazon  links to the two most recent years.

Mensa 365 Puzzlers  Calendar 2017

Mensa 365 Puzzlers Calendar 2018

(Hint: If you can wait, current year calendars are usually on sale in January.)

Contact

Feedback:  Send an e-mail with your comments about this program (or anything else).

Search DelphiForFun.org only

 

 

Problem Description

 Here is a solitaire version of the classical Battleships game where, in addition to the ship quantities and types, you are supplied with the number of ship parts hidden in each row or column and a few preplaced ship parts.

Background & Techniques

I found this Battleship Puzzle in one of my favorite puzzle books:  "Logical Puzzles", 2006, ChartWell Publishers.  It is apparently out of print, but a few new and used copies are available at the above Amazon link as of this date (June, 2009) . There are about 10 puzzles of this type in the book, two of which have been implemented here.

For each puzzle, the upper grid displays the number of ships and the number which have not yet been displayed on the board for each ship type.  The lower grid is the playing board and represents the "sea".  The first row displays the total number of ship parts in each column and the number which are currently displayed separated by a "/".  Row values are displayed in the first column.   A few ship parts will be initially displayed in their proper location. 

 You can use PrntScrn button or a window capture feature of any image processing program to print the puzzle if you want to tackle it with pencil and paper.  To play on-screen, click the start square where you wish to add  a ship.  A popup menu will allow you to select the ship to add - only those which will fit at this location will be available.   Double-clock a ship on the board to remove it.  

When all ships have been displayed, the "counts" column  and row will have equal "total" and "displayed" values and the "Available" column in the upper grid will display all zero values.,   

Non-programmers are welcome to read on, but may want to skip to the bottom of this page to download executable version of the program.

Notes for programmers

The data model for this puzzle turned out to be more complicated than I recognized when I started working on it. 

We have ship types with properties like Name, Length, Total #, and the Available #.   I made a TShipRec record type to hold this information.  The Ships array  of TShipRec records contains the information for a specific puzzle.     When a ship is placed, additional fields containing location and orientation (vertical or horizontal) must be associated with each individual ship.  I chose to use the BoardGrid cells to contain a 3 character representation of the ship type index in the Ships array, the orientation and an indication of which part this cell represents. See below for details.   Using the cell for this info makes it easy to draw the proper shape in each cell and also to count the number of parts used in each column and row.     

Each puzzle contains some ship parts which are initially displayed.  These parts must be identified so that they do not block out adjacent cells as normal placed parts would and so that they can be redrawn if the user defines a ship here and later removes it.   OriginalParts is an array of TPieceRec records with column, row, and TPartType information.  A Placement array of TPieceRec records was added to TShiprec records to hold the solution for each puzzle.          

 Lots of fiddly problems to solve as indicated by the list of the methods defined:

Private Methods

bulletprocedure FormActivateCall MakeDefaultCase to display the initial puzzle.
bulletprocedure ShipGridDrawCell:  OnDrawCell event exit to display upper grid cells. Using the ships[Arow] record it update shipname, total, and available columns and calls DrawLeftEnd, DrawMiddle, DrawRightEnd as appropriate to draw the ship for that row.   
bulletprocedure BoardGridDrawCell: OnDrawCell event exit to draw row and column values or the ship part defined for this cell or the "unavailable flag. "X".  Ships parts are encoded as 3 character text values as follows:
bullet  s[1] = ship number or '?' for an original part whcih ahs no assigned ship yet.
bullet  s[2] =  Direction: "H" or "V".  "?" if unknown or not applicable (e.g. Destroyer with a length of 1)
bullet  s[3] = Piece type
bullet"F" first piece of a multi-piece ship
bullet"L" Last piece of a multi-piece ship.
bullet"S" Square; middle pieces of a multi-piece ship.
bullet"C" Circle for a one piece Destroyer.  
bulletprocedure BoardGridClick  User clicked on a cell to indicate that he wants to add a ship here.  The first problem is to determine which cell was clicked.  Mouse.Cursorpos plus ScreenToClient and MouseToCellrect methods take care of that.  This routine examines each of the 7 possible ship orientations and sets the Visible property of a Popup menu TMenuItem for that ship to true or false accordingly.  Function CanPlaceShipAt does most of the work in determining which result applies.  PopupMenu1 is displayed at the end of the routine.
bulletprocedure PlaceShipClickCalled when the user clicks one of the menu items.  The Tag field of each visible menu item has been code to contain the index of the ship and direction entry, plus the row and the column where the ship is to be places  (tag=1000*column+ 10*row + menu item index). 
bulletprocedure BoardGridDblClick: User double clicked on a ship to remove that guess.
bulletprocedure DefcaseBtnClick:   Reinitialize the currently displayed case by call MakeDefaultCase procedure.
bulletprocedure CheckBox1Click: Display or hide indicators of cells which cannot receive ship parts.

Public Methods

bulletprocedure ShowMeBtnClick: Show the solution for current case.  Solution will display for one second on the first click, 2 seconds on the 2nd click, etc. 
bullet{procedure MakeDefaultCaseInitialize and display one of the two sample cases.
bulletprocedure MakeShipCalled by MakeDefaultCase to make a TShipRec from  passed parameters, add it to the Ships array and display it in the ShipsGrid StringGrid.  
bulletfunction CanPlaceShipAt;: Test location of the ship described by "ship" in direction "dir" at (c,r) and return true if it can be placed there. 
bulletprocedure DisplayShip: Place a ship of the specified type in the specified direction starting at the specified column and row.
bulletfunction IsOriginalpart): Check if the ship part in this square was part of the original puzzle definition and therefore must remain visible even if a ship containing it is removed from the board.
bulletprocedure UpdateAvailable: Decrement count of ship parts of specified type are still hidden after a ship is displayed, increment the available count for that type if  one is removed.
bulletfunction IsSolved:boolean: Check if all ships  have been displayed (available counts are all 0) and return True if so.
bulletprocedure UpdateUsed: Update column and row used counts - called after a ship has been added or removed fro m the board.
bulletprocedure FlagUnavailable: Identify and flag squares which cannot be hiding a ship
bulletProcedures which draw parts of a ship, oriented as specified in the cell text code:
bulletprocedure DrawLeftEnd
bulletprocedure DrawRightEnd
bulletprocedure DrawMiddle
 

 Running/Exploring the Program 

bullet Download source
bullet Download  executable

Suggestions for Further Explorations

bullet Ability to create, load, and save additional puzzles.
bullet Ability for the program to search for solutions.    

 

Original Date: June 7,2009

Modified: July 29, 2017

 

  [Feedback]   [Newsletters (subscribe/view)] [About me]
Copyright 2000-2017, Gary Darby    All rights reserved.