Random directions, with no repeat.. (Bad Description) - c#

Hey there, So I'm knocking together a random pattern generation thing.
My code so far:
int permutes = 100;
int y = 31;
int x = 63;
while (permutes > 0) {
int rndTurn = random(1, 4);
if (rndTurn == 1) { y = y - 1; } //go up
if (rndTurn == 2) { y = y + 1; } //go down
if (rndTurn == 3) { x = x - 1; } //go right
if (rndTurn == 4) { x = x + 1; } //go left
setP(x, y, 1);
delay(250);
}
My question is, how would I go about getting the code to not go back on itself?
e.g. The code says "Go Left" but the next loop through it says "Go Right", how can I stop this?
NOTE: setP turns a specific pixel on.
Cheers peoples!

It depends on what you mean.
If you mean "avoid going back to a step I was most previously on" then you have to remember the direction of the last movement. That is if you move up your next movement can't be down.
If you mean "avoid going back on a spot you've ever been on" then you're going to have to remember every spot you've been on. This can be implemented efficiently with a hash table using a key with a class representing a coordinate with appropriate Equals/HashCode functions.

Since each square corresponds to a pixel, your coordinate space must be finite, so you could keep track of coordinates you've already visited.
If there's a corresponding getP function to determine if a pixel has already been turned on, you could just use that.

You remember the last direction and, using random(1,3), pick either of the remaining three, then store that as the last one.

Not sure if this approach will work.
Create a new variable called lastRndTurn as int, and assign this after your if statements.
Then add a new while loop after your int rndTurn = random(1, 4).
while (lastRndTurn == rndTurn)
{
rndTurn = random(1, 4);
}

Related

Cant get a path finding algorithm to work correctly in all cases

I am having trouble with an assignment about finding the shortest total path in a grid, while visiting all the correct tiles in the correct order.
We are supposed to emulate manually inputting a word, like when using a controller to write something, and find the least amount of commands (up, down, left, right) needed to do so.
Our input is the grid, parameters, and the word we are supposed to work with.
I store them like this (with example inputs):
Height = 2;
Width = 2;
Content = "ABCC";
Word = "ABC";
grid = new char[Height, Width];
Contents = Content.ToCharArray();
Words = Word.ToCharArray();
int ch = 0;
for (int i = 0; i < Height; i++)
{
for (int j = 0; j < Width; j++)
{
if (ch < Contents.Length)
{
grid[i, j] = Contents[ch];
ch++;
}
}
}
The actual way I compute the shortest path is like so:
public void GridSearch( int a, int FirstX, int FirstY, int PathLength)
{
int NewPath;
int NewX;
int NewY;
int SecondX = 0;
int SecondY = 0;
for (int i = 0; i < Height; i++)
{
for (int j = 0; j < Width; j++)
{
if (grid[i, j] == Words[a])
{
SecondX = i;
SecondY = j;
NewPath = PathLength;
NewPath += Math.Abs(FirstX - SecondX);
NewPath += Math.Abs(FirstY - SecondY);
NewX = SecondX;
NewY = SecondY;
if (a < Words.Length-1)
{
GridSearch(a+1, NewX, NewY, NewPath);
}
else
{
if (FinalPath > NewPath ^ FinalPath == -1)
{
FinalPath = NewPath;
}
}
}
}
}
We are also supposed to "click" when on the correct tile, so I am adding the length of "Words" to the total of commands.
In this case, the shortest path between the letters would be 2 (right, down) and the length is 3, so 5 is the correct answer.
This is also what my program gets, however when I try to send it in, the automated checker says it only passes 1 out of 5 tests, which is an improvement over the 0 that I had until recently, but still not actually good.
Sadly it does not say which inputs it used to make my program fail, and after a day of trying things I am out of ideas on how to fix it, could anyone please point out the, no doubt, obvious mistake I am making and help me fix this program?
EDIT: The assignment instructions as written (since a commenter asked for them):
Some devices allow text entry using a grid of letters. The grid
contains a movable cursor, which begins in the upper-left-hand corner.
Arrow keys move the cursor up, down, left and right and Enter key
chooses the letter under cursor.
For example, if the input grid looks like this:
ABCDEFGH
IJKLMNOP
QRSTUVWX
YZ
we can enter the text "HELLO" with the following sequence of keys
(which is only one of many possible sequences):
right
right
right
right
right
right
right
Enter
left
left
left
Enter
down
left
Enter
Enter
right
right
right
Enter
Write a program that for a given grid (which may contain both
lowercase and uppercase letters) and text (which may also contain
non-alphabetic characters) determines and writes out the minimum
number of keystrokes required to enter the given text.
Caution: Each letter may appear more than once in the grid!
The input begins with numbers indicating the width and height of the
grid (each on its own line).
A single line follows containing the contents of the entire grid (in
row-major order, i.e. with one row after another).
The rest of the lines contain the text to be entered. ! You should
ignore any characters in the text that are not present in the grid.
Example:
Input:
3
3
ABCBFECDF
ABCDEFA
Output:
15
In this example, the grid has the form
ABC
BFE
CDF
It is possible to enter the text ABCDEFA in many possible ways; 15
keystrokes is the length of the shortest of these.
Revising my previous answer, it is likely that you have not counted the "enter" keystroke. I.e. you should add one to the candidate path length for each letter:
...
NewY = SecondY;
**NewPath++;**
if (a < Words.Length - 1)
...
This gives a correct length of 15 keypresses on your example set of "ABCBFECDF" / "ABCDEFA".
Note that this type of code greatly benefits from a type that represents a pair of x/y coordinate, like a Point or Vector2i, so you don't have to repeat a bunch of calculations for both x and y coordinates. I would also recommend following common coding conventions like
declare local variables in the smallest possible scope, not at the top of the method
Use "camelCasing" for local variables
Prefer pure methods whenever possible, i.e.
I would still recommend reading up on Djikstra or A*, since these should be more generally applicable and be more efficient.

C# slotmachine supposed to keep one continuous score, somehow keeps multiple separate scores

I've been working on a slotmachine in C# for practise purposes, and the machine itself works as intentional. The points system, however, does not. The game starts at 100 points, and if, for example, the player lose three 5-point bets and wins 40 points on the fourth bet, the expected points would be 100-20+40=120 points. For some reason however, the code treats ALL the previous bets as being 40 point wins as well, bringing the total to 100-20+160=240 points. If the player then lose the fifth 5-point bet, the score jumps to 75.
I start by setting the 'points' value to 100, which should then update everytime the 'game()' function is called upon.
public static void Main()
{
int points = 100;
int num = 0;
Console.WriteLine("Welcome to 'Slotmachine'!\nThe aim of this game is to get a score of 1000 or higher.\nYou lose if you reach 0 or lower.\nPress enter to play");
Console.ReadLine();
Console.Clear();
points = points + game(100);
while(points<1000 && points>0)
{
num = num + 1;
Console.WriteLine("You've played for "+num+" number of round(s)");
points = points + game(points);
}
}
The 'game()' funtion returns the players winnings, which is used to update the 'points' value (Suspect nr 1?).
Inside the game function I have a 'usrbet' which takes an input from the user (1-10), which is then fed into the 'slots()' function to determine the winnings (the 'points' that are fed from 'Main()' are checked to see what the user can bet)
Console.WriteLine("Here are your current points: "+points+"\nHow much would you like to bet?\nmin bet: 1\nmax bet: 10");
try
{
usrbet = Convert.ToInt32(Console.ReadLine());
}
catch
{
usrbet = 1;
}
winnings = slots(usrbet);
int RetWin = winnings - usrbet;
return RetWin;
Here's what the 'slots()' function does, with some examples of the winnings calculations
public static int slots(int usrbet)
{
int Win;
int x;
int y;
int z;
Random slot = new Random();
x = slot.Next(2,10);
y = slot.Next(2,10);
z = slot.Next(2,10);
Console.WriteLine(x+""+y+""+z);
Example 1
if(x == y && y == z && x== 7)
{
Win = usrbet*250;
Console.WriteLine("WOW! That's incredible, you just won "+Win+"!");
}
Example 2
else if(x == z)
{
Win = usrbet*5;
Console.WriteLine("Congratulations, you win "+Win+".");
}
Example 3
else
{
Win = 0;
Console.WriteLine("Ah, bummer. You didn't win anything this time.");
}
After that, the 'Win' value is sent back to 'game()', updating 'winnings'.
I apologize for poor formatting of the question. I'll include a link to the code, in case my problem lies elsewhere in the code: https://dotnetfiddle.net/D5TwL0
I've tried making arrays of the 'bet' and 'usrbet' variables, in an attempt to have a "new" value to update the 'points' with at every run of 'game()', but that changed absolutely nothing other than limiting how many times 'game()' can run before getting an overflow error.
It turns out that the problem wasn't with the code, but with the compiler. Dotnetfiddle is where I made the code and had the issue, but trying it in another compiler, it managed to count just fine.

A for loop somehow overrides an entire array, even though I can see no reason for that

So, been looking at this code for a good while now, and I am lost.
The point is to run a for loop that adds classes to an array, and then for each class runs through an array of points inside of that class, and add variations to it.
This then shows as a bunch of dots on a form, which are supposed to move independently of each other, but now follows each other completely.
It does not matter how much variation there is or anything, it's just 99 dots with the exact same acceleration, velocity, and location, and path.
The code is here, the method isn't touched by any other code, and the problem arises before it returns.
//Point of the method is to put variations of Baby into an array, and return that array
Dot.Class[] MutateAndListBaby(Dot.Class Baby)
{
//Making the empty array
Dot.Class[] BabyList = new Dot.Class[dots.Length];
//For loop that goes through through the whole array
for (int i = 1; i < BabyList.Length; i++)
{
//For each itteration the for loop adds the class reference to the index, then puts the standard directions into that reference, and then sets a value preventing it from being changed in another code
BabyList[i] = new Dot.Class();
BabyList[i].Directions = Baby.Directions;
BabyList[i].StartupComplete = true;
//The zero index variation when made like this, allows it to not be overriden, which would lead one to believe that how the directions are copied is he problem
//But it shouldn't be, BabyList[i].Directions = Baby.Directions; should be fire and forget, it should just add the Directions to the array and then leave it
BabyList[0] = new Dot.Class();
BabyList[0].Directions = new PointF[100];
for (int b = 0; b < BabyList[0].Directions.Length; b++)
{
BabyList[0].Directions[b] = new Point (5, 10);
}
BabyList[0].StartupComplete = true;
//The for loop that shuld add variation, but it seems like it somehow overrides it self, somehow
for (int b = 0; b < BabyList[i].Directions.Length; b++)
{
if (rand.Next(0, 101) >= 100)
{
int rando = rand.Next(-50, 51);
float mod = (float)rando / 50;
float x = BabyList[i].Directions[b].X;
x = x + mod;
BabyList[i].Directions[b].X = rand.Next(-5, 6);
}
if (rand.Next(0, 101) >= 100)
{
int rando = rand.Next(-50, 51);
float mod = (float)rando / 50;
float y = BabyList[i].Directions[b].Y;
y = y * mod;
BabyList[i].Directions[b].Y = rand.Next(-5, 6);
}
}
//Now one would assume this would create a unique dot that would move 100% independently right? Since it's at the end of the for loop, so nothin should change it
// Nope, somehow it makes every other dot copy its directions...
if (i == 5)
{
for (int b = 0; b < BabyList[5].Directions.Length; b++)
{
BabyList[5].Directions[b] = new PointF(-5f, -5f);
}
}
}
return BabyList;
}
}
}
With the code there, what I get is the 0 index dot going its own way, while the other 99 dots for some reason follow the 5th index's Directions, even though they should get their own variations later on in the code.
Any help would be much appreciated, it probarbly something obvious, but trust me, been looking at this thing for quite a while, can't see anything.
If I understand you correctly, this might be the issue:
BabyList[i].Directions = Baby.Directions;
Directions is of type array of PointF - a reference. The line above does not copy the array. Is that what you assume? If I'm not misreading the code you're presenting, you're creating one Dot.Class with its own array of PointF at index 0 and fill the rest of your Dot.Class array with instances that share one single array.
Directions is array, which is a reference type. When you're making assigment of a variable of this type
BabyList[i].Directions = Baby.Directions;
no new instance is created and reference us just being copied into new variable which still references original instance. Essentially in your loop only very first item gets a new instance of Directions as it's explicitly constructed. The rest share the instance which comes as a member of parameter passed to the method.
You probably want to change your if conditions:
(rand.Next(0, 101) >= 100
to
(rand.Next(0, 100) < 99
This will run an average of 99 times out of 100, whereas your current condition runs 1 out of 101 times (on average)
Oh, and Benjamin Podszun's answer about assigning the same array (not a copy of the same array) to Directions apply as well!
(Assuming that Directions isn't a getter that you created to return a copy of an array instead of a reference!)

Need help for search optimization

I am fairly new to programming and i need some help with optimizing.
Basically a part of my method does:
for(int i = 0; i < Tiles.Length; i++)
{
x = Tiles[i].WorldPosition.x;
y = Tiles[i].WorldPosition.y;
z = Tiles[i].WorldPosition.z;
Tile topsearch = Array.Find(Tiles,
search => search.WorldPosition == Tiles[i].WorldPosition +
new Vector3Int(0,1,0));
if(topsearch.isEmpty)
{
// DoMyThing
}
}
So i am searching for a Tile in a position which is 1 unit above the current Tile.
My problem is that for the whole method it takes 0.1 secs which results in a small hick up..Without Array.Find the method is 0.01 secs.
I tried with a for loop also, but still not great result, because i need 3 more checks for
the bottom, left and right..
Can somebody help me out and point me a way of acquiring some fast results?
Maybe i should go with something like threading?
You could create a 3-dimensional array so that you can look up a tile at a specific location by just looking what's in Tiles[x, y + 1, z].
You can then iterate through your data in 2 loops: one to build up Tiles and one to do the checks you are doing in your code above, which would then just be:
for(int i = 0; i < Tiles.Length; i++)
{
Tile toFind = Tiles[Tile[i].x, Tile[i].y + 1, Tile[i].z];
if (toFind != null) ...
}
You would have to dimension the array so that you have 1 extra row in the y so that Tiles[x, y + 1, z] doesn't cause an index-out-of-range exception.
Adding to Roy's solution, if the space is not continuous, as it might be, you could put a hashcode of WorldPosition (the x, y and z coordinates) to some good use here.
I mean you could override WorldPosition's GetHashCode with your own implementation like that:
public class WorldPosition
{
public int X;
public int Y;
public int Z;
public override int GetHashCode()
{
int result = X.GetHashCode();
result = (result * 397) ^ Y.GetHashCode();
result = (result * 397) ^ Z.GetHashCode();
return result;
}
}
See Why is '397' used for ReSharper GetHashCode override? for explanation.
Then you can put your tiles in a Dictionary<WorldPosition, Tile>.
This would allow for quickly looking up for dict[new WorldPosition(x, y, z + 1)] etc. Dictionaries use hashcode for keys, so it would be fast.
First, like #Roy suggested, try storing the values in an array so you can access them with x,y,z coordinates,
Another thing you could do is change the search to
Tile topsearch = Array.Find(Tiles,
search => search.WorldPosition.x == Tiles[i].WorldPosition.x &&
search.WorldPosition.y == (Tiles[i].WorldPosition.y + 1) &&
search.WorldPosition.z == Tiles[i].WorldPosition.z)
This might be faster as well, depending on how many fields your WorldPosition has

math equation for fighting

I have the following code for a fight but the user will win around 99.9% of the time (tested with 5000 random loops)
I have the following variables that affect the fight
strength | defence | dexterity | damage | portal difficulty (always + 1 to stop * by 0) | critical
This is what I have so far
//player variable
//(int) player.itemDamage = 20
//(int) player.itemStr = 2
//(int) player.itemDex = 4
int defense = (int)Math.Round((((portal + 1) * ((rand.NextDouble() + 0.5))) + 5) / 2, 0);
int damage = (int)Math.Round((((portal + 1) * ((rand.NextDouble() + 0.5))) + player.itemDamage), 0);
int str = (int)Math.Round((((portal + 1) * ((rand.NextDouble() + 0.5))) + player.itemStr), 0);
int dex = (int)Math.Round((((portal + 1) * ((rand.NextDouble() + 0.5))) + player.itemDex), 0);
while(true)
{
for (int i = 0; i < 10; i++)
{
critical += rand.NextDouble();
}
eHP -= (int)Math.Round((((player.itemDamage + player.itemStr) - defense) * critical) / 2, 0);
critical = 1;
for (int i = 0; i < 10; i++)
{
critical += rand.NextDouble();
}
HP -= (int)Math.Round((((damage + str) - 5) * critical) / 2, 0);
if (eHP <= 0)
{
return;
}
else if (HP <= 0)
{
return;
}
}
What could I change in the following code to let the user (HP) win 70% of the time can I get some suggestions please? I am terrible with algorithms
Edit: Although I want the user to win 70% of the time I still want it to be round based on damage not using a simple if(0 > 70) win else loose statement because that wouldn't be a very interesting fight.
if (rand.next(10) > 7) {
//user wins
} else {
//user loses
}
In all seriousness, it is understandable why you are having trouble with this based on how you are approaching it with code. You should instead treat it like a math function.
Create a pure function f from a set of inputs (x, y, ..., z) to a boolean output. There should not be any usage of rand in this function. If you need random input, pass then into the function. Try doing it first without overwriting existing variables (don't use +=/-=). For every (x, y, z), f(x, y, z) should always result in the same output. If you do this, it should be pretty easy to use maths to solve for the missing values.
As drstevens says, your implementation would be better off split into smaller, pure functions.
In particular, the number of hit points lost appears to be proportional to the value of critical. The code you give does not show what the value of critical is when the loop starts, but after the first iteration the value will be about 5 higher when reducing 'enemy' hit points than when reducing 'user' hit points in the previous iteration, because you don't set it to 1 before adding ten random numbers to it. As critical for user is generally around 11 and for enemy around 6, it would take a strong enemy to win ( for example, one where defence is greater than the user's strength and item damage, so it gains hit points if you hit them!).
If you had written a pure function which calculated either critical or the number of hit points to subtract, this error would not have happened.

Categories

Resources