I am trying to add a list inside a list. But I wasn't able to retrieve the items from the sub list. There is no error, but no data was retrieved from the sub list. Please focus on GenerateClue() I think the error is there.
When I'm trying to access the data using clueList[0][0], There is no data
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.UI;
public class TrainingMode : MonoBehaviour {
private List<int> answerKey;
private List<int> clue;
private List<List<int>> clueList;
private int correct;
private int wellPlaced;
public Text answerKeyText;
System.Random random = new System.Random();
void Start () {
answerKey = new List<int>();
clue = new List<int>();
clueList = new List<List<int>>();
GenerateAnswerKey();
GenerateClue();
//CheckCorrectAndWellPlaced();
answerKeyText.GetComponent<Text>().text = answerKey[0] + " "+ answerKey[1] + " "+ answerKey[2];
foreach (List<int> arrClue in clueList)
{
foreach (int item in arrClue)
{
Debug.Log(item);
}
}
}
private void GenerateClue()
{
//Generate clue
for (int j = 0; j <= 5; j++)
{
for (int i = 0; i <= 2; i++)
{
int randomNumber = random.Next(0, 9);
if (clue.Contains(randomNumber))
{
i--;
}
else
{
clue.Add(randomNumber);
}
if (clue.Count == 3)
{
clueList.Add(clue);
clue.Clear();
}
}
}
}
private void CheckCorrectAndWellPlaced()
{
correct = 0;
wellPlaced = 0;
//Check for correct and wellplaced numbers
for (int i = 0; i <= 2; i++)
{
if (answerKey.Contains(clue[i]))
{
correct++;
}
if (clue[i] == answerKey[i])
{
wellPlaced++;
}
}
}
private void GenerateAnswerKey() {
//Generate answerkey
for (int i = 0; i <= 2; i++)
{
int randomNumber = random.Next(0, 9);
if (answerKey.Contains(randomNumber))
{
i--;
}
else
{
answerKey.Add(randomNumber);
}
}
}
}
The problem is that when you add the clue to your clue list what it's actually doing is passing a reference because List<> is a class. So you end up having just 2 variables pointing to the same memory. One is your clue variable and the other is the clueList[X]. So when you call clue.Clear() you are clearing the clue list which is ACTUALLY the same memory than your clueList[X].
As as fix just change this:
if (clue.Count == 3)
{
clueList.Add(clue);
clue.Clear();
}
into this:
if (clue.Count == 3)
{
clueList.Add(new List<int>(clue));
clue.Clear();
}
Your problem is here :
if (clue.Count == 3)
{
clueList.Add(clue);
clue.Clear();
}
You're adding clue to the clueList and then clearing the clue which has the same "memory address" ( same object as in the clueList ).
So in general, you're filling the clue list with some random numbers and then you're clearing this up whenever it fills making it empty again.
Instead, try to create a new list of ints on the beginning of your first for-loop.
for (int j = 0; j <= 5; j++)
{
var list = new List<int>();
for (int i = 0; i <= 2; i++)
{
int randomNumber = random.Next(0, 9);
if (list.Contains(randomNumber))
{
i--;
}
else
{
list.Add(randomNumber);
}
if (list.Count == 3)
{
clueList.Add(list);
}
}
}
You need to create a copy of the list, so to avoid the Clear() call to act on the element put in the clueList.
if (clue.Count == 3)
{
clueList.Add(clue.ToList());
clue.Clear();
}
But I also think that there can be cases when the list won't be inserted, because there can be cases when the random number it's always the same and you keep on going out the for loop.
for (int j = 0; j <= 5; j++)
{
for (int i = 0; i <= 2; i++)
{
int randomNumber = random.Next(0, 9);
if (clue.Contains(randomNumber))
{
i--;
}
else
{
clue.Add(randomNumber);
}
if (clue.Count == 3) // EDIT: what if it never reaches 3 ?
{
clueList.Add(clue.ToList());
clue.Clear();
}
}
}
Related
I am a total newbie to programming and i have been following some tutorials on array related to housie ticket generator.The point where I am stuck is that, I have to check each rows and each rows of the 3x9 matrix should not have more the two empty cells or it cannot have more then two cells filled next to each other.I am putting random numbers on the arrays and trying to validate the rules but,the program crashes. Can someone please give me an idea.?
This is what i've tried.
for(int columnIndex=0;columnIndex<=6;columnIndex++)
{
if(game[i,columnIndex+2]!=0)
{
return -1;
}
}
And this is the whole code
using System;
namespace HelloWorld
{
class Program
{
public static void Main (String[] args)
{
for(int times=0;times<2;times++)
{
startGame();
Console.WriteLine("******************************************************************");
}
}
private static void startGame()
{
int[,] game = new int[3, 9];
int occupancyLimit = 15;
while (occupancyLimit > 0)
{
int i = getRandomNumber(3);
int j = getRandomNumber(9);
//Console.Write(i);
//Console.Write(j);
// Console.Write(game[i,j]+" ");
int data = validateAndReturnNumber(i, j, game);
if (data>0)
{
game[i, j] = data;
occupancyLimit--;
//Console.WriteLine(game[i,j]);
}
}
for (int i = 0; i < game.GetLength(0); i++)
{
for (int j = 0; j < game.GetLength(1); j++)
{
Console.Write(game[i,j] + "\t");
}
Console.WriteLine();
}
}
private static int validateAndReturnNumber(int i, int j, int[,] game)
{
//do not override existing elements in array
if (game[i,j] != 0)
{
return -1;
}
//column cannot have more then two elements
int columncounter = 0;
for(int c=0;c<3;c++)
{
if(game[c,j]!=0)
{
columncounter++;
}
}
if(columncounter>=2)
{
return -1;
}
/*
//rows cannot have more then two cells filled in and
//rows cannot have more then two empty cells
for(int columnIndex=0;columnIndex<=6;columnIndex++)
{
if(game[i,columnIndex+2]!=0)
{
return -1;
}
}
*/
// rows cannot have more then 5 elements
int rowcounter = 0;
for(int r=0;r<9;r++)
{
if(game[i,r]!=0)
{
rowcounter++;
}
}
//Applying, rows cannot have more then 5 elements
if(rowcounter>=5)
{
return -1;
}
//return getRandomNumberForColumn(j);
int data = 0;
Boolean isValueSet = false;
do
{
data = getRandomNumberForColumn(j);
isValueSet = isValueExistsInCol(game, i, j, data);
} while (isValueSet);
return data;
}
private static bool isValueExistsInCol(int[,] game, int i, int j, int data)
{
Boolean status = false;
for(int k=0;k<3;k++)
{
if(game[k,j]==data)
{
status = true;
break;
}
}
return status;
}
private static int getRandomNumberForColumn(int high)
{
if(high==0)
{
high = 10;
}
else
{
high=(high + 1) * 10;
}
int low = high - 9;
Random random = new Random();
return random.Next(high-low)+low;
}
private static int getRandomNumber(int max)
{
Random random = new Random();
int num=random.Next(max);
return (num);
}
}
}
Why your for loop does not work:
for (int columnIndex = 0; columnIndex <= 6; columnIndex++)
{
if (game[i, columnIndex + 2] != 0)
{
return -1;
}
}
This loop does not take j into account. It is testing for previous numbers added, as soon as one previous number fails this test, it will fail indefinitely. This creates an infinite loop. This loop also fails if a number is placed in any position past 1, while it needs to fill 5 positions to succeed. This is mathematically impossible.
This:
'should not have more the two empty cells or it cannot have more then two cells' is also mathematically impossible. a row of 9 cannot have less than 2 full and less than 2 empty at the same time.
I think you are after 2 empty or full consecutively in a row. For that testing for two empty in a row cannot be achieved as it starts empty, and you are testing it before you fill it. Fortunately this is a redundant test that will always be true based on all of the other test cases.
No more than 2 full in a row is possible, but can also lead to impossible scenarios. I have added a check that resets the scenario if it has not found the solution after 1000 guesses.
using System;
namespace HelloWorld
{
class Program
{
public static void Main(String[] args)
{
for (int times = 0; times < 2; times++)
{
startGame();
// Console.WriteLine("******************************************************************");
}
}
private static void startGame()
{
int iCount = 0;
int[,] game = new int[3, 9];
int occupancyLimit = 15;
while (occupancyLimit > 0)
{
int i = getRandomNumber(3);
int j = getRandomNumber(9);
//Console.Write(i);
//Console.Write(j);
// Console.Write(game[i,j]+" ");
int data = validateAndReturnNumber(i, j, game);
if (data > 0)
{
game[i, j] = data;
occupancyLimit--;
//Console.WriteLine(game[i,j]);
}
else
{
iCount++;
//Console.WriteLine(iCount);
//printGame(game);
// If X many fails, retry
if(iCount > 1000)
{
iCount = 0;
game = new int[3, 9];
occupancyLimit = 15;
}
}
// If you want to check for zeros you would need to do it here. And use while(true) above
/*
if( //Check for zeros)
{
break; // Ends While loop
}
else
{
// Reset and try again
iCount = 0;
game = new int[3, 9];
occupancyLimit = 15;
}
*/
}
printGame(game);
}
private static void printGame(int[,] game)
{
for (int i = 0; i < game.GetLength(0); i++)
{
for (int j = 0; j < game.GetLength(1); j++)
{
Console.Write(game[i, j] + "\t");
}
Console.WriteLine();
}
Console.WriteLine("******************************************************************");
}
private static int validateAndReturnNumber(int i, int j, int[,] game)
{
//do not override existing elements in array
if (game[i, j] != 0)
{
return -1;
}
//column cannot have more then two elements
int columncounter = 0;
for (int c = 0; c < 3; c++)
{
if (game[c, j] != 0)
{
columncounter++;
}
}
if (columncounter >= 2)
{
return -1;
}
if(
(j != 0 && j != 1 && game[i, j - 2] != 0 && game[i, j - 1] != 0) || // 12X
(j != 0 && j != 8 && game[i, j - 1] != 0 && game[i, j + 1] != 0) || // 1X3
(j != 7 && j != 8 && game[i, j + 1] != 0 && game[i, j + 2] != 0) // X23
)
{
return -1;
}
//for (int columnIndex = 0; columnIndex <= 6; columnIndex++)
//{
// if (game[i, columnIndex + 2] != 0)
// {
// return -1;
// }
//}
// rows cannot have more then 5 elements
int rowcounter = 0;
for (int r = 0; r < 9; r++)
{
if (game[i, r] != 0)
{
rowcounter++;
}
}
//Applying, rows cannot have more then 5 elements
if (rowcounter >= 5)
{
return -1;
}
//return getRandomNumberForColumn(j);
int data = 0;
Boolean isValueSet = false;
do
{
data = getRandomNumberForColumn(j);
isValueSet = isValueExistsInCol(game, i, j, data);
} while (isValueSet);
return data;
}
private static bool isValueExistsInCol(int[,] game, int i, int j, int data)
{
Boolean status = false;
for (int k = 0; k < 3; k++)
{
if (game[k, j] == data)
{
status = true;
break;
}
}
return status;
}
private static int getRandomNumberForColumn(int high)
{
if (high == 0)
{
high = 10;
}
else
{
high = (high + 1) * 10;
}
int low = high - 9;
Random random = new Random();
return random.Next(high - low) + low;
}
private static int getRandomNumber(int max)
{
Random random = new Random();
int num = random.Next(max);
return (num);
}
}
}
Cheers!
I am new at programming and I am trying to create a method that allows me search Id inside a [10,4] matrix, however I don't get how to do it without using nested fors and also if and else statement. The problem is related to output, I know the structure isn't correct, but since I don't what else can be done I am trying make it as it is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace menu
{
class Program
{
enum header { id, name, surname, addres };
public static int id = 1;
static void Main(string[] args)
{
string[,] matrix = new string[10, 4];
insertStudent(matrix);
idSearch(matrix);
Console.ReadKey();
}
static int generateId()
{
return id++;
}
static void insertStudent(string[,] matrix)
{
int n = generateId();
matrix[n - 1, 0] = Convert.ToString(n);
for (int i = 1; i < matrix.GetLength(1); i++)
{
do
{
Console.WriteLine($"Insert {Enum.GetName(typeof(header), i)}");
matrix[n - 1, i] = Console.ReadLine();
}
while (String.IsNullOrEmpty(matrix[n - 1, i]));
}
}
static void idSearch(string[,] matrix)
{
int idChosen=0;
Console.WriteLine($"Insert ID you want to visualize:");
int.TryParse(Console.ReadLine(), out idChosen);
for (int i = 0; i < matrix.GetLength(0); i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
if (matrix[i, 0] == Convert.ToString(idChosen))
{
Console.WriteLine(matrix[i, j]);
}
else
{
Console.WriteLine("The chosen ID does not exist");
}
}
}
}
}
}
Right now you printing "The chosen ID does not exist" every time you check an index in your matrix. You want to move that statement to outside of your loop after you've already checked every index. Right now that check is really saying that your ID is not in that specific cell. I've altered your code slightly to reflect this. I also fixed your check to be on matrix[i,j] instead of matrix[i,0]
Also using a nested for loop is OK to use. I don't believe C# has any built in helper methods for searching multidimensional arrays.
bool found = false;
for (int i = 0; i < matrix.GetLength(0); i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
if (matrix[i, j] == Convert.ToString(idChosen))
{
//note that this will print your id
Console.WriteLine(matrix[i, j]);
//this would print where it found it
Console.WriteLine("Found at [" + i + "," + j + "]");
found = true;
}
}
}
if (!found)
{
Console.WriteLine("The chosen ID does not exist");
}
ok, decided I would mess around and create a very basic Bubble sorting algorithm, I have only spent a couple hours, and this is only my second iteration of the program, and I'm kind of burnt out right now, and I seem to have hit a bit of a wall. I have it designed so that it will produce and display an Integer based on the number of transpositions it made on each round of sorting ( so I can keep an eye on it and make sure it is trending downward) and it is stuck in an infinite loop, returning the value '36' constantly.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
bool sorted = false;
int[] data = new int[100];
data = GenerateData(data);
while (sorted == false)
{
int count = Sort(data);
if (count == 0)
{
sorted = true;
}
else
{
Console.WriteLine("{0}", count);
}
}
}
public static int[] GenerateData(int[] data)
{
Random num = new Random();
for (int x = 0; x < 100; x++)
{
data[x] = num.Next(0, 99);
}
return data;
}
public static int Sort (int[] data)
{
int TempA = 0;
int TempB = 101;
int count = 0;
for (int x =0; x<100; x++)
{
TempA = data[x];
if ((x + 1) < 100)
{
TempB = data[(x + 1)];
}
else
{
TempB = 101;
}
if ( TempA > TempB)
{
data[x++] = TempA;
data[x] = TempB;
count++;
}
}
return count;
}
}
}
I think there is something wrong with these two lines
data[x++] = TempA;
data[x] = TempB;
It should either be
data[x++] = TempA;
data[x--] = TempB;
Or
data[x+1] = TempA;
data[x] = TempB;
Otherwise your for loop will end up skipping elements.
What I want to do is compare two of the same variable in a structure.
For example I have a structure like so:
struct player
{
public string name;
public int number;
}
static player[] players = new player[3];
and what I want to do is compare the numbers, so that if two players have the same number, something will happen.
This is what I tried, however it would always say two numbers were the same because it would compare two of the same
for (int i = 0; i < length; i++)
{
for (int j = 0; j < length; j++)
{
if (players[i].number == players[j].number)
{
Console.WriteLine("Same");
Console.ReadLine();
}
else
{
Console.WriteLine("Not");
Console.ReadLine();
}
}
Hopefully you understand what I mean.
Any help would be really appreciated!
Thanks
Problem is in your loop variables i and j starting both at index zero. Then you are comparing element zero to element zero and therefore the condition is true.
Update this line:
for (int j = 0; j < length; j++)
to this:
for (int j = i + 1; j < length; j++)
Edit
To be more precise. The condition evaluates to true not only for the first element, but for each element when i and j are the same. This solution bars both control variables from having the same value in any iteration.
Simple, just add a check to make sure you aren't comparing the same index, because this is the same object:
for (int i = 0; i < length; i++)
{
for (int j = 0; j < length; j++)
{
if (i == j) continue;
if (players[i].number == players[j].number)
{
Console.WriteLine("Same");
Console.ReadLine();
}
else
{
Console.WriteLine("Not");
Console.ReadLine();
}
}
Use a Class, and do it using Linq:
public class Player
{
public string Name { get; set; }
public int Number { get; set; }
}
Then in the other class have this method to cross-check
private void Match()
{
var players = new Player[3].ToList();
foreach (var found in players.ToList().Select(player => players.FirstOrDefault(p => p.Number == player.Number)))
{
if (found != null)
{
Console.WriteLine("Same");
Console.ReadLine();
}
else
{
Console.WriteLine("Not");
Console.ReadLine();
}
}
}
I have this code that has to remove all numbers from 1 to 700 containing digits bigger than 6
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Sevenland_Numbers
{
class Program
{
static void Main(string[] args)
{
List<string> numbers = new List<string>();
for (int i = 0; i <= 700; i++)
{
numbers.Add(i.ToString());
}
for (int i = 0; i <numbers.Count; i++)
{
if (numbers[i].Contains('7') || numbers[i].Contains('8') || numbers[i].Contains('9'))
{
numbers.Remove(numbers[i]);
;
}
}
for (int i = 0; i < numbers.Count; i++)
{
Console.WriteLine(numbers[i]);
}
}
}
}
but when I use Remove the list gets resized so I don't get through all the elements with the for cycle. Is there an easy way to fix this ?
Here is a simple way to do it:
var toRemove = "789";
numbers.RemoveAll(n => toRemove.Any(r => n.Contains(r)));
Just decrement the counter after you call Remove.
for (int i = 0; i <numbers.Count; i++)
{
if (numbers[i].Contains('7') || numbers[i].Contains('8') || numbers[i].Contains('9'))
{
numbers.Remove(numbers[i]);
i--;
}
}
That will cause your loop to repeat the operation using the same value, and will keep it from "skipping" over the next value in the list.
Of course, you could always use LINQ as well:
var numbers = new List<string>();
for (var i = 0; i <= 700; i++)
numbers.Add(i.ToString());
numbers = numbers
.Where(n => !(n.Contains('7') || n.Contains('8') || n.Contains('9')))
.ToList();
for (var i = 0; i < numbers.Count; i++)
Console.WriteLine(numbers[i]);
There is.
Decrement the iterator index whenever you remove an element, like this:
for (int i = 0; i <numbers.Count; i++)
{
if (numbers[i].Contains('7') || numbers[i].Contains('8') || numbers[i].Contains('9'))
{
numbers.Remove(numbers[i]);
i--;
}
}
Alternatively, you may go through the list backwards (decrementing to 0):
for (int i = numbers.Count-1; i >= 0; --)
{
if (numbers[i].Contains('7') || numbers[i].Contains('8') || numbers[i].Contains('9'))
{
numbers.Remove(numbers[i]);
}
}
That way, the math will handle itself out.
normally i would use deleting loop:
for(int i = numbers.Count - 1; i > -1; --i){
numbers.Remove(numbers[i])
}