How to generate an array of pointers in C#? - c#

I have this piece of code that’s really huge, and I feel that I could shorten it down significantly if I used pointers. I don’t really see any other alternative, as arrays don’t hold references to variables.
What I’d like to do is to create a pointer array. I’d then place all of my “tick” variables inside of it, then I could iterate over them to complete the actions shown below.
[SerializeField] private bool canEatFood = true;
[SerializeField] private bool canTakeBath = true;
[SerializeField] private bool canPlay = true;
[SerializeField] private bool isScared = false;
[SerializeField] private bool beenPet = false;
private int canEatTick = 0;
private int canBatheTick = 0;
private int canPlayTick = 0;
private int beenPetTick = 0;
private int pettedCount = 0;
private const int PETS_TO_KILL_PER_CYCLE = 50;
private const int PET_HAPPINESS_VALUE = 1;
private const int DEFAULT_STARTING_VALUE = 10;
private const int DEFAULT_MAX_VALUE = 100;
private const int DEFAULT_MIN_VALUE = 0;
private const int DEFAULT_CYCLE_START_VALUE = 0;
private const int DEFAULT_CYCLE_END_VALUE = 500;
public void FixedUpdate()
{
CheckTicks();
}
private void CheckTicks()
{
if (!canEatFood && canEatTick >= DEFAULT_CYCLE_END_VALUE)
{
canEatTick = DEFAULT_CYCLE_START_VALUE;
canEatFood = true;
}
else if (!canEatFood)
{
canEatTick++;
}
if (!canTakeBath && canBatheTick >= DEFAULT_CYCLE_END_VALUE)
{
canBatheTick = DEFAULT_CYCLE_START_VALUE;
canTakeBath = true;
}
else if (!canTakeBath)
{
canBatheTick++;
}
if (!canPlay && canPlayTick >= DEFAULT_CYCLE_END_VALUE)
{
canPlayTick = DEFAULT_CYCLE_START_VALUE;
canPlay = true;
}
else if (!canPlay)
{
canPlayTick++;
}
if (beenPet && beenPetTick >= DEFAULT_CYCLE_END_VALUE)
{
beenPetTick = DEFAULT_CYCLE_START_VALUE;
beenPet = false;
CheckIfPetsShouldKill();
}
else if (beenPet)
{
beenPetTick++;
}
}
I tried
int*[] ticks = new int*[4];
which resulted in an error.
I then tried
ref int[] ticks = new ref int[4];
which also resulted in an error.

Don't, this is not what pointers are for.
What you want to use is a class. You should wrap your variables inside a class, and this should also contain the associated logic:
public class Tick{
private bool canDoX= true;
private int tick = 0;
public event EventHandler CycleEnd;
// define all the constants
public void Update(){
if (!canDoX && tick >= DEFAULT_CYCLE_END_VALUE)
{
tick = DEFAULT_CYCLE_START_VALUE;
canDoX = true;
CycleEnd?.Invoke(this, EventArgs.Empty);
}
else if (!canDoX)
{
tick ++;
}
}
}
This lets you create a collection of ticks, and apply the logic to each of them. If needed you can use events, delegates or inheritance to customize the behavior if needed.

To use pointers in C# you need an unsafe scope
void example() {
int*[] tick_safe = new int*[4]; // shows an error
unsafe {
int*[] tick_unsafe = new int*[4]; // ok
}
}
example();
In visual studio (2022, .NET 7) you have to manually allow unsafe code for your project:
right click your project > properties > build > general > allow unsafe code
And if you need an alternative to pointers, you could use an array of arrays
int[][] ticks = new int[4][];

Related

Rewriting my code as a Method, using C# Visual Studio

I am currently having trouble understanding Methods and how they work in C#. I currently have code written for a car cost calculator program I created, I want to rearrange or break my code down using methods. I am unsure how or where to begin doing so as it pertains to my program. Here is my code, clarification would be helpful! Thank you!
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//constants for the Zone entered by user
const decimal ZoneCostN = 27;
const decimal ZoneCostS = 36;
const decimal ZoneCostE = 45;
const decimal ZoneCostW = 54;
private void CalcButton_Click(object sender, EventArgs e)
{
//set the variables
decimal PackWeight = 0;
decimal CostZone = 0;
decimal CostWeight = 0;
decimal ShippingTot = 0;
decimal Net = 0;
const decimal PerPound = 18;
//parses the entry into the textboxes
decimal.TryParse(WeightText.Text, out PackWeight); ;
//algorithm for variables
CostWeight = PackWeight * PerPound;
Zonelbl.Text = "";
CostZone = 0;
//if else statement to get the zone cost
{
if (NorthButton.Checked)
{
CostZone = ZoneCostN;
}
else if (SouthButton.Checked)
{
CostZone = ZoneCostS;
}
else if (EastButton.Checked)
{
CostZone = ZoneCostE;
}
else if (WestButton.Checked)
{
CostZone = ZoneCostW;
}
else
{
MessageBox.Show("Select a zone!");
}
}
//algorithm to get total and net
ShippingTot = CostZone + CostWeight;
Net = ShippingTot / CostWeight;
//if condition for CAPPED label
if (ShippingTot >= 100)
{
CAPPEDlbl.Visible = true;
}
else
{
CAPPEDlbl.Visible = false;
}
//output for all the data
Zonelbl.Text = CostZone.ToString("c");
Weightlbl.Text = CostWeight.ToString("c");
Totallbl.Text = ShippingTot.ToString("c");
Netlbl.Text = Net.ToString("c");
}
private void ClearButton_Click(object sender, EventArgs e)
{
//clears the form
Zonelbl.Text = "";
Weightlbl.Text = "";
Totallbl.Text = "";
Netlbl.Text = "";
WeightText.Text = "";
CAPPEDlbl.Visible = false;
WeightText.Focus();
}
}
Usually, we create methods when we need to reuse a code. In your case, you should see which part of your code will be reused in the future. If it is a simple form you may don't need to change anything but imagine you want to use your clear functionality somewhere else, create a method and call it everywhere you need
void clear()
{
Zonelbl.Text = "";
Weightlbl.Text = "";
Totallbl.Text = "";
Netlbl.Text = "";
WeightText.Text = "";
CAPPEDlbl.Visible = false;
WeightText.Focus();
}
private void ClearButton_Click(object sender, EventArgs e)
{
clear();
}
Now you can reuse clear() and in case you needed to change it you only need to change the method. It's the concept and you can apply it wherever you need.

How to make RFID reader seek for card continously

For a while now, i have been trying to make my RFID reader to automatically read (scan) a card. Although the former code i had, makes the reader scan the card when a button is pressed. But i want to be able to scan cards automatically and continuously, once any card is placed in the field. Here is what i tried. but i was not able to display the scanned UID in a textbox. Please, your help will be appreciated.
class CardReader : IDisposable
{
IntPtr _pSnr = Marshal.AllocHGlobal(1024);
private Thread _t;
private Action<string> _callback;
private volatile bool _stop;
public void ReadCard()
{
short icdev = 0x0000;
int status;
byte type = (byte)'A';//mifare one type is A
byte mode = 0x26; // Request the card which is not halted.
ushort TagType = 0;
byte bcnt = 0x04;//mifare hold on 4
IntPtr pSnr;
byte len = 255;
sbyte size = 0;
pSnr = Marshal.AllocHGlobal(1024);
for (int i = 0; i < 2; i++)
{
status = rf_request(icdev, mode, ref TagType);//request card
if (status != 0)
continue;
status = rf_anticoll(icdev, bcnt, pSnr, ref len);//i did anticol--get the card sn
if (status != 0)
continue;
status = rf_select(icdev, pSnr, len, ref size);//select one card
if (status != 0)
continue;
byte[] szBytes = new byte[len];
for (int j = 0; j < len; j++)
{
szBytes[j] = Marshal.ReadByte(pSnr, j);
}
String m_cardNo = String.Empty;
for (int q = 0; q < len; q++)
{
m_cardNo += byteHEX(szBytes[q]);
}
_callback(m_cardNo);
// txtSearchPurse.Text = m_cardNo;
break;
}
}
public void Work()
{
while (!_stop)
{
ReadCard();
Thread.Sleep(1000);
}
}
public void Start(Action<string> cardRead)
{
if (_t != null)
return;
_stop = false;
_callback = cardRead;
_t = new Thread(Work);
_t.Start();
}
public void Stop()
{
if (_t != null)
{
_stop = true;
_t.Join();
_t = null;
}
}
public void Dispose()
{
Marshal.FreeHGlobal(_pSnr);
}
}
And i tried to use it like this:
private void btnRequest_Click(object sender, EventArgs e)
{
var reader = new CardReader();
reader.Start(CardReaded);
}
private void CardReaded(string cardnr){
//txtSearchPurse.Text = _callback;
}
Here is what i tried. but i was not able to display the scanned UID in a textbox.
So your callback successfully fired? What error, if any, did you get? I'm guessing you got a "cross thread exception". If so, fix it like this:
private void CardReaded(string cardnr)
{
this.Invoke((MethodInvoker)delegate
{
txtSearchPurse.Text = cardnr;
});
}

C# GUI Dice Game pass by reference

Ok I'm trying to make a GUI dice game where the dice numbers are represented in textboxes.
I have to create a class that represents the dice and at least one of my methods has to correctly pass parameters by reference. My problem is that I am not too experienced with classes or passing parameters
I get an error at
rd.RollDice1(ref dice1);
rd.RollDice2(ref dice2);
(I am sure I have not constructed the RollDice class incorrectly)
Please is there anyone that can help me?
here is my code so far:
public partial class Form1 : Form
{
private RollDice rd;
public Form1()
{
InitializeComponent();
rd = new RollDice();
}
private void button1_Click(object sender, EventArgs e)
{
int dice1, dice2;
const int EYE = 1;
const int BOX = 6;
rd.RollDice1(ref dice1);
rd.RollDice2(ref dice2);
string result = string.Format("{0}", dice1);
string result2 = string.Format("(0)", dice2);
textBox1.Text = result;
textBox2.Text = result;
if (dice1 == EYE && dice2 == BOX)
{
MessageBox.Show("You rolled a Snake Eyes!");
}
if (dice1 == BOX && dice2 == BOX)
{
MessageBox.Show("You rolled BoxCars!");
}
else
{
MessageBox.Show("You rolled a {0} and a {1}", dice1, dice2);
}
}
}
}
class RollDice
{
const int EYE = 1;
const int BOX = 6;
public int RollDice1(ref int dieValue1)
{
Random randomNums = new Random();
dieValue1 = randomNums.Next(1, 7);
return dieValue1;
}
public int RollDice2(ref int dieValue2)
{
Random randomNums = new Random();
dieValue2 = randomNums.Next(1, 7);
return dieValue2;
}
}
}
Passing a variable with ref requires that variable to be initialized with a default value. If you don't set the two dices with an initial value your compiler complains about "Use of unassigned local variable xxxxx"
private void button1_Click(object sender, EventArgs e)
{
const int EYE = 1;
const int BOX = 6;
int dice1 = EYE;
int dice2 = BOX;
rd.RollDice1(ref dice1);
rd.RollDice2(ref dice2);
.....
However looking at your code there is no need to pass that values using ref, you could simply get the return value
dice1 = rd.RollDice1();
dice2 = rd.RollDice2();
of course you should change the two methods in your class to remove the parameter passed by ref
class RollDice
{
Random randomNums = new Random();
public int RollDice1()
{
return randomNums.Next(1, 7);
}
public int RollDice2()
{
return randomNums.Next(1, 7);
}
}

c# text difference

I have two words:
Source: John
ConvertTo: Jack
and I want to show the effect of convert all letters from "Source" at the same time to the "ConvertTo" word. I already create a program to accomplish that but processing one letter at a time, to show the effect I use Threads, the thing is that to process all letters at the same time I suppose I need one thread per letter, and every thread will call the same function that process the letter, and I use global variables.
Here is the code (works only for texts with same lenght):
private void button1_Click(object sender, EventArgs e)
{
lblResult.Text = "";
lblResult2.Text = "";
ThreadPool.QueueUserWorkItem(new WaitCallback(Process));
}
int movement = 0;
string CumulateText;
private void Process(object stateinfo)
{
int value;
int operation; //0->[+] 1->[-]
CumulateText = "";
for (int i = 0; i <= textBox1.Text.Length - 1; i++)
{
if (textBox1.Text[i] != ' ')
{
value = (char)textBox1.Text[i] - (char)textBox2.Text[i];
if (value >= 0)
operation = 1;
else
operation = 0;
for (int ii = 0; ii <= Math.Abs(value); ii++)
{
if (operation == 1)
movement = (char)textBox1.Text[i] - ii;
else
movement = (char)textBox1.Text[i] + ii;
this.Invoke(new EventHandler(ShowMovement));
System.Threading.Thread.Sleep(10);
}
}
CumulateText += textBox2.Text[i].ToString();
}
}
private void ShowMovement(object sender, EventArgs e)
{
lblResult.Text = CumulateText + Convert.ToString((char)movement);
}
I hope I made myself understood.
please any advise to accomplish that.
thanks
To clarify more what I want to accomplish here is an example:
Source: John
ConvertTo: Jack
J - same J
o - decrease till a (o, n, m, ..., a)
h - decrease till c (h, g, f, ..., c)
n - decrease till k (n, m, l, k)
I once had to do something similar for a small little project I was working on for fun.
I do not see why you would need to create a thread for each letter to create a transition between two words unless I'm not understanding what you are pretending to do correctly.
Check and study the following code, see if its any help:
static class Program
{
static void Main()
{
TextTranstition transition = new TextTranstition();
transition.TransitionFinished += TransitionTicked;
transition.TransitionTicked += TransitionTicked;
transition.StartTransition("AmazingWordTransition", "MyNewWordAppearing", 100);
Thread.CurrentThread.Join();
Console.ReadKey();
}
public static void TransitionTicked(object sender, TranstitionEventArgs e)
{
Console.Clear();
Console.Write(e.TransitionText);
}
}
public class TranstitionEventArgs : EventArgs
{
private readonly string transitionText;
public string TransitionText { get { return this.transitionText; } }
public TranstitionEventArgs(string transitionText)
{
this.transitionText = transitionText;
}
}
public class TextTranstition
{
private struct StartInfo
{
public StartInfo(string initialText, string finalText, int timeStep)
{
this.initialText = initialText;
this.finalText = finalText;
this.timeStep = timeStep;
}
private readonly string initialText;
public string InitialText { get { return this.initialText; } }
private readonly string finalText;
public string FinalText { get { return this.finalText; } }
private readonly int timeStep;
public int TimeStep { get { return this.timeStep; } }
}
public EventHandler<TranstitionEventArgs> TransitionFinished;
public EventHandler<TranstitionEventArgs> TransitionTicked;
public void StartTransition(string initialText, string finalText, int timeStep)
{
StartInfo startInfo = new StartInfo(initialText, finalText, timeStep);
Thread t = new Thread(startTransition);
t.Start(startInfo);
}
private void startTransition(object info)
{
StartInfo startInfo = (StartInfo)info;
string initialText = startInfo.InitialText;
string finalText = startInfo.FinalText;
if (initialText.Length < finalText.Length)
{
initialText = initialText.PadRight(finalText.Length);
}
if (TransitionTicked != null) TransitionTicked(this, new TranstitionEventArgs(initialText));
while ((initialText = transition(initialText, finalText)) != finalText)
{
Thread.Sleep(startInfo.TimeStep);
if (TransitionTicked != null) TransitionTicked(this, new TranstitionEventArgs(initialText));
}
if (TransitionFinished != null) TransitionFinished(this, new TranstitionEventArgs(finalText));
}
private string transition(string initialText, string finalText)
{
StringBuilder b = new StringBuilder(finalText.Length);
for (int i = 0; i < finalText.Length; i++)
{
char c = initialText[i];
int charCode = (int)c;
if (c != finalText[i])
{
if (charCode == 122 || charCode==32) charCode = 65;
else if (charCode == 90) charCode = 97;
else
{
charCode += 1;
}
}
b.Append((char)charCode);
}
return b.ToString();
}
}
Use BackgroudWorker for this kind of stuff.

Generating a random number that can be accesed anywhere

Here is the beginning of my code:
public partial class Form1 : Form
{
static Random random = new Random();
int prevnum;
int currentnum;
public int GenerateRandomNumber()
{
return random.Next(1, 1000);
}
public Form1()
{
int randomNumber = random.Next(1, 1000);
InitializeComponent();
}
private void enterButton_Click(object sender, EventArgs e)
{
currentnum = Convert.ToInt32(guessBox.Text);
if (randomNumber < currentnum)
{
warmOrColdLabel.Text = "Too High";
if (currentnum > prevnum)
{
guessBox.BackColor = Color.Blue;
prevnum = currentnum;
}
else
{
guessBox.BackColor = Color.Red;
prevnum = currentnum;
}
}
if (randomNumber > currentnum)
{
warmOrColdLabel.Text = "Too Low";
if (currentnum > prevnum)
{
guessBox.BackColor = Color.Blue;
prevnum = currentnum;
}
else
{
guessBox.BackColor = Color.Red;
prevnum = currentnum;
}
}
if (randomNumber == currentnum)
{
guessBox.Enabled = false;
enterButton.Enabled = false;
playAgainButton.Enabled = true;
}
}
private void playAgainButton_Click(object sender, EventArgs e)
{
enterButton.Enabled = true;
guessBox.Enabled = true;
playAgainButton.Enabled = false;
}
}
The issue I have is getting a random number, it always puts out 0. I simply need a random number that I can put into different buttons and such. What am I doing wrong?
Edit: must be a random number between 1 and 1000.
You don't actually call RandomNumberHandler() anywhere. Also, you need to specify your range in the call to .Next() (e.g., random.Next(1000)+1 to get a number from 1 to 1000).
public partial class Form1 : Form
{
//other stuff from before
int randomNumber; //move this here
public Form1()
{
randomNumber = random.Next(1, 1000); //assign it here
InitializeComponent();
}
Main problem is randomNumber is initialized when the constructor is called, and thereafter when you access it you access the same value.
You should eliminate that instance variable, and instead simply make a new call to GenerateRandom().
In addition, you probably want to make your instance of Random a static variable:
static Random random =
Otherwise each time the class is unloaded and reloaded it will repeat the same sequence which would be less random (or rather, pseudo random).

Categories

Resources