I started working on a project in C# using Windows Forms, making a sea battle game.
How my game works:
When the program starts, a dialog is displayed where we have two options:
-Player vs player
-Player vs computer
After that dialog, another dialog appears where we choose the following:
4×4
8×8
10×10
(what dimensions do we want the fields to be when we place the ships)
Then, after that selection, a dialog appears with the display of those fields and it looks like this:
For example I chose 4×4:
4×4 field
I will give an example and what is the output:
I choose a 4×4 field for placing ships (one size 1 ship and two size 2 ships are placed on a 4×4 field)
First I was offered a size 1 ship.
I set it at the following coordinates i=0, j=0 (i is a column, j is a row) Size 1 ship placed
Then after that it’s the turn of the size 2 ship, and now I need to place that ship.
I place the first part of the ship at i = 2, j =0, and place it successfully. First part of size 2 ship placed
Then I try to place another part of that ship (size 2) at i = 2, j =1, unsuccessfully it says “you cannot place a part of the ship at this position try again” unsuccessful
I also try to set that other part of the ship to i = 3, j = 0, but it still fails. unsuccessful
I’ve been trying to solve the problem for an hour now, but I don’t know where the error/bug is and why it’s not working.
Here is the code of that class:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace oop_template
{
public partial class ShipPlacementForm : Form
{
private int tableSize;
private List<Ship> ships;
private List<Ship> placedShips;
private Button[,] tableButtons;
private int currentShipIndex;
private Ship currentShip;
private bool horizontalPlacement;
public List<Ship> PlacedShips
{
get { return placedShips; }
}
public ShipPlacementForm(int tableSize, List<Ship> ships)
{
this.tableSize = tableSize;
this.ships = ships;
this.placedShips = new List<Ship>();
CustomInitializeComponent();
// Initialize placement of the first ship
this.currentShipIndex = 0;
SetCurrentShip();
deleteButton.Enabled = false; // Disable delete until at least one ship is placed
}
private void CustomInitializeComponent()
{
this.SuspendLayout();
// Dynamically create buttons for the table fields
tableButtons = new Button[tableSize, tableSize];
for (int i = 0; i < tableSize; i++)
{
for (int j = 0; j < tableSize; j++)
{
tableButtons[i, j] = new Button();
tableButtons[i, j].Size = new Size(30, 30);
tableButtons[i, j].Location = new Point(30 * i, 30 * j);
tableButtons[i, j].Click += new EventHandler(TableButton_Click);
this.Controls.Add(tableButtons[i, j]);
}
}
// Label for displaying the current ship
this.currentShipLabel = new Label();
this.currentShipLabel.Location = new Point(30 * tableSize, 30);
this.currentShipLabel.AutoSize = true;
this.Controls.Add(this.currentShipLabel);
// Button for confirmation
this.confirmButton = new Button();
this.confirmButton.Text = "Confirm";
this.confirmButton.Location = new Point(30 * tableSize, 60);
this.confirmButton.Click += new EventHandler(ConfirmButton_Click);
this.confirmButton.Enabled = false; // Disabled until all ships are placed
this.Controls.Add(this.confirmButton);
// Button for deleting a ship
this.deleteButton = new Button();
this.deleteButton.Text = "Delete Ship";
this.deleteButton.Location = new Point(30 * tableSize, 90);
this.deleteButton.Click += new EventHandler(DeleteButton_Click);
this.deleteButton.Enabled = false; // Disabled until at least one ship is placed
this.Controls.Add(this.deleteButton);
// Set form size
this.ClientSize = new System.Drawing.Size(30 * (tableSize + 2), 30 * tableSize);
this.Name = "ShipPlacementForm";
this.Text = "Ship Placement";
this.ResumeLayout(false);
this.PerformLayout();
}
private void TableButton_Click(object sender, EventArgs e)
{
Button clickedButton = sender as Button;
if (clickedButton == null)
return;
int x = clickedButton.Location.X / 30;
int y = clickedButton.Location.Y / 30;
if (CanPlaceShipPart(x, y))
{
PlaceShipPart(x, y);
currentShip.Positions.Add(new Point(x, y));
if (currentShip.Positions.Count == 1)
{
// First part of the ship is placed, wait for the second part to determine orientation
deleteButton.Enabled = false; // Disable deletion until the entire ship is placed
}
else if (currentShip.Positions.Count == 2)
{
// Determine the orientation of the ship based on the first two positions
horizontalPlacement = currentShip.Positions[0].Y == currentShip.Positions[1].Y;
}
// Check if the ship is complete
if (currentShip.Positions.Count == currentShip.Size)
{
placedShips.Add(currentShip);
currentShipIndex++;
if (currentShipIndex < ships.Count)
{
SetCurrentShip();
}
else
{
currentShipLabel.Text = "All ships are placed.";
confirmButton.Enabled = true;
deleteButton.Enabled = true;
}
}
}
else
{
MessageBox.Show("You cannot place a ship part on this position. Please try again.");
}
}
private void DeleteButton_Click(object sender, EventArgs e)
{
currentShipLabel.Text = "Click on any part of the ship you want to delete.";
foreach (var ship in placedShips)
{
foreach (var position in ship.Positions)
{
tableButtons[position.X, position.Y].Click += DeleteShipClick;
}
}
}
private void DeleteShipClick(object sender, EventArgs e)
{
Button clickedButton = sender as Button;
if (clickedButton == null)
return;
int x = clickedButton.Location.X / 30;
int y = clickedButton.Location.Y / 30;
Ship shipToDelete = null;
foreach (var ship in placedShips)
{
if (ship.Positions.Contains(new Point(x, y)))
{
shipToDelete = ship;
break;
}
}
if (shipToDelete != null)
{
DeleteShip(shipToDelete);
currentShipLabel.Text = $"Place a ship of size {shipToDelete.Size}";
currentShip = shipToDelete;
currentShipIndex = ships.IndexOf(shipToDelete);
foreach (var position in shipToDelete.Positions)
{
tableButtons[position.X, position.Y].Click -= DeleteShipClick;
}
}
deleteButton.Enabled = placedShips.Count > 0;
}
private void DeleteShip(Ship ship)
{
foreach (var position in ship.Positions)
{
tableButtons[position.X, position.Y].BackColor = default(Color);
tableButtons[position.X, position.Y].Enabled = true;
}
placedShips.Remove(ship);
ships.Insert(currentShipIndex, ship); // Return the ship to the list for re-placement
}
private void ConfirmButton_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.OK;
this.Close();
}
private void SetCurrentShip()
{
currentShip = ships[currentShipIndex];
currentShip.Positions.Clear();
currentShipLabel.Text = $"Place a ship of size {currentShip.Size}";
deleteButton.Enabled = placedShips.Count > 0;
}
private bool CanPlaceShipPart(int x, int y)
{
if (tableButtons[x, y].BackColor == Color.Gray)
return false; // The field is already taken
// Check continuity of ship placement
if (currentShip.Positions.Count > 0)
{
var lastPos = currentShip.Positions[currentShip.Positions.Count - 1];
// Check if the second part of the ship can be placed next to the first one
bool validHorizontalPos = (x == lastPos.X && Math.Abs(y - lastPos.Y) == 1);
bool validVerticalPos = (y == lastPos.Y && Math.Abs(x - lastPos.X) == 1);
if (validHorizontalPos || validVerticalPos)
{
// Check if the adjacent field is taken
foreach (var (dx, dy) in new[] { (-1, 0), (1, 0), (0, -1), (0, 1) })
{
int nx = x + dx;
int ny = y + dy;
if (nx >= 0 && nx < tableSize && ny >= 0 && ny < tableSize)
{
if (tableButtons[nx, ny].BackColor == Color.Gray)
return false; // The adjacent field is taken
}
}
return true;
}
else
{
return false;
}
}
return true;
}
private void PlaceShipPart(int x, int y)
{
tableButtons[x, y].BackColor = Color.Gray; // Color the field gray
tableButtons[x, y].Enabled = false; // Disable clicking on the same field again
}
private Label currentShipLabel;
private Button confirmButton;
private Button deleteButton;
}
}
Thank you for your time.
PS: sorry if I am grammatically incorrect somewhere, English is not my native language
Огњен Стојановић is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.