|
I meant how I can create a UserSubUser table. I need a C# model to create this table (Code-First approach). UserIDs in the UserSubUser table should be linked to the UserModel table.
|
|
|
|
|
No, they don't. You need to look up normalization, and apply dem rules to your database.
If all that is required is whitelisting, then just have a table with users who are allowed to message each other. You think from C#; but the layer your working in is SQL, where you need to think SQL. Normalize them tables, work from there.
Bastard Programmer from Hell
"If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
|
|
|
|
|
|
I've finished an application in C# using Visual Studio 2022 and need to make an installer for it. I used Microsoft Visual Studio Installer Projects extension and could create the installer which works fine. But I need something else: during instalation, it's necessary to create a folder, then a file and save this file into that folder. But I don't know how to do this in this installer. Does anybody has a solution for this? Thanks.
|
|
|
|
|
Your app should be able to create a folder and file; there's no reason for an installer to do it as you describe it ("the install works fine").
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
C# you try it's remain a fewer ways for you
|
|
|
|
|
I want to create a memory stream as follows
[1byte][4bytes][n bytes][4 bytes][n bytes][4 bytes][n bytes] ....ect
my first stream consisted of [0][12][Hello World.]
_packetWriter.WriteOpCode((byte)opCode);
_packetWriter.WriteMessage("Hello World.");
_client.Client.Send(_packetWriter.GetPacketBytes());
when I read it back I get the following, and when I look at the byte arrays I'm seeing some bytes from the previous chunk
10/09/2022 11:39:00 : Opcode Found With Value 0
10/09/2022 11:39:00 : Chunk Found With Value 12
10/09/2022 11:39:00 : Message Found With Value
Hello Worl
can anybody help
thanks madaxe
public class PacketWriter : BinaryWriter
{
public MemoryStream MemoryStream;
public BinaryWriter BinaryWriter;
public PacketWriter()
{
MemoryStream = new MemoryStream();
BinaryWriter = new BinaryWriter(MemoryStream);
}
public void WriteOpCode(byte opCode)
{
MemoryStream.WriteByte(opCode);
}
public void WriteNextChunckSize(int chunkSize)
{
BinaryWriter.Write((Int32)chunkSize);
}
public void WriteMessage(string message)
{
WriteNextChunckSize(message.Length);
BinaryWriter.Write(message);
}
public byte[] GetPacketBytes()
{
return MemoryStream.ToArray();
}
}
public class PacketReader : BinaryReader
{
private NetworkStream _memoryStream;
public PacketReader(NetworkStream memoryStream) : base(memoryStream)
{
_memoryStream = memoryStream;
}
public int ReadOpCode()
{
return _memoryStream.ReadByte();
}
public string ReadMessage(int chunkSize)
{
byte[] readMessage;
readMessage = new byte[chunkSize];
_memoryStream.Read(readMessage, 0, chunkSize);
var message = Encoding.ASCII.GetString(readMessage);
return message;
}
public int ReadChunkSize()
{
byte[] readChunkSize;
readChunkSize = new byte[4];
_memoryStream.Read(readChunkSize, 0, 3);
return BitConverter.ToInt32(readChunkSize, 0);
}
}
|
|
|
|
|
BinaryWriter.Write(string) writes a length-preceded string to the stream, with the length encoded as a variable-length integer (7 bits per block and a continuation bit). So some extra stuff appeared in your stream that you didn't count on.
BinaryWriter.Write(string) is most easily "mirrored" by using BinaryReader.ReadString in the decoder. Of course, you can also handle the length manually, but then you should probably also handle the encoding and write raw bytes to the stream to start with.
This is also wrong: _memoryStream.Read(readChunkSize, 0, 3); reading 3 bytes instead of 4. Why not use BinaryReader , it's simpler and less error prone.
By having written one extra byte per mistake (the extra length byte that BinaryWriter.Write(string) wrote, could have been more bytes for longer strings) and by having read one byte too few, a two byte discrepancy was created. Actually you should find that there are two unprintable characters at the start of your string, since it still should be 12 bytes, just not quite the right 12 bytes.
|
|
|
|
|
sure enough _memoryStream.Read(readChunkSize, 0, 4); fixed part of the problem and also changing the Write message as below fixed the issue.
but I want to use BinaryReader since I'm using BinaryWriter
the behavior I'm seeing is I can consecutively call ReadByte and it will read each byte in turn without me having to define position within the stream, which I don't understand.
so how do is use BinaryReader to read specific blocks of bytes, 2->6, and 7->19
thanks
Madaxe
public void WriteMessage(string message)
{
WriteNextChunckSize(message.Length);
byte[] byteArray = Encoding.UTF8.GetBytes(message);
BinaryWriter.Write(byteArray);
}
|
|
|
|
|
You can do some dummy reads of suitable sizes, discard the results, and then call the suitable Read method when the position of the stream is at the intended location. Or you can set the position of the underlying stream directly, and then read with the BinaryReader. Unfortunately both of these feel a bit like a hack, IMO there should have been some method on BinaryReader to skip a number of bytes, but that doesn't exist.
|
|
|
|
|
Hello,
I have a problem with a self programmed windows service for .Net 6 that inherits from BackgroundService:
namespace WooComMesserschmidt
{
internal class Worker : BackgroundService
{
private readonly HttpClient Client = new()
private string BaseAddress = string.Empty;
private readonly IConfiguration Configuration;
private string ConfigFile = string.Empty;
private readonly Dictionary<string, dynamic?> _ConfigPar;
internal static Dictionary<string, string> ConfigPar = new();
private readonly ILogger<Worker> _logger;
public struct LogInfo
{
public ILogger<Worker>? Logger;
public string? LogFile;
public LogInfo(ILogger<Worker>? logger, string logfile)
{
Logger = logger;
LogFile = logfile;
}
}
public static LogInfo logInfo;
public Worker(ILogger<Worker> logger, IConfiguration configuration, Dictionary<string, dynamic?> configpar)
{
Configuration = configuration;
_ConfigPar = configpar;
_logger = logger;
Init();
}
...
In the method "Init()" relatively extensive tasks take place (on my PC it takes about 2 seconds). If these are through, it goes on here:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
if (int.TryParse(ConfigPar[cpQueryInterval], out int QueryInterval) == false)
{
QueryInterval = QueryIntervalStd;
Log.LogInformation(logInfo, $"Abfrageintervall konnte nicht ermittelt werden. Es wird daher der Standardwert von {QueryInterval} Millisekunden verwendet. Prüfen Sie die Angaben in der Parameterdatei.");
}
Log.LogInformation(logInfo, $"{Process.GetCurrentProcess().ProcessName} gestartet.");
Log.LogInformation(logInfo, $"Worker arbeitet mit Abfrageintervall von {QueryInterval} Millisekunden.");
while (stoppingToken.IsCancellationRequested == false)
{
await ProcessNewOrders();
await UpdateProducts();
Dhl_Polling();
await Task.Delay(QueryInterval, stoppingToken);
}
}
...
The service is supposed to fetch orders from an eShop every few minutes, update items and process DHL shipments.
Well, when I start the program manually in the command line (i.e. not as a service), everything works as expected. Now I have registered the program as a service and every time I try to start the service I get the following error: Error 1053: The service did not respond to the start or control request in a timely fashion
We started everything in Main:
private static async Task<int> Main(string[] args)
{
try
{
IHost host = Host.CreateDefaultBuilder(args)
.UseWindowsService(options =>
{
options.ServiceName = ServiceName;
})
.ConfigureServices(services =>
{
services.AddSingleton<Dictionary<string, dynamic?>> (_ConfigPar);
services.AddHostedService<Worker>();
})
.Build();
await host.RunAsync();
Log.LogInformation((LogInfo)_ConfigPar[cpLogInfo], $"{Process.GetCurrentProcess().ProcessName} beendet.");
if (Debugger.IsAttached == true)
{
Console.ReadLine();
}
}
catch (Exception ex)
{
Console.WriteLine($"{ex}{Environment.NewLine}{Environment.NewLine}");
...
How do I proceed to avoid this error?
Many thanks
René
|
|
|
|
|
That would suggest that your startup code is taking too long. You mention the Init method contains "extensive tasks" - I'd suggest moving some or all of those to the start of the ExecuteAsync method instead.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thank you. That's exactly what I did yesterday, but the error remained. I will try again, but now rested
|
|
|
|
|
OK, problem solved. The error message had driven me astray and I was looking in the wrong place for the cause of the error. Now I proceeded systematically step by step: at the very beginning, the service crashes without doing anything. The error was due to the "displayname" of the service - this may be maximum 80 characters long, while I used 110 characters. I didn't know that and the error message also said something completely different.
Thanks for your help! The weekend is saved!
René
|
|
|
|
|
Repo: https://github.com/Charles-CarM/Battleship
I am currently building my battleship console application in C#. I have prior experience
building projects with Vanilla JS and in React. I went through a tutorial on C# and could
grasp most of the concepts pretty well. I have jumped into project building because I know
this is where the maximum amount of growth will be as a developer. With that being said I
will lay out the issues arising in my application.
requirements
* the ship has a length of 5
* ship will be randomly assigned on a 10X10 grid
* when the ship is hit five times it is sunk and game is over
I am having trouble choosing the best way to implement the 10x10 gameboard grid. With
some searching on the web I have came across the DataTable class, which allows for rows
and columns to be set in a table(I believe this to be the better approach), and I have attempted
to get them displayed in the Console below. Also I know that I can create a 10x10 grid with
a 2D array using int[,] grid = [10,10]; however I have realized that I can't assign the random values for the ship with an already populated array. I would like to get some feedback on how
I can move forward with creation of the gameboard, and random assignment of the ship on the board.
I know this post and my code are a little messy so please excuse me on that part. Any solutions or suggestions you recommend for me moving forward are welcomed and greatly appreciated. Hope you are very well wherever you may be.
using System.Data;
namespace Battleship
{
class Program
{
static void Main(string[] args)
{
GamePlay ship = new GamePlay("ten", "fast ship", 350);
Console.ReadLine();
GreetUser();
DataTable gameBoard = new DataTable("Battleship");
DataColumn columnA = new DataColumn("A");
DataColumn columnB = new DataColumn("B");
DataColumn columnC = new DataColumn("C");
DataColumn columnD = new DataColumn("D");
DataColumn columnE = new DataColumn("E");
DataColumn columnF = new DataColumn("F");
DataColumn columnG = new DataColumn("G");
DataColumn columnH = new DataColumn("H");
DataColumn columnI = new DataColumn("I");
DataColumn columnJ = new DataColumn("J");
gameBoard.Columns.Add(columnA);
gameBoard.Columns.Add(columnB);
gameBoard.Columns.Add(columnC);
gameBoard.Columns.Add(columnD);
gameBoard.Columns.Add(columnE);
gameBoard.Columns.Add(columnF);
gameBoard.Columns.Add(columnG);
gameBoard.Columns.Add(columnH);
gameBoard.Columns.Add(columnI);
gameBoard.Columns.Add(columnJ);
DataRow row1 = gameBoard.NewRow();
DataRow row2 = gameBoard.NewRow();
DataRow row3 = gameBoard.NewRow();
DataRow row4 = gameBoard.NewRow();
DataRow row5 = gameBoard.NewRow();
DataRow row6 = gameBoard.NewRow();
DataRow row7 = gameBoard.NewRow();
DataRow row8 = gameBoard.NewRow();
DataRow row9 = gameBoard.NewRow();
DataRow row10 = gameBoard.NewRow();
row1["A"] = 0;
row1["B"] = 0;
row1["C"] = 0;
row1["D"] = 0;
row1["E"] = 0;
row1["F"] = 0;
row1["G"] = 0;
row1["H"] = 0;
row1["I"] = 0;
row1["J"] = 0;
gameBoard.Rows.Add(row1);
gameBoard.Rows.Add(row2);
gameBoard.Rows.Add(row3);
gameBoard.Rows.Add(row4);
gameBoard.Rows.Add(row5);
gameBoard.Rows.Add(row6);
gameBoard.Rows.Add(row7);
gameBoard.Rows.Add(row8);
gameBoard.Rows.Add(row9);
gameBoard.Rows.Add(row10);
for(int j = 0; j < gameBoard.Rows.Count; j++)
{
for (int i = 0; i < gameBoard.Columns.Count; i++)
{
Console.WriteLine(gameBoard.Columns[i].ColumnName + " ");
Console.WriteLine(gameBoard.Rows[j].ItemArray[i]);
}
}
Console.ReadLine();
string coords;
int[,] numberGrid =
{
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
{ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 },
{ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 },
{ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 },
{ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50 },
{ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60 },
{ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70 },
{ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80 },
{ 81, 82, 83, 84, 85, 86, 87, 88, 89, 90 },
{ 91, 92, 93, 94, 95, 96, 97, 98, 99, 100 }
};
int[,] freshGrid = new int[10, 10];
for(int j = 0; j < freshGrid.Length; j++)
{
coords = Convert.ToString(j);
Console.Write(coords);
}
Console.ReadLine();
Console.WriteLine(freshGrid[3,4]);
Console.ReadLine();
Random random = new Random();
int newShip = random.Next();
Console.ReadLine();
Console.WriteLine("\nEnter guess: ");
int guess = Convert.ToInt32(Console.ReadLine());
Console.WriteLine($"\nYou guessed: {guess}");
Console.ReadLine();
}
static void GreetUser()
{
Console.WriteLine("Welcome to Battle! press Enter ");
Console.ReadLine();
Console.WriteLine("Enter username: ");
string username = Console.ReadLine();
Console.WriteLine($"\nLet's begin {username}!");
}
}
}
|
|
|
|
|
Why are you using a DataTable? It's a bit of a sledgehammer to crack a nut ...
You need a 10 x 10 area of "squares" which can contain four values: Empty, Ship, Hit, and Miss. So the simplest way to do that is you create an enum that has all of those values:
public enum Square
{
Empty,
Ship,
Hit,
Miss,
}
You can then create an array of that:
Square[,] MyBoard = new Square[10,10]; Or two:
Square[,] HisBoard = new Square[10,10]; You can now reference any particular Square via indexes:
if (MyBoard[x, y] == Square.Ship)
{
MyBoard[x, y] = Square.Hit;
...
} Create a method to clear a board:
public static Square[,] Clear(Square[,] board)
{
for (int x = 0; x < board.GetLength(0); x++)
{
for (int y = 0; y < board.GetLength(1); y++)
{
board[x, y] = Square.Empty;
}
}
return board;
} And you can start getting ready for a new game:
Square[,] MyBoard = new Square[10,10];
Square[,] HisBoard = new Square[10,10];
Clear(MyBoard);
Clear(HisBoard); Then just write another method to load your ships in: it accepts a board as a parameter, calls Clear. and then decides where to put the ships. (Initially, I'd try to write it using "single space" ships to make the code easier, then start working on the more complex shapes you really need).
In fact what I'd do is more complex than that: I'd encapsulate the Square array in a class called Board, several ship classes (Carrier, BattleShip, Cruiser, Submarine, Destroyer) derived from a base Ship class) and let it handle the mundane stuff so that most of the time you are manipulating Board objects:
MyBoard.place(myDestroyer, x, y, Orientation.Horizontal);
MyBoard.Bomb(6, 7); But if you haven't reached classes and instances yet then a basic array will be fine.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Thanks Griff for taking the time to read my post and provide meaningful feedback.
Haha I will opt for the nutcracker instead of the sledgehammer moving forward.
I was experimenting with the DataTable class due to the appeal of Rows/Columns in
a table, but that's not the best approach as you've laid out. I follow what you are
saying with the 10x10 area of squares that have the four possible enum values.
Then calling the Square to create the array for the game board. Using the if/else logic to Referencing the specific squares. Next creating the nested x,y for loops to clear the board, and then being able to start the new game by calling an instance of the Square[10,10] grid for each
player.
I follow you on creating a method to load the ships into, and at first trying single space ships(get that working ) before moving onto more complex logic with the ship lengths.
I'll have to do a deeper dive on encapsulating the Square array in a Board class, then a base Ship
class within to create the ships, but this seems like the best approach to implement.
Yeah I haven't had much practice with classes and instances up to this point, but have a surface
level understanding of them.
I am mostly just repeating back to you what you've told me in this post, but it's extremely
helpful for my understanding and guiding me along the way.
Thanks again Griff!
|
|
|
|
|
You're welcome!
If you get stuck, just ask again - we're all pretty willing to help.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I am a little bit further along in my Battleship app although
not as far as I'd hoped to be.
So I setup the 10x10 representations with the enum
Square class and values on the board
It feels like I am running into issues with the CheckGuess
Method in the location where I am calling it from, and also
with the values it's returning after the player enters their guess.
I know that I can change TheBoard values because I have done
so in the current code and wrote it out at the bottom with the
changed values displayed. I can't quite understand why those
same values don't show up when the players guess gets passed
into the CheckGuess Method.
{explained as best as possible to my knowledge}
Please help if you have free time
GitHub - Charles-CarM/Battleship[^]
namespace ConsoleBattle
{
public class Program
{
public enum Square
{
Water,
Miss,
Ship,
Hit,
}
public static void Main(string[] args)
{
bool finished = false;
string message;
Square[,] TheBoard = new Square[10, 10];
Welcome();
Console.WriteLine("X: 0 - 9");
Console.WriteLine("Y: 0 - 9");
Console.WriteLine("Enter your guess: X, Y");
while (!finished)
{
TheBoard[7, 7] = Square.Ship;
TheBoard[7, 5] = Square.Ship;
string guess = Console.ReadLine();
void CheckGuess(int x, int y)
{
if (TheBoard[x, y] == Square.Ship)
{
Console.WriteLine(TheBoard[x, y] = Square.Hit);
}
else if (TheBoard[x, y] == Square.Water)
{
Console.WriteLine(TheBoard[x, y] = Square.Miss);
}
else if (TheBoard[x, y] == Square.Miss)
{
Console.WriteLine(message = "you already missed here");
}
else
{
Console.WriteLine(message = "this spot was hit already");
}
Console.ReadLine();
}
try
{
int xPos = Convert.ToInt32(guess.Split(',')[0]) - 1;
int yPos = Convert.ToInt32(guess.Split(',')[1]) - 1;
if (xPos > 9 || yPos > 9)
{
message = "You are off the board, try again!";
}
CheckGuess(xPos, yPos);
}
catch
{
message = "Unable to process coordinates";
}
finished = true;
}
Console.WriteLine(TheBoard[7, 7]);
Console.WriteLine(TheBoard[7, 5]);
}
private static void Welcome()
{
Console.WriteLine("Welcome to Console Battle!");
Console.WriteLine("Enter username: ");
string username = Console.ReadLine();
Console.WriteLine($"\nLet's begin {username} press Enter!");
Console.ReadLine();
}
}
}
|
|
|
|
|
OK ... first off, to play battleships you need at least two boards: one with your ships on, one with his.
So write your methods with that in mind! If you don't, when you come to add the second board, you have to mess around with the existing, tested, working code to get it to work with extra boards. And remember, on the "hardware" version of the game, you have a total of four boards: Your ships / his hits, your hits his ships; and the same pair for him.
Guilty Gadgets Battleships Sea Battle Traditional Family Fun Combat Strategy Board Game : Amazon.co.uk: Toys & Games[^]
While you can do it with just the one, it's a clumsy solution that only saves about 10 * 10 * 4 * 3 bytes and makes your code a lot clumsier.
And don't declare methods inside other methods: it makes the code clumsy and hard to read.
I'd start with a class: give it a board area, and add the CheckGuess method to that. Then create four instances of the class in your main method.
public class BattleshipsBoard
{
private Square[,] TheBoard = new Square[10, 10];
public Square CheckGuess(int x, int y)
{
...
return whatTheSquareContained;
}
}
...
public static void Main(string[] args)
{
BattleshipsBoard myShips = new BattleshipsBoard();
BattleshipsBoard hisShips = new BattleshipsBoard();
BattleshipsBoard myGuesses = new BattleshipsBoard();
BattleshipsBoard hisGuesses = new BattleshipsBoard();
... Now all the boards are independant and you can query any of them the same way:
if (myShips.CheckGuess(hisX, hisY) == Square.Ship)
{
... Or
if (hisShips.CheckGuess(myX, myY) == Square.Ship)
{
... Your code becomes more readable, and easier to work with.
Give it a try!
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Hello there!
Yeah that slipped my mind that there are four representations of the board in the physical version. I definitely realize it's better to have two boards instead of just one. (original assigned spec for this project was a single player version with one ship of five values). I've decided to move forward with the dual ship design like you suggested (it makes more sense).
I had tried to declare the method outside of the Main, but I wasn't able to access TheBoard
So I have created a GameBoard class, and then created TheBoard
namespace ConsoleBattle
{
public class Program
{
public static void Main(string[] args)
{
GameBoard playerA = new GameBoard();
GameBoard playerB = new GameBoard();
GameBoard playerAGuesses = new GameBoard();
GameBoard playerBGuesses = new GameBoard();
bool sunk = false;
string message;
Welcome();
Console.WriteLine("X: 0 - 9");
Console.WriteLine("Y: 0 - 9");
while (true)
{
Console.WriteLine(playerA.AddShip());
Console.ReadLine();
while(!sunk)
{
try
{
Console.WriteLine("Enter your guess: X, Y");
string guess = Console.ReadLine();
int xPos = Convert.ToInt32(guess.Split(',')[0]) - 1;
int yPos = Convert.ToInt32(guess.Split(',')[1]) - 1;
if (xPos > 9 || yPos > 9)
{
Console.WriteLine(message = "You are off the board, try again!");
}
playerA.CheckGuess(xPos, yPos);
}
catch
{
Console.WriteLine(message = "Unable to process coordinates");
}
Console.ReadLine();
}
Console.WriteLine(message = "You sunk the ship!");
Console.WriteLine("Play Again? [Y or N]");
string answer = Console.ReadLine().ToUpper();
if (answer == "Y")
{
continue;
}
else if (answer == "N")
{
return;
}
else
{
return;
}
}
}
private static void Welcome()
{
Console.WriteLine("Welcome to Console Battle!");
Console.WriteLine("Enter username: ");
string username = Console.ReadLine();
Console.WriteLine($"\nLet's begin {username} press Enter!");
Console.ReadLine();
}
}
}
When I call my playerA.CheckGuess(xPos, yPos) it is working as intended
in regards to getting the correct value or message back in the console.
I am able to enter my guess iteratively(which I was struggling with)
I have came up with a quasi solution for the ship assignment, but it only
seems to assign one ship value on the board when I wish to have five. Any
suggestions on how I can get five ships assigned?
Cheers for all the help so far,
namespace ConsoleBattle
{
public class GameBoard
{
public enum Square
{
Water,
Miss,
Ship,
Hit,
}
private Square[,] TheBoard = new Square[10, 10];
public Square[,] CheckGuess(int x, int y)
{
if (TheBoard[x, y] == Square.Ship)
{
Console.WriteLine(TheBoard[x, y] = Square.Hit);
}
else if (TheBoard[x, y] == Square.Water)
{
Console.WriteLine(TheBoard[x, y] = Square.Miss);
}
else if (TheBoard[x, y] == Square.Miss)
{
string message1 = "you already missed here";
Console.WriteLine(message1);
TheBoard[x, y] = Square.Miss;
}
else
{
string message2 = "this spot was hit already";
Console.WriteLine(message2);
TheBoard[x, y] = Square.Hit;
}
return TheBoard;
}
public Square[,] AddShip()
{
Random random = new();
string direction;
int x = random.Next(0, 9);
int y = random.Next(0, 9);
if (x < 4)
{
direction = "right";
}
else if (x > 4)
{
direction = "left";
}
else
{
direction = "left,right";
}
if (y < 4)
{
direction += "down";
}
else if (y > 4)
{
direction += "up";
}
else
{
direction += "up,down";
}
direction = direction.Split(',')[random.Next(0, direction.Split(',').Length)];
if (direction == "up")
{
for (int i = y; i < y - 4; i--)
{
TheBoard[i, y] = Square.Ship;
}
}
else if (direction == "down")
{
for (int i = y; i < y + 4; i++)
{
TheBoard[i, y] = Square.Ship;
}
}
else if (direction == "left")
{
for (int i = x; i < x - 4; i--)
{
TheBoard[x, i] = Square.Ship;
}
}
else
{
for (int i = x; i < x + 4; i++)
{
TheBoard[x, i] = Square.Ship;
}
}
return TheBoard;
}
}
}
|
|
|
|
|
OK. Let's get complicated ... but not too much, and it'll make life easier later.
Do you know what an abstract class is?
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I have a surface level understanding of abstract classes. I know that it has to do with inheritance however I
have not used/implemented one before.
|
|
|
|
|
That's a good start.
OK, you have a board class, what do you put on the board?
In the real game, you don't add "single square" ships: you add 4 x Destroyer (two squares), 3 x submarines (three), 2 x Battleships (four) and 1 x Carrier (five).
So why not create an abstract base class Ship, which is inherited by the concrete classes Destroyer, Submarine, Battleship, and Carrier?
The abstract class has properties Length and Name which the concrete classes implement. The Name is so you can say "you sank my Destroyer!" without knowing which concrete class it is, and the Length says how many squares it takes.
Add a Add method to your board which accepts a Ship, a top left coordinate, and an orientation (NSEW) and modify your Hit method to see if it's sunk.
This way, the board doesn't need to know what ship it is, and it enforces rules like "you can't put it there because it hang over the side" and such like.
Have a think about it - I know it sounds complicated, but it's really pretty easy when you get the hang of it and it really does make your code easier to write and modify!
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I've added the abstract Ship class within my Gameboard class below
Does it seem like it's headed in the right direction?
abstract class Ship
{
public string Name;
public int Length;
}
class Destroyer: Ship
{
}
class Submarine : Ship
{
}
class Cruiser : Ship
{
}
class Battleship : Ship
{
}
class Carrier : Ship
{
}
|
|
|
|
|