class bishop:unit {}
class knight:unit {}
class peasant:unit {}
void Battle(unit first, unit second, byte firstAmount, byte secondAmount)
{
System.Array sideA = System.Array.CreateInstance(first.GetType(),firstAmount);
for(int i=0; i< firstAmount; i++)
{
sideA[i] = ???
}
}
In my last question I had problems with creating dynamic arrays and here is my next step problem! :D
Passable types to this method bishop, knight and etc
Actually I don't understand how to initialize objects now. I can't type just sideA[i] = new first.GetType()(constructor parameters) and understand why, but I don't understand how to work around this
This is really, really bad design.
I assume, that your method Battle could be an instance method of a class Game, which you didn't provide to us.
Then I strongly recommend, that the Battle method should NOT create instances of objects it works with. It should only take them and do a battle action (compute lives, etc.).
So, create these objects elsewhere and then just post them to the method.
class Game
{
List<Bishop> bishops = new List<Bishop>() { new Bishop(..), ... };
List<Knight> knights = new List<Knight>() { new Knight(..), ... };
void Battle(List<Unit> first, List<Unit> second)
{
foreach(var f in first)
{
// get random unit from the second collection and attack him
f.Attack(GetRandomKnight(second));
}
}
public void StartBattle()
{
Battle(bishop, knights);
}
}
Also make sure that you use correct C# naming. A name of a class should start with a capital letter.
class Unit
{
public virtual void Attack(Unit enemy)
{
// default attack
Kick(enemy);
}
protected Kick(Unit enemy) { ... }
}
class Bishop : Unit { }
Ondrej has a good answer. Just to help you with arrays, you should never use reflection unless with a good reason. I see no reason why you should be doing it here. You can use the typical new keyword to instantiate an array.
void Battle(unit first, unit second, byte firstAmount, byte secondAmount)
{
var sideA = new unit[firstAmount];
for(int i=0; i< sideA.Length; i++)
{
sideA[i] = ???
}
}
If the instantiated array should really be of run time type of first, then you can rely on generics.
void Battle<T1, T2>(T1 first, T2 second, byte firstAmount, byte secondAmount)
where T1 : unit where T2 : unit
{
var sideA = new T1[firstAmount];
for(int i=0; i< sideA.Length; i++)
{
sideA[i] = ???
}
}
The totally dynamic way to settle things will be SetValue and GetValue:
void Battle(unit first, unit second, byte firstAmount, byte secondAmount)
{
var sideA = Array.CreateInstance(first.GetType(),firstAmount);
for(int i=0; i< firstAmount; i++)
{
sideA.SetValue(???, i);
sideA.GetValue(i); //to get the value back.
}
}
Basically you dont get indexer syntax for System.Array.
Related
I've been trying to google one interesting fact for me, but can't grab the terminology to fully understand this concept. For example, I create my own container which holds an array of Cars. For this specific array I want to implement "Place" method which inserts a given car in a specific order (place method has logic). And what I don't get is how it gets the job done. Here is the code:
public static void Main(string[] args)
{
Car[] result = new Car[entries];
result.Place(poppedValue);
}
public static class Extension
{
public static void Place(this Car[] array, Car car)
{
for (int i = 0; i < array.Length; i++)
{
if (array[i] != null)
{
if (array[i].Year > car.Year)
{
}
}
}
}
}
public class Car
{
public string Name;
public int Year;
public double MPG;
public Car(string name, int year, double mpg)
{
this.Name = name;
this.Year = year;
this.MPG = mpg;
}
public bool ComplexMaths()
{
return (Year * MPG) % 2 == 0;
}
}
What I don't get is that in "Place" method, first argument is "this Car[] array" and when calling the method "Place" you don't give that argument. C# understands it by using result.Place... It's so confusing. Maybe someone can say what happends under the hood and how this "function" of C# is called. I would like to read about it more. Thank you.
An extension method is a syntactic sugar that allows functionality to be added to existing classes even if sealed and without inheriting them.
This is also called a Trait.
In C# we use the keyword this for the first parameter to indicate that the static method, that must be in a static class generally called a Helper class, applies to the specified type.
For example:
public static class CarArrayHelper
{
public static void Place(this Car[] array, Car car)
{
}
}
Indicates that we can apply the Place method on all arrays of Car.
Hence we can write:
var myArray = new Car[10];
myArray.Place(new car());
This is exactly the same as:
CarArrayHelper.Place(myArray, new car());
The Car class does not implement Place, so we added the functionality without changing the Car class or creating a subclass.
Here are some tutorials:
C# - Extension Method (TutorialsTeacher)
Extension Methods in C# (C-SharpCorner)
Extension Method in C# (GeeksForGeeks).
So let's say I have a helper class which contains methods that manipulate a collection:
public static void RemainingDegreeDistribution(IGraph graph, float[,] distArr)
{
int total = 0;
for(int i=0; i < graph.Edges.Count; i++)
{
int startRemDeg = graph.Edges[i].Start.RemDeg;
int endRemDeg = graph.Edges[i].End.RemDeg;
distArr[startRemDeg,endRemDeg]++;
distArr[endRemDeg, startRemDeg]++;
total = total+2;
}
for(int i=0; i < distArr.GetLength(0); i++)
{
for(int j=0; j < distArr.GetLength(1); j++)
{
distArr[i,j] /= total;
}
}
}
How can I change the code to allow the collection that is passed in to either be an array or one of my own collection classes?
The trouble is, the collection that is passed in must be 2-dimensional. There isn't an interface that I can implement in my own collection classes that arrays also implement.
I want to be able to reuse the code for both cases and avoid introducing lots of ugly conditional logic. I also need to avoid allocating memory so making some kind of wrapper class for arrays isn't acceptable. I also want to avoid using lists within lists as its so much simpler to work with normal 2d arrays and lists allocate too much memory for my purposes. It seems like this should be possible with indexers or something. Like is there a way to declare that "distArr" must be any type with an indexer that takes two arguments etc.?
There is no such interface. So you need to make your own, for instance:
public interface IMatrix<T>
{
int Rows { get; }
int Columns { get; }
ref T this[int row, int column] { get; }
}
and additionally of implementing it in your collection classes, create adapter for arrays (Adapter Pattern).
I know, I know, you said
I also need to avoid allocating memory so making some kind of wrapper class for arrays isn't acceptable.
I don't think a tiny short lived GC3 generation wrapper object will hurt your system, but anyway, the heap allocation can be avoided by implementing the wrapper as a struct:
public struct ArrayMatrix<T> : IMatrix<T>
{
readonly T[,] source;
public ArrayMatrix(T[,] source) => this.source = source;
public int Rows => source.GetLength(0);
public int Columns => source.GetLength(1);
public ref T this[int row, int column] => ref source[row, column];
}
and making your method generic (to avoid boxing of the struct):
public static void RemainingDegreeDistribution<TMatrix>(IGraph graph, TMatrix distArr)
where TMatrix : IMatrix<float>
{
int total = 0;
for (int i = 0; i < graph.Edges.Count; i++)
{
int startRemDeg = graph.Edges[i].Start.RemDeg;
int endRemDeg = graph.Edges[i].End.RemDeg;
distArr[startRemDeg, endRemDeg]++;
distArr[endRemDeg, startRemDeg]++;
total = total + 2;
}
for (int i = 0; i < distArr.Rows; i++)
{
for (int j = 0; j < distArr.Columns; j++)
{
distArr[i, j] /= total;
}
}
}
To make it easier to be used with arrays, you could add a helper method:
public static class ArrayMatrix
{
public static ArrayMatrix<T> ToMatrix<T>(this T[,] source) => new ArrayMatrix<T>(source);
}
and even provide overload of your method with array argument:
public static void RemainingDegreeDistribution(IGraph graph, float[,] distArr)
=> RemainingDegreeDistribution(graph, distArr.ToMatrix());
If you need to represent point in 2D space i suggesto you to use Point data structure.
https://learn.microsoft.com/en-us/dotnet/api/system.drawing.point?view=netframework-4.7.2
Try overloading if you also would pass an array of coordinates and points :
public static Method ( float[,] coordinates )
{
//generate array of Points starting from coordinates , points.Add ( new Point(coordinate[i,j]) )
}
public static Method ( Point[] points)
{
//actual logic
}
Recently, I found a post on Internet asking this question, I tried to figure out but not sure.
I guess the problem is related with Boxing and Unboxing:
public readonly object counter = new Counter();
This line boxs a Counter onto heap, and counter refers to it.
((Counter)riddle.counter)
This line unboxs the Counter from heap.
Every time data it unboxs from heap is same as origin. Therefore, Line A doesn't affect Line B because they both retrieve from heap and are two different instances of Counter.
Is that right? Sorry for my poor English.
public void WantToKnow()
{
var riddle = new Riddle();
((Counter)riddle.counter).Increment(); // Line A
Console.WriteLine(((Counter)riddle.counter).Count); // Line B
// Why the output is 0?///////////////////
}
struct Counter
{
private int x;
public void Increment() { this.x++; }
public int Count { get { return this.x; } }
}
class Riddle
{
public readonly object counter = new Counter();
}
Firstly, this is all a good example of why I try to avoid mutable structs in almost all cases. While you can usually predict what will happen if you pay enough attention, it's easy to miss one copy along the way which messes everything up. If you keep all structs immutable, life is simpler.
For your question: yes, you're unboxing which creates a copy of the counter. Changing that copy doesn't affect anything else. (There's IL to unbox without copying, but C# never uses that.)
You can make this work by making your counter implement an interface with an Increment operation. At that point you can cast to the interface instead of the value type, which means it's not unboxing. Your Increment operation would then modify the value within the box, which means you can then get at it again. Here's a complete example:
using System;
class Program
{
static void Main()
{
var riddle = new Riddle();
((ICounter)riddle.counter).Increment();
Console.WriteLine(((Counter)riddle.counter).Count); // Line B
}
}
interface ICounter
{
void Increment();
}
struct Counter : ICounter
{
private int x;
public void Increment() { this.x++; }
public int Count { get { return this.x; } }
}
class Riddle
{
public readonly object counter = new Counter();
}
Because struct is value type- You can use "class Counter instead "struct Counter"
or use below solution
Reason : ((Counter)riddle.counter).Count is treat as another copy of struct not as ref type. so it's showing initial value 0
using System;
using System.Text.RegularExpressions;
public class Program
{
public static void Main()
{
var riddle = new Riddle();
Console.WriteLine(((Counter)riddle.counter).Increment());
///////////////////////////////////////////
Console.WriteLine(((Counter)riddle.counter).Count);
// Why the output is 0?///////////////////
}
}
struct Counter
{
private int x;
//Change is here
public int Increment() { this.x++; return this.x; }
public int Count { get { return this.x; } }
}
class Riddle
{
public readonly object counter = new Counter();
}
I am writing in Unity and not all classes can be instantiated as they inheriting Monobehaviour. I have several classes and am trying to Return an array to one class, but keep getting a null reference exception.
I have made sure the array is indexed and initialized, yet it returns null.
However in a same construction without an array, eg an Int, it works.
public class StartUp : MonoBehaviour //Unity class
{
public int x = 30,y = 30;
public PlayField entireField;
void Awake()
{
entireField = new PlayField(x,y);
entireField.InitArray(entireField, x, y);
}
}
public class CharacterController : MonoBehaviour
{
//edit: playField is not supposed hold value, just to get
//access to a method in PlayField
PlayField playField;
FieldData fData;
void Start(){
playField = new PlayField();
fData = new FieldData();
}
void Update(){
fData = playField.GetFieldData(5,6); //We're just telling it go to that method
}
}
public class PlayField
{
public SingleField[,] singleField;
public PlayField()
{
}
public PlayField(int x, int y)
{
singleField = new SingleField[x,y];
}
void InitArray(PlayField playfield, int x, int y){
//In an effort to save the data I also did
this.singleField = new SingleField[x,y];
for(int j ...
{
for (int x...
{
playfield.singleField[x, y] = new SingleField();
playfield.singleField[x, y].fielData = new FieldData();
playfield.singleField[x, y].fielData.height = GetRandom();
//and here
this.singleField[x,y] = new SingleField();
this.singleField[x,y].fieldData = new FieldData();
}
}
//to ..
this.singleField = playfield.singleField;
}
public FieldData GetFieldData(int x, int y){
//Here it keeps returning null reference
return this.singleField[x,y].fieldData;
}
}
public class SingleField
{
public FieldData fieldData;
public GameObject fieldObject;
}
public class FieldData
{
public float height;
public Vector3 position = new Vector3();
}
I know I can use a static variable but I'd like to know what I am doing wrong here or how I can get the values from entireField in StartUp class to the FieldData fData in CharacterController using the none-MonoBehaviour class PlayField?
I thought the this.singleField-array would have values, but not during the Method call from CharacterController?
Erkan, I think you're going to need to take a step back and rethink how you're approaching this. Here's why I say that:
//edit: playField is not supposed hold value, just to get
//access to a method in PlayField
PlayField playField;
... that's not how things work. If you've got a 'main' PlayField that holds all your values, and initialize another one ... any time you call functions on that second one, it'll use the values from the second one. In your case, you're trying to call the GetFieldData function, which will grab field data from the second instance of PlayField - not the one you're going for.
So Where Do You Go From Here?
First, you might want to brush up a bit on Object Oriented Programming concepts. I'm not trying to be condescending - but it'll be hard to continue on with your program if you don't have a decent grasp on them.
Second, consider the use of 'static'. Static says, "I only have one instance of this throughout my program". Take the following for example:
class Playfield
{ /* code */ }
class SomeAlreadyExistingMainClassInYourCode
{
static Playfield globalFieldInstance = new Playfield();
/* rest of the class */
}
... at this point, you've got a single Playfield that's accessible throughout your program: SomeAlreadyExistingMainClassInYourCode.globalFieldInstance.
You shouldn't overuse/abuse this - but if you're only intending on having a single instance of an object being created, creating a static instance of it is a good way to do.
#m.rogalski Yes I was trying to avoid using a static too that's how this started.
Have solved the nullreference error. Really didn't think I had to initialize everything when I just wanted to use it only to call a method* in another class and use another instance of the same class for Return.
public class CharacterController : MonoBehaviour
{
//edit: playField is not supposed hold value, just to get
//access to a method in PlayField
PlayField playField;
FieldData fData;
void Start(){
playField = new PlayField();
InitArray(playField,30,30);
fData = new FieldData();
}
void InitArray(PlayField playfield int x, int y){
playfield.singleField = new SingleField[x,y];
for (int j =0; j< y;.. {
for (int i.. {
playfield.singleField[x,y] = new SingleField();
playfield.singleField[x,y].fieldData = new FieldData();
}
}
}
void Update(){
//The return was not supposed to be a field in this instance of
//PlayField, but come from the PlayField class itself as
//this.singleField[x,y] (a array in PlayField)
fData = playField.GetFieldData(5,6); //We're just telling it go to that method
}
}
public class PlayField
{
public SingleField[,] singleField = new SingleField[30,30];//evrything initailized and so on in the rest of the class here ommited. ect.
public FieldData GetFieldData(int x,int y){
//Here was the catch. Return values form this Class
// and not read from the instance created in CharacterController
//was giving me a nullrefence while I was using only FieldData
return this.singleField[x,y].fieldData;
}
}
This is solved for me.
On to the next question.
Thanks
I'm trying to build a console app that is a blackjack game. BlackJackTable : TableGame and has 6 BettingSpots. I'm thinking I want to have an array that contains the BettingSpots. But I am getting errors trying to populate the BettingSpot[]. Any advice on how to better proceed with the design would be much appreciated.
public abstract class TableGame
{
// Can have 5-7 bettings spots. Has a dealer, players, Rules
public abstract void Rules();
public abstract BettingSpot[] bettingSpotArray;
public Dealer dealer = new Dealer();
}
public class BlackJackTable : TableGame
{
// A blackjack tablegame "has a" 6 BettingSpots available that a Player chooses to occupy. Have the Game ask the player which bettingspots they'd
// like to place a bet on. Bet amount must be the same for each. Use a try catch block to make sure TotalChips >= all bets.
public BlackJackTable(int tableNumber)
{
_tableNumber = tableNumber;
}
public override void BlackJackRules()
{ }
BettingSpot spot1 = new BettingSpot(1);
BettingSpot spot2 = new BettingSpot(2);
BettingSpot spot3 = new BettingSpot(3);
BettingSpot spot4 = new BettingSpot(4);
BettingSpot spot5 = new BettingSpot(5);
BettingSpot spot6 = new BettingSpot(6);
public override BettingSpot[] bettingSpotArray = new BettingSpot[5];
for (int i = 0; i < bettingSpotArray.Length; i++)
{
bettingSpotArray[i] = new BettingSpot[i+1];
}
public void QueryPlayerForBettingSpots(BettingSpot[] bettingSpotArray)
{
int[] BettingSpotsAvailable = new BettingSpot[5];
for (int idx = 0; idx < 5; idx++)
if (bettingSpotArray[idx] == 0)
BettingSpotsAvailable[idx]
Console.WriteLine("Place up to 3 bets on the following available BettingSpots: {0}", bettingSpotArray.Where<BettingSpot.
}
}
public class BettingSpot
{
protected decimal bet = 0;
public int _bettingSpotNumber;
// How many spots are on the Blackjack table will determine how many seats there will be. There are six betting spots allowed,
// so six bettingspots are created. THere are just 6 BettingSpots available and a player can
// occupy up to 3 BettingSpots at a time. A bettingspot "has a" bet. If no bet, put '0' in BettingSpotArray
public BettingSpot(int number)
{
_bettingSpotNumber = number;
}
public Player player
public decimal Bet
{
get
{
return bet;
}
set
{
bet = value;
}
}
A few things I noticed in your code.
First, I believe you're having trouble trying to populate bettingSpotArray[] because you're trying to do it inside the body of the class. You need to do it inside the body of a method or property - I'd suggest the constructor or the Rules() method.
Secondly, since you're not defining any code in the abstract class, you might find it easier to make the abstract class an interface and have your game classes implement the interface - that way the class will know what it has to implement, but you don't have to override everything. If you had some sort of default logic you wanted for a majority of the game classes, then I'd agree with using an abstract class that had that base logic, and the "special" classes would override it as needed. But that's just my take on it; you may have your own valid reasons for using an abstract class that are not readily apparent in your question.
I'm not sure the code you have posted will actually compile, but I'll give some code samples that should help you get to where you're trying to go.
public class BlackJackTable : TableGame
{
// If other classes need access to this I'd set it up as public
// property, not a public field. If not, I'd set the field to
// private
public override BettingSpot[] bettingSpotArray = new BettingSpot[5];
public BlackJackTable(int tableNumber)
{
// I don't see a _tableNumber field in your abstract class or your
// inheriting class - if you don't have that field you'll get an error
// in the compiler
_tableNumber = tableNumber;
}
// Your posted code had public override void BlackJackRules, but there is
// no BlackJackRules() method to override
public override void Rules()
{
// These are superfulous since you'll be using an array
// for the betting spots
//BettingSpot spot1 = new BettingSpot(1);
//BettingSpot spot2 = new BettingSpot(2);
//BettingSpot spot3 = new BettingSpot(3);
//BettingSpot spot4 = new BettingSpot(4);
//BettingSpot spot5 = new BettingSpot(5);
//BettingSpot spot6 = new BettingSpot(6);
// Now you can initialize your array
for (int i = 0; i < bettingSpotArray.Length; i++)
{
bettingSpotArray[i] = new BettingSpot[i+1];
}
}
}
Your QueryPlayerForBettingSpots doesn't make a lot of sense either, as it prompts for input from the user, but doesn't accept any input. Perhaps you haven't finished that method?
I think your overall approach is the correct approach, but your implementation has some issues (which I've noted above). Hopefully this will be of some help to you in moving forward in your project.