I have an array of text and an array of fields, I need to implement so that when a user enters a value in a field, the value is compared with the text for this field. I.e., for example, the number "12" is written in one text field, and the user entered "13" and "Not correct" was output to the log, and there are 6 such fields and text. (this is the solution of the number 6+6=12) Please tell me how to do it better, I started doing this:
public InputField[] Inputfield1;
public Text[] text1;
public void CurBtn()
{
foreach (InputField inputField in Inputfield1)
{
for (int i = 0; i < text1.Length; i++)
{
for (int j = 0; j < Input_Numer_1.Length; j++)
{
if (text1[i].ToString() == Inputfield1[j].text)
{
Debug.LogFormat($"OK");
}
else{
Debug.LogFormat($"Not correct");
}
}
}
}
Text is a UnityEngine.Object and Object.ToString basically returns the GameObjects name like Text.name.
You rather would want it's UI.Text.text
if(text1[i].text == Inputfield1[j].text)
However, why not rather actually store int values and use int.TryParse to convert your user input to a numeric values and rather compare int based which is way more efficient.
You also have one loop to much there .. currently you iterate the inputs twice.
To me it sounds like you don't even want to compare each input to each text but rather have certain pairs of both you want to compare like
[Serializable]
public class CheckPair
{
public InputField Input;
public Text Text;
public bool Compare()
{
var correct = Text.text == Input.text;
Debug.Log($"{correct ? "" : "NOT "} correct", Input);
return correct;
}
}
And in the Inspector rather assign these in a single
public CheckPair pairs;
and then
public void CurBtn()
{
foreach (var pair in pairs)
{
pair.Compare();
}
}
or if you e.g. want to know if all are correct
public void CurBtn()
{
foreach (var pair in pairs)
{
if(!pair.Compare())
{
Debug.Log($"{pair.Input} is not correct!");
return;
}
}
Debug.Log("All are correct!");
}
Related
Okay so I'm trying to make a system that picks a random word then it turns that word into a char array. Then it will track if you type the characters. But the method that I'm trying to do hasn't been working. mainly because it won't let me use a variable name as a keycode. Is this a worthwhile problem, or should I abort mission and try something else.
string currentWord = wordArray[Random.Range(0, typingWords.Length)];
char[] wordAsArray = currentWord.ToCharArray();
Keycode currentLetter = wordAsArray[0];
if (Input.GetKey(currentLetter))
{
Debug.Log("Test");
}
most of this works fine but what doesn't work the problem is the if (Input.GetKey(currentLetter))
is there something that can turn the word into a KeycodeArray or something like that or turn the specific character into keycode.
Does anybody know if this problem is solvable or will I have to use another method.
is there something that can turn the word into a KeycodeArray or something like that or turn the specific character into keycode.
There is not a built-in function for that. You can create a keycode array with each keycodes in it and use that to determine current letter. Like:
KeyCode[] letterCodes = new KeyCode[] {
KeyCode.A, KeyCode.B, KeyCode.C, ... KeyCode.Z
};
KeyCode currentLetterCode = letterCodes[wordAsArray[0] - 'A'];
'A' is subtracted from it to get the index of the letter in the letterCodes array. This assumes that the word only contains uppercase letters.
Instead of that method i would use a different approach. I will write down a complete example of how i would do it with comments.
public class TypingGame : MonoBehaviour
{
public Text wordText;
private string currentWord;
private int currentIndex;
private void Start()
{
// Pick a random word to type
currentWord = GetRandomWord();
// Display the word on screen
wordText.text = currentWord;
}
private void Update()
{
// Check if the current letter has been typed
if (Input.anyKeyDown)
{
KeyCode keyPressed = GetKeyPressed();
if (keyPressed != KeyCode.None && keyPressed == GetNextKeyCode())
{
currentIndex++;
if (currentIndex >= currentWord.Length)
{
// The word has been completely typed
currentWord = GetRandomWord();
wordText.text = currentWord;
currentIndex = 0;
}
else
{
// Update the display to show the next letter
wordText.text = currentWord.Substring(currentIndex);
}
}
}
}
private string GetRandomWord()
{
// Replace this with your own word selection logic
string[] words = { "cat", "dog", "bird", "fish" };
return words[Random.Range(0, words.Length)];
}
private KeyCode GetNextKeyCode()
{
char nextChar = currentWord[currentIndex];
KeyCode keyCode = (KeyCode)System.Enum.Parse(typeof(KeyCode), nextChar.ToString().ToUpper());
return keyCode;
}
private KeyCode GetKeyPressed()
{
foreach (KeyCode keyCode in System.Enum.GetValues(typeof(KeyCode)))
{
if (Input.GetKeyDown(keyCode))
{
return keyCode;
}
}
return KeyCode.None;
}
}
GetNextKeyCode method converts the next letter in the word to a KeyCode value by converting the letter to uppercase and using System.Enum.Parse to look up the corresponding KeyCode value.
GetKeyPressed method checks which key was pressed and returns the corresponding KeyCode value by looping over all possible KeyCode values and checking which one has been pressed using Input.GetKeyDown.
I'm dealing with some legacy data, where they store each record in one huge/large string (one string = one record)
In each string, they split the data in some sort of delimiters, but each of them actually defines a meaning, for example: \vToyota\cBlue\cRed\cWhite\s200mph\oAndrew\oJohn
\v means vehicle, \c is color, \s is speed \o is Owner... something like that
My task requires me to reformat the data so that if there are multiple fields of one characteristic, I have to rewrite it as: (for example) \vToyota\cBlue\c2Red\c3White\s200mph\oAndrew\o2John
Edited: Alright. #DarrenYoung's suggestions works! Now I have an array of vToyota cBlue cRed cWhite s200mph oAndrew oJohn. I tested on other data using the same method and it is working too. Now I just need help to find a way to rewrite the first letter of each string whenever they are repeated.
Thank you!
I found this an interesting little puzzle to see what I could do with LINQ. The following seems to work:
private string FixIt(string foo)
{
var newFoo = "\\" + string.Join("\\",
foo.Split(new[] {'\\'}, StringSplitOptions.RemoveEmptyEntries)
.GroupBy(s => s[0],
(c, g) =>
{
var cnt = 0;
return g.Select(x => cnt++ == 0
? x
: x[0] + cnt.ToString() + x.Substring(1));
})
.SelectMany(g => g));
return newFoo;
}
Input: \vToyota\cBlue\cRed\cWhite\s200mph\oAndrew\oJohn
Output: \vToyota\cBlue\c2Red\c3White\s200mph\oAndrew\o2John
That SelectMany is a handy thing to remember.
Because I thought this question was interesting I wrote up a program to do what I believe to be a reasonable solution. I started with a few principle assumptions:
In "old data" situations you probably don't know every single option that is going to show up in the records. Consequently whatever approach is taken needs to quickly and easily accommodate new types of delimiters and tags. For that reason I did not use a string.split approach (even though this is easier to read). Instead all tokens are declared at the beginning of the file. Anything can be a token whether or not it has a "\" in front of it.
The solution needs to gracefully handle records that don't conform to the standards
The option of parsing integers for multiple records needs to be able to be disabled per record type. Speed, for example, doesn't (seem) to be able to appear multiple times per record. So, setting the value for speed to false in the "ALLOW_MULTIPLE" variable turns this parsing off, ensuring the correct output value.
In my solution I also created separate classes for readability and so the code could be quickly investigated. Although I would not suggest that this is production ready, the following should go a long ways towards solving the issue. Best of luck!
// Just paste the rest of this into a new console application to see it work!
public class Program
{
private static readonly List<string> TOKENS = new List<string> {#"\v", #"\c", #"\o", #"\s"};
private static readonly List<string> DISPLAY = new List<string> {"Vehicle", "Color", "Owner", "Speed"};
private static readonly List<bool> ALLOW_MULTIPLE = new List<bool> {false, true, true, false};
private class RecordEntry
{
public string Value { get; set; }
public int Index { get; set; }
public string DataType { get; set; }
public override string ToString() { return DataType + ": " + Value; }
}
private class ParsedRecord
{
private List<RecordEntry> entries = new List<RecordEntry>();
public List<RecordEntry> Entries { get { return entries; } }
}
public static void Main(string[] args)
{
// sample records (second has a \m which is ignored since it isn't a recognized token)
var records = new[] {#"\vToyota\cBlue\c2Red\c3White\s200mph\oAndrew\o2John",
#"\vChevy\c2Orange\cGreen\s50mph\o2Bob\mWhite"};
var parsedData = new List<ParsedRecord>();
foreach (var record in records)
{
// character by character parsing
var currentParseRecord = new ParsedRecord();
parsedData.Add(currentParseRecord);
var currentRecord = new StringBuilder(record);
var currentToken = new StringBuilder();
for (var parseIdx = 0; parseIdx < currentRecord.Length; parseIdx++)
{
currentToken.Append(currentRecord[parseIdx]);
var recordIdx = 0;
var index = TOKENS.IndexOf(currentToken.ToString());
if (index < 0) continue;
// current char is used up now (was part of the token)
parseIdx++;
if (ALLOW_MULTIPLE[index] && currentRecord.Length > parseIdx + 1)
{
// assuming less than 10 records max - if more, would need to pull multiple numeric values here
if (!Int32.TryParse(currentRecord[parseIdx] + "", out recordIdx)) recordIdx = 0;
else parseIdx++;
}
// find the next token or end of string
int valueLength = FindNextToken(currentRecord, parseIdx) - parseIdx;
if (valueLength <= 0) valueLength = currentRecord.Length - parseIdx;
currentParseRecord.Entries.Add(new RecordEntry
{
DataType = DISPLAY[index],
Index = recordIdx,
Value = currentRecord.ToString(parseIdx, valueLength)
});
parseIdx += valueLength - 1;
currentToken.Clear();
}
}
}
private static int FindNextToken(StringBuilder value, int currentIndex)
{
for (var searchIdx = currentIndex; searchIdx < value.Length; searchIdx++) {
if (TOKENS.Any(checkToken => value.Length > searchIdx + checkToken.Length &&
value.ToString(searchIdx, checkToken.Length) == checkToken)) {
return searchIdx;
}
}
return -1;
}
}
I am looping through a list and would like to add multiple occurrences, should I find them.
so far I have,
public struct optionsSort
{
public string name;
public string date;
public double strike;
public string callPut;
public double size;
public string isin;
}
List<List<optionsSort>> stocks = new List<List<optionsSort>>();
optionsSort tempStock1 = new optionsSort();
List<optionsSort> posCheckOptions = new List<optionsSort>();
then some code, then,
for(int k = 0; k<posCheckOptions.Count; k++)
{
for(int l = 0; l<posCheckOptions[l].Count; l++)
{
if(posCheckOptions[l+1] == null)
{
//finished the iteration
break;
}
else if
(posCheckOptions[k][l + 1].date == posCheckOptions[k][l].date
&& posCheckOptions[k][l + 1].strike == posCheckOptions[k][l].strike
&& posCheckOptions[k][l + 1].callPut == posCheckOptions[k][l].callPut)
{
posCheckOptions[k][l].size = posCheckOptions[k][l].size
+ posCheckOptions[k][l + 1].size;
}
}
}
Basicly, Im looking forward from the start of the list. asking the question, are certain elements of the list at i+1 the same as i, if so, add those elements to i and delete the entire row.
i get this error
"Error 1 Cannot modify the return value of 'System.Collections.Generic.List.this[int]' because it is not a variable C:\Users\WindowsFormsApplication1\WindowsFormsApplication1\ReadCSV.cs 890 25 WindowsFormsApplication1
"
Many Thanks for looking.
I believe your problem is that you are using a mutable struct. Mutable structs are evil.
The simplest solution is to change optionsSort to a class. That should fix the error message.
To explain the error message, when you call posCheckOptions[k][l], since optionsSort is a struct, it returns a copy of the value in the list. When you change size, it will update the copy, but not the one in the list. The copy would then be discarded. The compiler recognizes this and stops you.
I recommend you read up on the differences between reference types and value types.
I am working on a program that would allow the user to build digital circuits from virtual logic gates. Every gate would be an instance of a class that represents particular gate type, for example here's how AND class looks:
public class andgate
{
public andgate()
{
inputs = new bool[7];
for (int i = 0; i < 7; i++) inputs[i] = true;
output = (inputs[0] && inputs[1] && inputs[2] && inputs[3] && inputs[4] && inputs[5] && inputs[6]);
}
public bool[] inputs;
public bool output;
}
Every gate has seven inputs but not all of them have to be used (i.e. for a gate with three imputs the remaining four will just be "1" which is AND's neutral element anyway). Each input is a reference to an output of another gate or to an element of bool array (which stores the input vector) so that signal generated by one gate automatically is sent to the following gate. The problem is I also need the signal to be transmitted dynamically within the gate, i.e. if one of the input signals in AND gate is set to 0 then the output automatically has a 0 value. Therefore when you feed a binary vector to the inputs of the cirtuit, it changes the values of the circuit's outputs. Or maybe there's an easier way to simulate a circuit than building it from individual gates? I need it for test pattern generating.
Make the output property read-only:
public bool output
{
get
{
return inputs.All(i => i);
}
}
Instead of ANDing all the inputs, just check if there is any input that is false.
Of course you have to remove the assignment to output in the constructor. This should make your output property "dynamic".
You may also want to change the inputs to bool?[] instead, so that a null value would signify that there is no signal. You will then have to remove the initialization of the input array to all true and change the output return to:
return inputs.All(i => i.GetValueOrDefault(true));
Edited with Tim S's suggestions in the comments
For this, you should use a properties to set/get the inputs, as you can perform additional computations in a property. The state variables you're holding should be private.
public bool[] Inputs {
set {
inputs = value;
}
}
public bool Output {
get {
return inputs[0] && inputs[1] ...
}
}
I would avoid doing this for the Inputs property, since exposing arrays is really exposing information about how the class stores things, which should be avoided where possible for good OOP. A ReadOnlyCollection might be more suitable, for example.
However, I would rethink the design in general, and avoid having some arbitrary # of inputs, 7. Where have you conjured that value from?
A more simplistic approach would be to assume that a gate takes 2 values - A and B, for which you can set the values in the constructor or individual properties.
You then take advantage of the fact that operations on binary logic gates are associative, so an AND gate taking a, b, c, is equivalent to one taking a, b, feeding it's output to another which also takes c. This is how you'd build a circuit in practice anyway - the issue you need to consider is the latency of the gate though.
It sounds like you should add events into your gates, such that when their state changes they're able to notify dependant objects; something like this:
public class AndGate
{
private bool[] inputs;
private bool output;
public bool[] Inputs
{
get
{
return this.inputs;
}
set
{
this.inputs = value;
UpdateOutput();
}
}
public bool Output
{
get
{
return this.output;
}
}
public AndGate()
{
inputs = new bool[7];
for (int i = 0; i < 7; i++) inputs[i] = true;
UpdateOutput();
}
private void UpdateOutput()
{
bool original = output;
output = true;
for(int i=0; i<inputs.Length; i++)
{
output = output && inputs[i];
}
if (original != output)
{
OnChanged(EventArgs.Empty);
}
}
public event GateStateChangedEventHandler StateChanged;
protected virtual void OnChanged(EventArgs e)
{
if (StateChanged != null)
{
StateChanged(this, e);
}
}
}
for (int i = (int)MY_ENUM.First; i <= (int)MY_ENUM.Last; i++)
{
//do work
}
Is there a more elegant way to do this?
You should be able to utilize the following:
foreach (MY_ENUM enumValue in Enum.GetValues(typeof(MY_ENUM)))
{
// Do work.
}
Enums are kind of like integers, but you can't rely on their values to always be sequential or ascending. You can assign integer values to enum values that would break your simple for loop:
public class Program
{
enum MyEnum
{
First = 10,
Middle,
Last = 1
}
public static void Main(string[] args)
{
for (int i = (int)MyEnum.First; i <= (int)MyEnum.Last; i++)
{
Console.WriteLine(i); // will never happen
}
Console.ReadLine();
}
}
As others have said, Enum.GetValues is the way to go instead.
Take a look at Enum.GetValues:
foreach (var value in Enum.GetValues(typeof(MY_ENUM))) { ... }
The public static Array GetValues(Type enumType) method returns an array with the values of the anEnum enumeration. Since arrays implements the IEnumerable interface, it is possible to enumerate them.
For example :
EnumName[] values = (EnumName[])Enum.GetValues(typeof(EnumName));
foreach (EnumName n in values)
Console.WriteLine(n);
You can see more detailed explaination at MSDN.