Random XML Questions Using Fisher-Yates Shuffle - c#

I am making a Quiz/Trivia Game and have questions stored in XML file and it gets a random question. Everything works fine, but I want to stay random but not show the same question until every question has been shown.
public struct Question {
public string questionText;
public string answerA;
public string answerB;
public string answerC;
public string answerD;
public int correctAnswerID;
}
[XmlRoot("QuestionsRoot")]
public class QuestionData {
[XmlArray("Questions")]
[XmlArrayItem("Question")]
public List<Question>questions = new List<Question>();
public static QuestionData LoadFromText(string text) {
try {
XmlSerializer serializer = new XmlSerializer(typeof(QuestionData));
return serializer.Deserialize(new StringReader(text)) as QuestionData;
} catch (Exception e) {
UnityEngine.Debug.LogError("Exception loading question data: " + e);
return null;
}
}
And I use this in my other script to get a random question:
questionData = QuestionData.LoadFromText(questionDataXMLFile.text)
q = Random.Range(0, questionData.questions.Count);
currentQuestion = questionData.questions[q];

Do something along the following lines:
create another list with available questions - initialise it to the list of all questions:
questionData = QuestionData.LoadFromText(questionDataXMLFile.text)
var available = new List<Question>(questionData.question);
...
}
public Question GetNextQuestion()
{
if (available.Count == 0)
available.AddRange(questionData.question);
q = Random.Range(0, available.Count);
currentQuestion = available[q];
available.RemoveAt(q);
return currentQuestion;
}

Related

How to allow my client to interact with Lists of my code without Unity software?

I'm working on a fortune gift program.There is atleast 2 different fortune gift with a list of itself. Client also want to set the percentages of fortune gift by themself. I don't know how to let them do it. How can I let them edit the list (add more GValue, edit GWeight) and create another List?
public class GiftValue
{
public int GValue;
public int GWeight;
public GiftValue(int gvalue, int gweight)
{
GValue = gvalue;
GWeight = gweight;
}
}
public List<GiftValue> GiftwithWeight = new List<GiftValue>
{
new GiftValue(1, 25),
new GiftValue(2, 25),
new GiftValue(3, 25),
new GiftValue(5, 20),
new GiftValue(4, 5),
};
private readonly List<int> _GiftList = new List<int>();
private void Start()
{
foreach (GiftValue kvp in GiftwithWeight)
{
for (int i = 0; i < kvp.GWeight; i++)
{
_GiftList.Add(kvp.GValue);
}
}
}
public int GetRandomNumber()
{
int randomIndex = Random.Range(0, _GiftList.Count);
randomnumber=randomIndex;
return _GiftList[randomIndex];
}
I would serialize those lists as JSON and load them at runtime.
Your client can replace this file or adjust values before he starts the application.
Code would look like this.
[Serializable]
public struct GiftValue
{
public int Value;
public int Weight;
}
[Serializable]
public class GiftConfig
{
public List<GiftValue> Gifts;
}
public void LoadConfig(string filePath) {
string fileContent = File.ReadAllText(filePath);
var giftConfig = JsonUtility.FromJson<GiftConfig>(fileContent);
}
JSON would look like this:
{
"Gifts":[
{
"Value":1,
"Weight":25
},
{
"Value":2,
"Weight":25
}
]
}
Edit: Added code and json

JsonUtility.FromJson Create List<Object> [duplicate]

This question already has answers here:
Serialize and Deserialize Json and Json Array in Unity
(9 answers)
Closed 5 years ago.
I have some problems with converting a json string into a c# List!
This is my JSON that i get from form a server.
[
{"roundid":1,"coins":700,"created":"2016-03-16 11:13:26","duration":198,"score":765230},
{"roundid":3,"coins":330,"created":"2016-03-16 11:13:56","duration":123,"score":425726},
{"roundid":4,"coins":657,"created":"2016-03-16 11:21:23","duration":432,"score":75384},
{"roundid":8,"coins":980,"created":"2016-03-16 11:23:19","duration":271,"score":827200}
]
In my C# program i then try to transform my json string into useable objects using with this function
public List<Round> getPlayerRounds(string username)
{
string url = BaseURL + "op=findUserRounds&username=" + username;
var json = new WebClient().DownloadString(url);
RoundDataList rounds = JsonUtility.FromJson<RoundDataList>(json);
List<Round> playerRounds = new List<Round>();
//for (var i = 0; i < rounds.roundList.Count; i++)
for (var i = 0; i < rounds.roundList.Length; i++)
{
RoundData rd = rounds.roundList[i];
Round r = rd.getRound();
playerRounds.Add(r);
}
return playerRounds;
}
Here i get error
ArgumentException: JSON must represent an object type.
I've looked around and haven't found anything that works, Tried 2-3 solution even tried edited my php webservice that creates the JSON string.
My Classes looks like this
/* This is previus atempt to solve the issue
[Serializable]
public class RoundDataList
{
public List<RoundData> roundList;
}
*/
[Serializable]
public class RoundDataList
{
public RoundData[] roundList;
}
[Serializable]
public class RoundData
{
public int roundid;
public int coins;
public DateTime created;
public int duration;
public int score;
public Round getRound()
{
Round r = new Round();
r.Roundid = roundid;
r.Coins = coins;
r.Created = created;
r.Duration = duration;
r.Score = score;
return r;
}
}
Thank for looking at this long post!
Unity's new Json API does not support Json array and that is exactly what your problem is. There is a way to do it but it is a long process to repost again. Just read how to do it here.What you are looking for is the second solution that says "2. MULTIPLE DATA(ARRAY JSON)."
Creating a class and another class holding list of it works for me.
[Serializable]
public class Questions
{
public string id;
public string question;
public string answer1;
public string answer2;
}
[Serializable]
public class QuestionList
{
public List<Questions> list;
}
//and
var jstring = "{\"list\":[{\"id\":\"1\",\"question\":\"lorem Ipsome \",\"answer1\":\"yes\",\"answer2\":\"no\"},{\"id\":\"2\",\"question\":\"lorem Ipsome Sit dore iman\",\"answer1\":\"si\",\"answer2\":\"ne\"}]}";
var result = JsonUtility.FromJson<QuestionList>(jstring);
From a list, Convert to JSON
List<Questions> questionlist = new List<Questions>();
questionlist.Add(new Questions()
{
answer1 = "yes",
answer2 = "no",
id = "1",
question = "lorem Ipsome "
});
questionlist.Add(new Questions()
{
answer1 = "si",
answer2 = "ne",
id = "2",
question = "lorem Ipsome Sit dore iman"
});
var ql = new QuestionList();
ql.list = questionlist;
var result = JsonUtility.ToJson(ql);
//this gives
{"list":[{"id":"1","question":"lorem Ipsome ","answer1":"yes","answer2":"no"},{"id":"2","question":"lorem Ipsome Sit dore iman","answer1":"si","answer2":"ne"}]}
Note: "list" and questionList.list should be in same name.

Input String Was Not In A Correct Format. int.Parse(array[0]); [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 7 years ago.
Improve this question
Im pretty new to C# and using an open source code that connects to the website and trades items.
My previous question was very stupid and Im very sorry!
I found where the code stops and need suggestions on how to fix the error. - http://i.imgur.com/qqeMOUn.png
I also tagged where I think the error is with //Code stops on this line!
namespace BOT
{
internal static class Program
{
private const string serverName = "http://MYVPSIP/ezyskins.php";
private const string serverDemon = "ws://MYVPSIP:5555";
public static List<IWebSocketConnection> allsockets = new List<IWebSocketConnection>();
public static WebSocketServer server = new WebSocketServer(serverDemon);
public static WebClient wc = new WebClient();
public static GameJson GJ = new GameJson();
public static List<DepositItem> DI = new List<DepositItem>();
public static List<DepositUser> DU = new List<DepositUser>();
public static Thread ResolveSocketsThread;
public static Thread GameThread;
public static Thread TradeBotThread;
public static Thread SendBotThread;
public static Thread SteamAuth;
public static Thread ClearInfo;
public static int globalGameID = 0;
public static string winnersecretkey;
public static List<string> FoundPrices = new List<string>();
public static List<string> resTrades = new List<string>();
public static List<string> waitTrades = new List<string>();
public static List<string> BannedSteamID = new List<string>();
public static object steamRequest = new object();
public static object lockSocket = new object();
public static string username = ""; //Bot Login
public static string password = ""; //Bot Pass
public static string steamID = ""; //Steam64 ID
public static string sessionID = ""; //Cookies
public static string steamLogin = ""; //Cookies
public static string steamLoginSecure = ""; //Cookies
public static string machineAuth = ""; //Cookies
public static string steamApiKey = ""; //Bots Api
public static string webServerSecretKey = ""; Secret Key
public static int gameID = 0;
public static double gameKey = 0.0;
public static int totalItems = 0;
public static double totalPrice = 0.0;
public static double totalPrice2 = 0.0;
public static long closeAt = 0L;
public static long openAt = 0L;
public static double last_ticket = 0.0;
public static string hash = string.Empty;
public static DepositUser winner;
public static string totalwinner;
public static bool deposits = false;
public static bool timerStarted = false;
public static bool gameStarted = false;
public static NumberFormatInfo nfi = NumberFormatInfo.CurrentInfo;
[STAThread]
private static void Main()
{
try
{
string source = string.Empty;
using (HttpRequest httpRequest = new HttpRequest())
{
RequestParams requestParams = new RequestParams();
httpRequest.Cookies = new CookieDictionary(false) {
{
"key", webServerSecretKey
}
};
requestParams["method"] = "getinfo";
source = httpRequest.Post(serverName, requestParams, false).ToString();
}
string[] array = Program.explode("(|)", source);
Program.globalGameID = int.Parse(array[0]); //Code stops on this line!
Program.winnersecretkey = array[1];
Program.server.SupportedSubProtocols = new string[] {
"ezyskins"
};
Program.ResolveSocketsThread = new Thread(new ThreadStart(Program.ResolveSockets));
Program.GameThread = new Thread(new ThreadStart(Program.Game));
Program.TradeBotThread = new Thread(new ThreadStart(Program.TradeBot));
Program.SendBotThread = new Thread(new ThreadStart(Program.SendBotT));
Program.SteamAuth = new Thread(new ThreadStart(Program.SteamAuthT));
Program.ClearInfo = new Thread(new ThreadStart(Program.ClearInfoT));
Program.GameThread.IsBackground = true;
Program.TradeBotThread.IsBackground = true;
Program.ResolveSocketsThread.IsBackground = true;
Program.SendBotThread.IsBackground = true;
Program.SteamAuth.IsBackground = true;
Program.ClearInfo.IsBackground = true;
Program.ResolveSocketsThread.Start();
Program.GameThread.Start();
Program.TradeBotThread.Start();
Program.SendBotThread.Start();
Program.SteamAuth.Start();
Program.ClearInfo.Start();
while (true)
{
string a = Console.ReadLine();
if (a == "clear")
{
Console.Clear();
}
if (a == "save-online")
{
Console.WriteLine("Sockets: " + Program.allsockets.Count<IWebSocketConnection>());
foreach (IWebSocketConnection current in Program.allsockets)
{
string text = "";
if (File.Exists("online.txt"))
{
text = File.ReadAllText("online.txt");
}
foreach (KeyValuePair<string, string> current2 in current.ConnectionInfo.Headers)
{
File.WriteAllText("online.txt", string.Concat(new object[] {
text, "\r\n", current.ConnectionInfo.ClientIpAddress, ":", current.ConnectionInfo.ClientPort, " (", current2.Key, ": ", current2.Value, ")"
}));
}
}
}
if (a == "restart")
{
Program.ResolveSocketsThread.Abort();
Program.ResolveSocketsThread.Start();
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message); // ----> This gets printed out! <----
Console.Read();
}
}
You should investigate what's in the inside of the array. If value if cannot be parsed into number, exception will be thrown.
Print the array into the debug console or set break point to parsing line and add array into watch if you're using visual studio.
You are not giving valid integer value to int.Parse because of that you receive this exception. In this case you can't use int.TryParse because you need your game ID. What I advice you is to debug your code and see what are the value of array.
You need to add this lines if you want to see it in the console.
foreach(string sArr in array)
{
Console.WriteLine(sArr);
}
After that see on which position is your game ID and put it in the int.Parse.

Permanently in while loop c# , Visual Studio 2013

with my code, I'm supposed to be able to call a question from my file at random and not reuse that question again.
But for some reason I'm stuck in the while loop and after a few hours of searching I still can't see why, so I hope you guys can help me out.
(he gets stuck after he generated 8 questions)
Code (for the generatequestion one, if you need more I can paste it but I hope this gives enough information):
lineCount = File.ReadLines(pad).Count();
questions = new string[lineCount, 2];
public string GenerateQuestion(int total)
{
if (total <= 10)
{
Random ran = new Random();
questionNumber = ran.Next(lineCount);
while (previousQuestions.Contains(questionNumber))
{
questionNumber = ran.Next(lineCount);
}
}
previousQuestions[questionCount] = questionNumber;
questionCount++;
return questions[questionNumber, 0];
}
You could make a method to return the lines in the file in random order.
public string[] GetQuestionsInRandomOrder()
{
var lines = File.ReadAllLines("test.txt");
var rnd = new Random();
lines = lines.OrderBy(line => rnd.Next()).ToArray();
return lines;
}
Then as you use the questions you can remove them from the array.
var isRemoved = Array.remove(array, item);
https://msdn.microsoft.com/en-us/library/vstudio/bb397721%28v=vs.100%29.aspx
This is easier that what I had before and will give greater control. I would create a class for this and this example is a starting point. You can add more functionality as you go along. By having a class to do all this work you can add methods to do additional features later on without having to rewrite code.
public class Logic
{
public List<string> AllQuestionsInRandomOrder { get; set; }
public List<string> QuestionsThatHaveBeenRemoved { get; set; }
public Logic()
{
QuestionsThatHaveBeenRemoved = new List<string>();
AllQuestionsInRandomOrder = GetQuestionsInRandomOrder().ToList();
}
public string GetUnusedQuestion()
{
var question =
AllQuestionsInRandomOrder.FirstOrDefault(x => !QuestionsThatHaveBeenRemoved.Contains(x));
QuestionsThatHaveBeenRemoved.Add(question);
return question;
}
public IEnumerable<string> GetQuestionsInRandomOrder()
{
var lines = File.ReadAllLines("test.txt").ToList();
var rnd = new Random();
lines = lines.OrderBy(line => rnd.Next()).ToList();
return lines;
}
public void RemoveQuestion(List<string> questions, string questionToRemove)
{
questions.Remove(questionToRemove);
}
}
I would avoid using loops and break the problem into separate methods or functions. It will make it easier to debug. This implementation does not separate the questions and answers out, so you will need to add a method that returns a dictionary of the questions and answers.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
var questions = new Questions();
var firstQuestion = questions.GetUnusedQuestion();
Console.WriteLine(firstQuestion);
}
}
class Questions
{
public string FileName { get; set; }
public static List<string> AllQuestionsAndAnswersFromFile { get; set; }
public List<string> AllQuestionsInRandomOrder { get; set; }
public List<string> QuestionsThatHaveBeenRemoved { get; set; }
public Questions()
{
FileName = "text.txt";
QuestionsThatHaveBeenRemoved = new List<string>();
AllQuestionsAndAnswersFromFile = new List<string>();
ReadQuestionsFromFile();
AllQuestionsInRandomOrder = GetQuestionsInRandomOrder().ToList();
}
public string GetUnusedQuestion()
{
var question =
AllQuestionsInRandomOrder.FirstOrDefault(x => QuestionsThatHaveBeenRemoved.Contains(x));
QuestionsThatHaveBeenRemoved.Add(question);
return question;
}
private static IEnumerable<string> GetQuestionsInRandomOrder()
{
var lines = AllQuestionsAndAnswersFromFile;
var rnd = new Random();
lines = lines.OrderBy(line => rnd.Next()).ToList();
return lines;
}
public void RemoveQuestion(List<string> questions, string questionToRemove)
{
questions.Remove(questionToRemove);
}
public void ReadQuestionsFromFile()
{
using (var reader = new StreamReader(FileName, Encoding.Default))
{
var text = reader.ReadToEnd();
var lines = text.Split('=');
foreach (var s in lines)
{
AllQuestionsAndAnswersFromFile.Add(s);
}
}
}
}
}
When you run out of questions, let's see what
while (previousQuestions.Contains(questionNumber))
{
questionNumber = ran.Next(lineCount);
}
actually does:
Is questionNumber one of the questions we already asked?
Yes, get a new question number. (because we've asked all the questions)
Is questionNumber one of the questions we already asked?
yes, get a new question number. (because we've asked all the questions)
A solution in this case would be to shuffle your questions that you return, removing them as you grab them.

C# custom object in combobox

I am relatively new to C# (WinForms), and had a question regarding combo boxes. I have a combo box of Reviewer objects (it is a custom class with an overridden ToString method) and am currently attempting to go through all the checked items and use them to generate a setup file.
Here is how the combo box is populated (populated on form load). Parameters is just a collection of linked lists and parsing code.
for (int i = 0; i < parameters.GetUsers().Count; i++)
{
UserList.Items.Add(parameters.GetUsersArray()[i], parameters.GetUsersArray()[i].isSelected());
}
Here is how I am trying to read it. setup is a StringBuilder. The problem is that GetID is not defined. Does the add function above cast the Reviewer object to a Object object? It looks a little funny since it creates a file fed into a Perl script. A sample desired output line looks like this: inspector0 => "chg0306",
for (int i = 0; i < UserList.CheckedItems.Count; i++)
{
setup.AppendLine("inspector" + i.ToString() + " => \t \"" +
UserList.CheckedItems[i].GetID() + "\",");
}
Here is the users class: (Sample User is ID = aaa0000 name: Bob Joe)
public class Reviewer
{
private string name;
private string id;
private bool selected;
public Reviewer(string newName, string newID, bool newSelected)
{
name = newName;
id = newID;
selected = newSelected;
}
public string GetName()
{
return name;
}
public override string ToString()
{
//string retVal = new string(' ', id.Length + name.Length + 1);
string retVal = id + '\t' + name;
return retVal;
}
public string GetID()
{
return id;
}
public bool isSelected()
{
return selected;
}
}
For posterity, here is the Parameters class:
public class ParameterLists
{
public ParameterLists()
{
projects = new LinkedList<string>();
reviewers = new LinkedList<Reviewer>();
}
public enum FileContents {
PROJECT_LIST,
USERS_LIST,
}
public LinkedList<Reviewer> GetUsers()
{
return reviewers;
}
public LinkedList<string> GetProjects()
{
return projects;
}
public Reviewer[] GetUsersArray()
{
Reviewer[] userArray = new Reviewer[reviewers.Count];
reviewers.CopyTo(userArray, 0);
return userArray;
}
public string[] GetProjectsArray()
{
String[] projectArray = new String[projects.Count];
projects.CopyTo(projectArray, 0);
return projectArray;
}
public void LoadParameters(string fileName)
{
//Reads the parameters from the input file.
}
private void CreateDefaultFile(string fileName)
{
// Create the file from the defaultfile , if it exists.
// Otherwise create a blank default file.
}
private LinkedList <string> projects;
private LinkedList <Reviewer> reviewers;
}
I am probably missing something simple, coming from embedded C++. Any help would be appreciated.
You have to cast that object:
((Reviewer)UserList.CheckedItems[i]).GetID()

Categories

Resources