For my own personal amusement, I'm writing what I hope will be the foundation of a game to come later. At current, I'm working on the game "board". Please consider the following:
class Board
{
private Cube[,,] gameBoard;
public Cube[, ,] GameBoard { get; }
private Random rnd;
private Person person;
public Person _Person { get; }
//default constructor
public Board()
{
person = new Person(this);
rnd = new Random();
gameBoard = new Cube[10, 10, 10];
gameBoard.Initialize();
int xAxis = rnd.Next(11);
int yAxis = rnd.Next(11);
int zAxis = rnd.Next(11);
gameBoard[xAxis, yAxis, zAxis].AddContents(person);
}
}
And this:
class Person : IObject
{
public Board GameBoard {get; set;}
public int Size { get; set; }
public void Move()
{
throw new NotImplementedException();
}
public void Move(Cube startLocation, Cube endLocation)
{
startLocation.RemoveContents(this);
endLocation.AddContents(this);
}
public Person(Board gameBoard)
{
Size = 1;
GameBoard = gameBoard;
}
public int[] GetLocation()
{
int[] currentLocation;
var location =
from cubes in GameBoard.GameBoard
where cubes.GetContents.Contains(this)
select cubes;
}
}
I know this is so wrong it's probably not even funny, but this is the roughest of rough cuts.
I'm trying to get GetLocation to return the specific index of the Cube in which the Person is located. So that if the person is in Board.GameBoard[1, 2, 10] I'll be able to retrieve that location (probably as an int[] as listed above). However, at current, I'm unable to compile due to the following error:
Could not find an implementation of the query pattern for source type 'Cubes.Cube[*,*,*]'. 'Where' not found.'
I was pretty sure that LINQ should be able to query multi-dimensional arrays, but I haven't found any documentation on how to do it.
Any suggestions, or am I on the completly wrong track here?
LINQ does not see multidimential arrays as you want it to because they do not implement IEnumerable<T> (although single index arrays do, which is what surprises people). There are several workarounds: you can avoid LINQ for searching the cube or you can write an extension method of your own that does the more traditional walks.
This is a case where I wouldn't use LINQ do to the search, but more than that I probably would keep some references to the various playing pieces in a simple structure (probably a dictionary) that is easier to update and manage. As an idea, your piece object would know where it is on the board itself and could update the cube as it moved by removing itself from one cell and adding itself to another.
It would be important to know if a single cell can contain more than one piece: if so, each cell would need to be a list of some type as well (it appears that way in your code). And once you get to this point, if there are vastly fewer playing pieces than cells, I probably would never actually create the "cube" itself as a datastructure. It would be drawn and the pieces displayed via some Z order drawing algorithm that pulled directly from the piece list, rather than an array. This would depend on the style of game though: if the pieces have attributes and are small in number this would work. If the game is more like 3D Go or similar, then your original cube would make sense... it really depends on how much "personality" (and thus data) your pieces have.
Makes a lot more sense to me to move the int[] currentLocation declaration to the top level inside your Person class, and provide getter/setter methods. Then each Person stores its own location.
For the memory cost of 3 ints, you save yourself from having to query 1000 database entries every time you want to retrieve the person's location.
I think the Person should tell the board where he is, not ask the board. In otherwords, I would create a Location3D class (x,y,z), use that in a GamePiece class that all other things on the board inherit from. That stores location, then each peice knows it's location.
public class Location3D
{
public Location3D(int x, int y, int z) { X = x; Y = y; Z = z; }
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
}
public abstract GamePiece
{
public Location3d { get; set; }
public class Person: GamePiece // inherit GamePiece
{
// everything else about Person
}
public class Board
{
public Board()
{
person = new Person(this);
rnd = new Random();
gameBoard = new Cube[10, 10, 10];
gameBoard.Initialize();
int xAxis = rnd.Next(11);
int yAxis = rnd.Next(11);
int zAxis = rnd.Next(11);
var location = new Location3D(xAxis, yAxis, zAxis);
person.Location = location;
GetCubeAt(location).AddContents(person);
}
public Cube GetCubeAt(Location3D location)
{
return gameBoard[location.X, location.Y, location.Z];
}
public Cube GetCubeAt(int x, int y, int z)
{
return GetCubeAt(new Location3D(x,y,z));
}
}
Related
Okay I am trying to practice for an "rpg".
I created an array of monsters that you may encounter, and it will spit out one random monster to fight.
So since im ultra beginner, what do i do now? I am thinking that, for example, if it spits out zombie, it will have a set of variables/integers attached to it, the health and damage. So, the index [3] will have more information stored with it?
I just learned enums so i was also wondering if something like this would work better over an array or inheritance and polymorphism, since those would work but its much more code to write. I dont even know if C# has the capability to do what i want to do exactly and i need help.
string[] monsters = { "goblin", "dog", "ghoul", "zombie" };
Random random = new Random();
int randommonster = random.Next(0, monsters.Length);
This was the base to help you picture exactly what i wanted the array or enums to do, then values need to be attached to each monster/index.
C# will be fine for the job.
Create a set of classes of type Monster and add the values to the array.
Then generate a random index from the array of monsters.
Use the values from the Monster object at that index.
class Monster
{
public string Name { get; set; }
public int Health { get; set; }
public int Damage { get; set; }
public Monster(string name, int health, int damage)
{
Name = name;
Health = health;
Damage = damage;
}
}
Then use that class ...
Monster[] monsters =
{
new Monster("Goblin", 2, 3),
new Monster("Dog", 3, 4),
etc ...
}
Random random = new Random();
int monsterIndex = random.Next(0, monsters.Length);
Monster monsterInPlay = monsters[monsterIndex];
I have foreach loop that goes through an array of a class and has an if statement that uses one of the class' properties, however it doesn't work. I get this error:
Board.Boat.length cannot be accessed with an instance reference; qualify it with a type name instead.
How do you solve that here's the code. Keep in mind it still isn't finished.
using System;
using System.Collections.Generic;
using System.Numerics;
namespace BattleShip
{
class Board
{
class Boat
{
// This class is made for storing the meta-data of each individual boat
// Determines the start point
static int[,] pos = new int[xBoardSize, yBoardSize];
// Determines the direction of the boat (0 = horizontal, 1 = vertical)
static int direction = 0;
// Keeps track of the boat's size
static int length = 1;
// Keeps track if tile is hit or untouched
static int[] stateList;
// Searches fora oat object and
static Boat SearchForBoat (Vector2 coords, Boat[] database)
{
foreach (Boat boat in database)
{
for (int i = 0; i < boat.length; i++)
}
}
}
// These variables determine the size of the board
static int xBoardSize = 10;
static int yBoardSize = 10;
}
}
It's because length property is static. Such properties are rather class properites, while others are instance properties, i.e. static field are use with type (and the other with instantiated object of a class). In your case it should be Boat.length instead of boat.length.
Remark: you should consider those static properties, as length seems to me like it should depend on particular object, thus should not be static.
There error is telling you that you are trying to access a static property from an object instance.
foreach (Boat boat in database) // give me each real boat from database
{
for (int i = 0; i < boat.length; i++) // access an individual boat length
However, because length is static, technically the boat instance doesn't have a property called length.
I have taken the liberty to SRP (single responsibility principle) and normalize your code
The single responsibility principle is a computer programming
principle that states that every module, class, or function1 should
have responsibility over a single part of the functionality provided
by the software, and that responsibility should be entirely
encapsulated by the class, module or function.
As such it removed all your static guff
Use the static modifier to declare a static member, which belongs to
the type itself rather than to a specific object.
public class Board
{
// These variables determine the size of the board
public const int XBoardSize = 10;
public const int YBoardSize = 10;
// a board has an array of boats, seems logical
public Boat[] Boats { get; set; }
// a board can find boats on it
public Boat SearchForBoat(Vector2 coords )
{
foreach (var boat in Boats)
{
for (int i = 0; i < boat.Length; i++)
/// do stuff here
}
}
}
// concrete boat class, which you can make instances from
public class Boat
{
// notice not static, we are saying an individual "boat" can have these properties
public int[,] Pos = new int[Board.XBoardSize, Board.YBoardSize];
public int Direction { get; set; }
public int Length { get; set; } = 1;
public int[] StateList { get; set; }
}
The static member is callable on a class even when no instance of the class has been created. The static member is always accessed by the class name, not the instance name.
for (int i = 0; i < boat.length; i++) //wrong access static from an instance
for (int i = 0; i < Boat.length; i++) //correct access static from the type itself (class itlsef)
read here for more information
I've got multiple comments for your code:
1st static is to be considered as something unique. It is something like a global value shared by all object instances
From Microsoft documentation on static
The static member is callable on a class even when no instance of the class has been created. The static member is always accessed by the class name, not the instance name. Only one copy of a static member exists, regardless of how many instances of the class are created.
With that in mind your Boat class will become:
public class Boat
{
// This class is made for storing the meta-data of each individual boat
// Determines the start point
public int[,] pos = new int[xBoardSize, yBoardSize];
// Determines the direction of the boat (0 = horizontal, 1 = vertical)
public int direction = 0;
// Keeps track of the boat's size
public int length = 1;
// Keeps track if tile is hit or untouched
public int[] stateList;
}
Your boats should now be made part of your Board with a Has-A relationship:
public class Board
{
private Boat[] boats;
public Board(Boat[] boats) {
// initialize th boats for the specific game
this.boats = boats
}
Boat SearchForBoat (Vector2 coords)
{
foreach (Boat boat in boats)
{
for (int i = 0; i < boat.length; i++)
}
}
// These variables determine the size of the board
int xBoardSize = 10;
int yBoardSize = 10;
}
Then you need to initialize via a constructor and use the specific instances
I would like to design something that gets the distance between two things. However, these things can be manifest in many obnoxious forms.
Let's say we have a set of classes. (Not necessarily base and derived)
Cat, CoolCat, ReallyCoolCat
All of them have a way to access a position. I would like to write a function call 'DistanceBetween' that gets the distances between the cats.
I can make overloads:
public static float DistanceBetween(Cat cat1, Cat cat2)
{
return Mathf.Abs(cat1.position - cat2.position);
}
public static float DistanceBetween(CoolCat cat1, CoolCat cat2)
{
return Mathf.Abs(cat1.transform.position, cat2.transform.position);
}
// ... etc...
However, then I would have cases where I need to know the distance between a Cat and a CoolCat or the distance between a CoolCat and a ReallyCoolCat. That means...
public static float DistanceBetween(Cat cat1, CoolCat cat2)
{
return Mathf.Abs(cat1.position, cat2.transform.position);
}
public static float DistanceBetween(CoolCat cat1, ReallyCoolCat cat2)
{
return Math.Abs(cat1.tranform.position, cat2.kittyVariables.position);
}
// ... etc ...
But then it just seems arbitrary cause I can rearrange the order of my arguments and my function wouldn't work. So I have to make...
public static float DistanceBetween(CoolCat cat1, Cat cat2)
{
return Mathf.Abs(cat1.tranform.position, cat1.position);
}
public static float DistanceBetween(ReallyCoolCat cat1, CoolCat cat2)
{
return Math.Abs(cat1.kittyVariables.position, cat2.transform.position);
}
// ... etc ...
So This means the amount of code per cute kitties I make grows by n^2. This amount of code growth is not acceptable due to how many cute kitties I want to make. I cannot implement inheritance because my cute kitties (though similar in name) have very different features and are unique. (I could add doggies and the such too.) So what I am thinking is to create an interface 'IDistanceable' that says the implementing class has a 'Position' property and implementing it in each kitty. But this starts to seem like overkill though, all I wanted was something that can rearrange my arguments and make Func(a,b) equal to Func(b,a)...
I don't really know what to do... both solutions (write 500 functions or make interface and lots of junk) both seem wrong.
The interface will NOT work due to the inability to modify some of the cute kitty classes...
Please help me and my cute kitties! Thanks!
If you can't modify the classes, you're best off wrapping them in something you can modify. That way, you can centralize the class-specific logic in one place (the different constructors).
class CatWrapper
{
private int position { get; set; }
public CatWrapper(Cat cat) { ... }
public CatWrapper(CoolCat cat) { ... }
public CatWrapper(ReallyCoolCat cat) { ... }
public DistanceFrom(CatWrapper other) { ... }
}
This is a purely academic answer, since #Andrews Pilser's is far superior for almost any real-world project, but this will solve it for any class that has any conceivable way of representing a location. It makes heavy use of lambda-expressions, and generics, and requires no control over the underlying classes.
The code was written in LINQPad, so it may look a little odd, but it is standard C# (version 7) that can be snapped right in to Visual Studio. File available here.
This uses a Dictionary to store a ToPointConverter for any Type that can be converted to a Point. A ToPointConverter is created from a static method Create that accepts a lambda that returns a Point from the specific generic T.
As you can see, I provide 3 example "kitty" classes that each store their location in completely different ways. The main function creates a converter for each, storing it in the dictionary of converters, and then calculates the distance between the different combination of "kitties". (I may have gotten my distance function wrong, it's late, but that is a minor detail.)
It produces this output:
2.23606797749979
9.05538513813742
2.23606797749979
8.06225774829855
9.05538513813742
8.06225774829855
void Main()
{
//Define conversion functions for anything that can be converted.
converters.Add(typeof(KittyA), ToPointConverter<KittyA>.Create(kitty => kitty.Location));
converters.Add(typeof(KittyB), ToPointConverter<KittyB>.Create(kitty => new Point { X = kitty.X, Y = kitty.Y }));
converters.Add(typeof(KittyC), ToPointConverter<KittyC>.Create(kitty => kitty.MyLocation));
//Declare some kitties
var kitty1 = new KittyA { Location = new Point { X = 1, Y = 1 } };
var kitty2 = new KittyB { X = 3, Y = 2 };
var kitty3 = new KittyC { MyLocation = new Point { X = 2, Y = 10 } };
//Calculate the distances
GetDistance(kitty1, kitty2).Dump();
GetDistance(kitty1, kitty3).Dump();
GetDistance(kitty2, kitty1).Dump();
GetDistance(kitty2, kitty3).Dump();
GetDistance(kitty3, kitty1).Dump();
GetDistance(kitty3, kitty2).Dump();
}
private Dictionary<Type, IToPointConverter> converters = new Dictionary<Type, IToPointConverter>();
//A helper function that does the converts the passed objects in to Points, and calculates the distance between them.
private double GetDistance(object obj1, object obj2)
{
var point1 = GetConvrterFor(obj1).Convert(obj1);
var point2 = GetConvrterFor(obj2).Convert(obj2);
return Math.Sqrt(Math.Pow(point2.X - point1.X, 2) + Math.Pow(point2.Y - point1.Y, 2));
}
//Another helper that gets the IToPointConverter for the object instance passed in.
private IToPointConverter GetConvrterFor(object obj) => converters[obj.GetType()];
//This generic class stores a lambda expression that converters from T to a Point
public class ToPointConverter<T> : IToPointConverter
{
public static ToPointConverter<T> Create(Func<T, Point> conversion)
{
return new ToPointConverter<T>(conversion);
}
private ToPointConverter(Func<T, Point> conversion)
{
_conversion = conversion;
}
private Func<T, Point> _conversion;
public Point Convert(T obj) => _conversion(obj);
Point IToPointConverter.Convert(object obj) => Convert((T)obj);
}
//The non-generic interface for the converter (so different closed generic types can be stored in the same dictionary, and have their Convert method called.)
public interface IToPointConverter
{
Point Convert(object obj);
}
//Just a standard structure to hold a location. You would use whatever native location class your framework has.
public struct Point
{
public int X;
public int Y;
}
//Some example kitty classes
public class KittyA
{
public Point Location { get; set; }
}
public class KittyB
{
public int X { get; set; }
public int Y { get; set; }
}
public class KittyC
{
public Point MyLocation { get; set; }
}
This is not exactly what I am working with but I hope it makes a clear example:
public abstract class Shape
{
public int Area;
public int Perimeter;
public class Polygon : Shape
{
public int Sides;
public Polygon(int a, int p, int s){
Area = a;
Perimeter = p;
Sides = s;
}
}
public class Circle : Shape
{
public int Radius;
public Circle(int r){
Area = 3.14*r*r;
Perimeter = 6.28*r;
Radius = r;
}
}
}
In the main function I would have something like this:
Shape[] ThisArray = new Shape[5];
ThisArray[0] = new Shape.Circle(5);
ThisArray[1] = new Shape.Polygon(25,20,4);
My problem is that when I deal with ThisArray, I can't access values other than Area and Perimeter. For example:
if (ThisArray[0].Area > 10)
//This statement will be executed
if (ThisArray[1].Sides == 4)
//This will not compile
How can I access Sides from ThisArray[1]? I could access it if I did something like
Shape.Polygon RandomSquare = new Shape.Polygon(25,20,4) but not if it is in an array of shapes.
If I recall correctly this could be accomplished in C++ by doing something like
Polygon->ThisArray[1].Sides (I forget what this is called) but I do not know how do this in C#
If I can't do what I am trying to do, how can I circumvent this problem?
Thank you for reading through what I intended to be short, any help is appreciated.
You should use casting:
(ThisArray[1] as Shape.Polygon).Sides
Note that you should make sure the underlying object instance actually IS a Polygon, otherwise this will raise an exception. You can do this by using something like:
if(ThisArray[1] is Shape.Polygon){
(ThisArray[1] as Shape.Polygon).Sides
}
Basically I created this skill class:
public class skill
{
public int level { get; set; } //Level of the skill (average of sub-skills' levels)
public int arrayCount { get; set; } //Number of skill/levels in the below arrays
public string[] sub_skills { get; set; } //Names of sub-skills ([0] connect's to levels' [0], etc.)
public int[] sub_levels { get; set; } //Levels of sub-skills ([0] connect's to names' [0], etc.)
void set(int l, int a, string[] sub_s, int[] sub_l)
{
this.level = l; //Sets the skill's level to the input'd l value
this.arrayCount = a; //Sets the skill's array count to the input'd a value
for (int i = 0; i < arrayCount; i++) //For loop to assign each value in both arrays
{
this.sub_skills[i] = sub_s[i]; //Assigns each input'd sub_s array value to each sub_skills value
this.sub_levels[i] = sub_l[i]; //Assigns each input'd sub_l array value to each sub_levels value
}
}
}
Now I have created another class, player:
public class Player
{
public string name { get; set; } //Name of Player
public int level { get; set; } //Player's combat level (average of combat-related skills' levels)
//Start Thievery skill block
string[] thief_s = { "lockpicking", "looting", "pickpocketing", "sneaking" }; //Array for thievery's sub-skill names
int[] thief_i = { 1, 1, 1, 1 }; //Array for thievery's sub-levels
skill thievery = new skill(); //Creates the skill of Thievery (stealing items / passing unnoticed)
//Start Melee skill block
skill melee = new skill(); //Creates the skill of Melee (close-range, strong combat)
//Start Archery skill block
skill archery = new skill(); //Creates the skill of Archery (long-range, weak combat)
//Start Magicka skill block
skill magicka = new skill(); //Creates the skill of Magicka (medium-range, medium combat)
//Start Craftship skill block
skill craftship = new skill(); //Creates the skill of Craftship (retreivement then creation of items from materials)
}
How can I use the set() method from the skill class inside the player class, for a specific skill created inside the player class? For example you can see how I have the skill thievery created there, already with its arrays for it's sub-level's names and levels (variables in the skill class). How can I access thievery's set() function and also use the arrays in it to set thievery's variables? I've tried the line thievery.set(// insertvarshere) but my IDE keeps throwing errors. (I'm using Microsoft Visual Studio Ultimate 2010)
EDIT: Thanks everyone. For some reason setting the set() function to public didn't change anything. When I call thievery.set() my IDE throws red lines under thievery. I'm going to take Charles advice and make the sub-skills skills, and then, if it's possible, apply some sort of tag to them to mark them as part of the major skill. Is that possible, or must I create my own class/function etc. for a tag?
On the face of it, you need to make it public:
public void set(int l, int a, string[] sub_s, int[] sub_l) {
...
Then, for each skill instance, you can call it:
thievery.set( ... );
Where you want to call it, and with what parameter arguments, is up to you.
Unless I'm missing something here you'd need to make the set method visible by either making it public or building a new public method that called it. It's possible that you need an abstracted method that calls set the way you want it called so that it's used properly by consumers.
Where are you trying to call the set method in the Player class. You can only call the set method in another method or constructor of Player class. May be that is why you are getting errors.
Edit: You also need to add public for the method of course.