Reputation: 15
I'm trying to create a text file containing the players' scores of a hangman game. The structure of the text file should follow the order: number. name score (e.g. 1. Helen 2500). I tried to split the line so that I can introduce the data into a specific array for name and score so that I can compare the results and reorder them (the numbers remain the same: 1, 2, 3, etc.) but it doesn't work. I don't get errors but the building stops at this function because of an incorrect use of the array v[]. What do you suggest me to do to make it work?
[code]
private void New_Score(int score)
{
int k=0, i;
char[] sep = new char[] { ' ', '\n', '.' };
string line, aux1, aux2;
string n=null, s=null;
n = textBox1.Text;
s = Convert.ToString(score);
string[] part=null, nr=null, name=null, result=null;
file_path = @"D:\Visual Studio 2005\Projects\WindowsApplication2\WindowsApplication2\Resources\HighScore.txt";
StreamReader f = new StreamReader(file_path);
while ((line = f.ReadLine()) != null)
{
part = null;
v = null;
part = line.Split(sep);
i=0;
foreach(string c in part)
{
v[i]= c;
i++;
}
nr[k] = v[0];
name[k] = v[1];
result[k] = v[2];
}
for (i = 0; i < k; i++)
if (string.CompareOrdinal(s,result[i]) == 1)
{
aux1 = s;
s = result[i];
result[i] = aux1;
aux2 = n;
n = name[i];
name[i] = aux2;
}
for (i = 0; i < k; i++)
{
line = nr[i] + ". " + name[i] + " " + result[i] + "\n";
File.WriteAllText(file_path, line);
}
}
[/code]
Upvotes: 0
Views: 14011
Reputation: 20693
There is no reason to store number, line position can serve to that purpose. Even better would be serialize List with score objects to for example XML (if you want to keep human readable score file), to avoid line parsing. But if you want to store to plain text here is a simple example :
private void New_Score(int score, string name)
{
string filename = "scores.txt";
List<string> scoreList;
if (File.Exists(filename))
scoreList = File.ReadAllLines(filename).ToList();
else
scoreList = new List<string>();
scoreList.Add(name + " " + score.ToString());
var sortedScoreList = scoreList.OrderByDescending(ss => int.Parse(ss.Substring(ss.LastIndexOf(" ") + 1)));
File.WriteAllLines(filename, sortedScoreList.ToArray());
}
And later when displaying results add order number in front, something like this:
int xx = 1;
List<string> scoreList = File.ReadAllLines(filename).ToList();
foreach (string oneScore in scoreList)
{
Console.WriteLine(xx.ToString() + ". " + oneScore);
xx++;
}
Upvotes: 2
Reputation: 151720
Despite the fact this goes entirely against the saying about fishing and eating which I strongly support, I took the liberty of making a few improvements by completely rewriting your code.
First of all, I got rid of storing the position of the player in the text file. This isn't efficient, since when you add a player with the highest score (rendering him #1), you'll have to re-number everyone else that's present in the file at that point.
So the resulting file looks like this:
Foo 123
Qux 714
Bar 456
Baz 999
The main()
method looks like this:
var scores = ReadScoresFromFile("Highscores.txt");
scores.ForEach(s => Console.WriteLine(s));
Console.ReadKey();
Then there's the Highscore
class:
class Highscore
{
public String Name { get; set; }
public int Position { get; set; }
public int Score { get; set; }
public Highscore(String data)
{
var d = data.Split(' ');
if (String.IsNullOrEmpty(data) || d.Length < 2)
throw new ArgumentException("Invalid high score string", "data");
this.Name = d[0];
int num;
if (int.TryParse(d[1], out num))
{
this.Score = num;
}
else
{
throw new ArgumentException("Invalid score", "data");
}
}
public override string ToString()
{
return String.Format("{0}. {1}: {2}", this.Position, this.Name, this.Score);
}
}
You see a Highscore populates itself based on the line from the Highscore file it's fed. I populate the list of scores using this method:
static List<Highscore> ReadScoresFromFile(String path)
{
var scores = new List<Highscore>();
using (StreamReader reader = new StreamReader(path))
{
String line;
while (!reader.EndOfStream)
{
line = reader.ReadLine();
try
{
scores.Add(new Highscore(line));
}
catch (ArgumentException ex)
{
Console.WriteLine("Invalid score at line \"{0}\": {1}", line, ex);
}
}
}
return SortAndPositionHighscores(scores);
}
And finally some sorting and position assigment:
static List<Highscore> SortAndPositionHighscores(List<Highscore> scores)
{
scores = scores.OrderByDescending(s => s.Score).ToList();
int pos = 1;
scores.ForEach(s => s.Position = pos++);
return scores.ToList();
}
Resulting in:
1. Baz: 999
2. Qux: 714
3. Bar: 456
4. Foo: 123
Upvotes: 2
Reputation: 8962
Seems like a complicated way to store a simple list of high scores. Why don't you try the following.
Define a simple object to hold a player's score.
[Serializable]
public class HighScore
{
public string PlayerName { get; set; }
public int Score { get; set; }
}
Make sure you mark it with the [Serializable] attribute.
Let's quickly create a list of high scores for a couple of players.
var highScores = new List<HighScore>()
{
new HighScore { PlayerName = "Helen", Score = 1000 },
new HighScore { PlayerName = "Christophe", Score = 2000 },
new HighScore { PlayerName = "Ruben", Score = 3000 },
new HighScore { PlayerName = "John", Score = 4000 },
new HighScore { PlayerName = "The Last Starfighter", Score = 5000 }
};
Now you can use the BinaryFormatter to serialize the scores and save them to a local file.
using (var fileStream = new FileStream(@"C:\temp\scores.dat", FileMode.Create, FileAccess.Write))
{
var formatter = new BinaryFormatter();
formatter.Serialize(fileStream, highScores);
}
Later you can load the high scores from this files in a similar manner.
using (var fileStream = new FileStream(@"C:\temp\scores.dat", FileMode.Open, FileAccess.Read))
{
var formatter = new BinaryFormatter();
highScores = (List<HighScore>) formatter.Deserialize(fileStream);
}
If you want to sort them you can implement the IComparable interface on the HighScore type.
[Serializable]
public class HighScore : IComparable
{
//...
public int CompareTo(object obj)
{
var otherScore = (HighScore) obj;
if (Score == otherScore.Score)
return 0;
if (Score < otherScore.Score)
return 1;
return -1;
}
}
Now you can just call the Sort(...) on your generic List collection.
highScores.Sort();
And voila the scores are sorted in a descending order.
foreach(var score in highScores)
{
Console.WriteLine(String.Format("{0}: {1} points", score.PlayerName, score.Score));
}
Or even more simple, just use LINQ to sort the high scores.
var sortedScores = highScores.OrderByDescending(s => s.Score).ToList();
Upvotes: 1
Reputation: 14688
I would personally abstract the code a bit more, but if you don't want to add any more classes or really do anything outside of the method, here's what I'd do:
List<Tuple<int, string, int>>
list.Sort()
or LINQ to sort the listIt's a lot cleaner and way more readable than what you have in the question.
Upvotes: 4