C# DataTable objects output - c#

How do I output the value of this table because it outputs to me:
lab5.FootballTeam - lab5.Tournament - System.Collections.Generic.HashSet`1[System.Int32]
lab5.FootballTeam - lab5.Tournament - System.Collections.Generic.HashSet`1[System.Int32]
lab5.FootballTeam - lab5.Tournament - System.Collections.Generic.HashSet`1[System.Int32]
And i need:
title1 city1 1910 turnirtilte1 true 1950 1980 1989
title2 city2 1920 turnirtilte1 true 1950 1991 1995
title3 city3 1930 turnirtilte1 true 1950 2002
Here is my code:
using System;
using System.Data;
using System.Collections.Generic;
namespace lab5
{
class FootballTeam
{
public string title;
public string city;
public int foundationYear;
public FootballTeam(string title1, string city1, int foundationYear1)
{
title = title1;
city = city1;
foundationYear = foundationYear1;
}
public string Print()
{
return $"{title},{city},{foundationYear}";
}
}
class Tournament
{
public string title;
public Boolean international;
public int foundationYear;
public Tournament(string title1, Boolean international1, int foundationYear1)
{
title = title1;
international = international1;
foundationYear = foundationYear1;
}
public string Print()
{
return $"{title},{international},{foundationYear}";
}
}
class Program
{
static void Main(string[] args)
{
var date1 = new DateTime(2008, 5, 1);
HashSet<int> set1 = new HashSet<int>();
HashSet<int> set2 = new HashSet<int>();
HashSet<int> set3 = new HashSet<int>();
HashSet<int> turnir = new HashSet<int>();
FootballTeam team1 = new FootballTeam("title1", "city1", 1910);
FootballTeam team2 = new FootballTeam("title2", "city2", 1920);
FootballTeam team3 = new FootballTeam("title3", "city3", 1930);
Tournament tournament1 = new Tournament("turnirtilte1", true, 1950);
turnir.Add(1980);
turnir.Add(1989);
turnir.Add(1991);
turnir.Add(1995);
turnir.Add(2002);
set1.Add(1980);
set1.Add(1989);
set2.Add(1991);
set2.Add(1995);
set3.Add(2002);
DataTable dt = new DataTable();
dt.Columns.Add("FootballTeam", typeof(FootballTeam));
dt.Columns.Add("Tournament", typeof(Tournament));
dt.Columns.Add("HashSet", typeof(HashSet<int>));
dt.Rows.Add(team1, tournament1, set1);
dt.Rows.Add(team2, tournament1, set2);
dt.Rows.Add(team3, tournament1, set3);
var selectedBooks = dt.Select();
foreach (var b in selectedBooks)
{
Console.WriteLine("{0} - {1} - {2}", b["FootballTeam"], b["Tournament"], b["HashSet"]);
}
}
}
}
Thank you very much.

Rename the Print() methods so they override ToString(). The WriteLine() method automatically calls ToString() when formatting the value into the template.
Alternatively, you can change b["FootballTeam"] to b["FootballTeam"].Print(), and do the same for the Tournament.
Then you also need to loop through your HashSet. Collections in .Net will never automatically print the items. You have to do that work yourself to print each individual item yourself. Sometimes you can use String.Join() to help with this.

Related

How to loop to add items up to a quantity

I'm trying to make a loop to add 10 items but only add one with the number 10.
List<Contact> listContact;
for (int cuantidade = 0; cuantidade < 10; cuantidade++)
{
listContact = new List<Contact>(cuantidade)
{
new Contact()
{
Name = cuantidade.ToString(),
Number = cuantidade.ToString(),
},
};
}
this.listBoxNames.ItemsSource = listContact;
What am I doing wrong?
Try this:
var contactList= new List<Contact>();
for (int cuantidade = 0; cuantidade < 10; cuantidade++)
{
contactList.Add(new Contact
{
Name = cuantidade.ToString(),
Number = cuantidade.ToString(),
});
}
this.listBoxNames.ItemsSource = contactList;
You need to set the list before the loop. With your current code, at every iteration the list is redefined and resets...
Here is an alternate example pair using Linq
The first just gets 10
The second starts at one point (13) and then gets the next 7
I used a number generator just for the example but it could be any source.
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
// Generate a sequence of integers from 9 to 50
IEnumerable<int> quanityNumbers = Enumerable.Range(9, 50);
// just take the first 10:
List<Contact> contacts = quanityNumbers
.Take(10)
.Select(a => new Contact()
{
Name = a.ToString(),
Number = a.ToString()
}).ToList();
Console.WriteLine($"Hello World contacts has {contacts.Count} items");
foreach (var c in contacts)
{
Console.WriteLine($"contacts has Name: {c.Name} with Number: {c.Number}");
}
//Start at some point and take 7 from there:
List<Contact> contactsFromTo = quanityNumbers
.Skip(13)
.Take(7)
.Select(a => new Contact()
{
Name = a.ToString(),
Number = a.ToString()
}).ToList();
Console.WriteLine($"Hello World contactsFromTo has {contactsFromTo.Count} items");
foreach (var c in contactsFromTo)
{
Console.WriteLine($"contactsFromTo has Name: {c.Name} with Number: {c.Number}");
}
}
public class Contact
{
public string Name { get; set; }
public string Number { get; set; }
}
}

Same random values are inserted into a collection repeatedly C#

This might be silly, but I'm stuck on this. I have a list with a property that has a default value. What I will do is update the property in the list using a random value, and then store the list with the new values on it inside a Dictionary. The dictionary's key is int, which represents the year, and the value is the list. The problem is only the last set of random values are stored in the dictionary. Please check my code
public static void Main()
{
List<int> numbers = new List<int>(){ 0, 1, 2, 3 ,4};
Dictionary<int, List<TestClass>> testAllYearsList = new Dictionary<int, List<TestClass>>();
int year = 2018;
var random = new Random();
List<TestClass> testList = new List<TestClass>();
testList = db;//assuming the values here are fetched from db
foreach(var number in numbers){
testList.ForEach(x => {
x.test = random.NextDouble();
});
testAllYearsList.Add(year - number, testList);
}
foreach(KeyValuePair<int, List<TestClass>> entry in testAllYearsList)
{
foreach(var xx in entry.Value){
Console.WriteLine(entry.Key + "-------" + xx.test);
}
}
}
public class TestClass{
public string name{get;set;}
public double test{get;set;}
}
The above code results are like these:
2018-------0.702259658231521
2018-------0.517733022811698
2017-------0.702259658231521
2017-------0.517733022811698
2016-------0.702259658231521
2016-------0.517733022811698
2015-------0.702259658231521
2015-------0.517733022811698
2014-------0.702259658231521
2014-------0.517733022811698
What I'm expecting is something like this:
2018-------0.232323558231521
2018-------0.679072365236698
2017-------0.702259658231545
2017-------0.834268732412351
2016-------0.465468889231561
2016-------0.323423456811698
2015-------0.125332658231528
2015-------0.347588566678699
2014-------0.734758565656521
2014-------0.854544444571690
UPDATE: I tried this but still it's getting me the same issue.
foreach(var number in numbers){
var newTestList = new List<TestClass>();
foreach(var xx in testList){
newTestList.Add(xx);
}
newTestList.ForEach(x => {
x.test = random.NextDouble();
});
testAllYearsList.Add(year - number, newTestList);
}
When you use the same testList with the same TestClass objects you're adding references to the same objects to testAllYearsList, one possible way of fixing this would be to add a new testList with new objects each time:
static void Main(string[] args) {
List<int> numbers = new List<int>() { 0, 1, 2, 3, 4 };
Dictionary<int, List<TestClass>> testAllYearsList = new Dictionary<int, List<TestClass>>();
int year = 2018;
var random = new Random();
foreach (var number in numbers) {
List<TestClass> testList = new List<TestClass> {
new TestClass { test = 0.2 },
new TestClass { test = 1.5 }
};
testList.ForEach(x => {
x.test = random.NextDouble();
});
testAllYearsList.Add(year - number, testList);
}
foreach (KeyValuePair<int, List<TestClass>> entry in testAllYearsList) {
foreach (var xx in entry.Value) {
Console.WriteLine(entry.Key + "-------" + xx.test);
}
}
}
Example output:
2018-------0.961755354405267
2018-------0.285138806926617
2017-------0.249302806914459
2017-------0.68261938015121
2016-------0.998315326403042
2016-------0.692115324871668
2015-------0.822671521838136
2015-------0.0111894570343147
2014-------0.745275680788455
2014-------0.0539408922446616
You only have two instances of TestClass, you've added references to those two instance to each entry in the dictionary. When one instance of TestClass has its property updated all references to that TestClass instance see the same value.
Inside the loop over numbers create new instances of TestClass and see your expected behaviour:
testList = new List<TestClass> {
new TestClass { test = random.NextDouble() },
new TestClass { test = random.NextDouble() }
}
testAllYearsList.Add(year - number, testList);
Finally got it working now. Here's what I changed:
foreach (var number in numbers)
{
var newTestList = new List<TestClass>();
foreach (var xx in testList)
{
newTestList.Add(new TestClass
{
name = xx.name,
test = xx.test
});
}
newTestList.ForEach(x => {
x.test = random.NextDouble();
});
testAllYearsList.Add(year - number, newTestList);
}
So adding xx directly to the newTestList would not resolve the issue. Instead, I need to create new TestClass, map the values from the xx, and then add it into newTestList.
Thanks a lot to those who took their time to help. Without those ideas, I couldn't get this working.

Regex - Capture every line based on condition

To revisit a solution I had here over a year ago:
/* ----------------- jobnameA ----------------- */
insert_job: jobnameA job_type: CMD
date_conditions: 0
alarm_if_fail: 1
/* ----------------- jobnameB ----------------- */
insert_job: jobnameB job_type: CMD
date_conditions: 1
days_of_week: tu,we,th,fr,sa
condition: s(job1) & s(job2) & (v(variable1) = "Y" | s(job1)) & (v(variable2) = "Y"
alarm_if_fail: 1
job_load: 1
priority: 10
/* ----------------- jobnameC ----------------- */
...
I use the following regex to capture each job that has uses a variable v(x) in its condition parameter (only jobnameB here matches):
(?ms)(^[ \t]*/\*[\s-]*([\w-]*)[\s-]*\*/)((?:(?:(?!^[ \t]*/\*[\s-]*[\w-]*[\s-]*\*/).)*?condition\: ([^\n\r]*v\([^\n\r]*)[ \t]*\))+(?:(?!^[ \t]*/\*[\s-]*[\w-]*[\s-]*\*/).)*)
I now need each line caught as parameter and value groups while satisfying the same conditions.
This regex will get each line with parameter and value as separate capture groups, but this wont take into account the presence of variables v(x), so it grabs all jobs:
(?:^([\w_]*\:) ([^\n]+))
And, the following expression will get me as far as the first line (insert_job) of the satisfying jobs, but it ends there instead of grabbing all parameters.
(?:^[ \t]*/\*[\s-]*[\w-]*[\s-]*\*/)(?:(?!^[ \t]*/\*[\s-]*[\w-]*[\s-]*\*/).)*?(?:^([\w_]*\:) ([^\n]+))
Any further help will be appreciated.
I think this would be much easier if you broke it up into steps. I am using LINQ for this:
var jobsWithVx = Regex.Matches(src, #"(?ms)(^[ \t]*/\*[\s-]*([\w-]*)[\s-]*\*/)((?:(?:(?!^[ \t]*/\*[\s-]*[\w-]*[\s-]*\*/).)*?condition\: ([^\n\r]*v\([^\n\r]*)[ \t]*\))+(?:(?!^[ \t]*/\*[\s-]*[\w-]*[\s-]*\*/).)*)").Cast<Match>().Select(m => m.Value);
var jobParameters = jobsWithVx.Select(j => Regex.Matches(j, #"(?ms)^([\w_]+\:) (.+?)$")).Select(m => m.Cast<Match>().Select(am => am.Groups));
Then you can work with the job parameters:
foreach (var aJobsParms in jobParameters) {
foreach (var jobParm in aJobsParms) {
// work with job and parm
}
// alternatively, convert to a Dictionary
var jobDict = aJobsParms.ToDictionary(jpgc => jpgc[1].Value, jpgc => jpgc[2].Value));
// then work with the dictionary
}
Sample that runs in LINQPad:
var src = #"/* ----------------- jobnameA ----------------- */
insert_job: jobnameA job_type: CMD
date_conditions: 0
alarm_if_fail: 1
/* ----------------- jobnameB ----------------- */
insert_job: jobnameB job_type: CMD
date_conditions: 1
days_of_week: tu,we,th,fr,sa
condition: s(job1) & s(job2) & (v(variable1) = ""Y"" | s(job1)) & (v(variable2) = ""Y""
alarm_if_fail: 1
job_load: 1
priority: 10
/* ----------------- jobnameC ----------------- */
";
var jobsWithVx = Regex.Matches(src, #"(?ms)(^[ \t]*/\*[\s-]*([\w-]*)[\s-]*\*/)((?:(?:(?!^[ \t]*/\*[\s-]*[\w-]*[\s-]*\*/).)*?condition\: ([^\n\r]*v\([^\n\r]*)[ \t]*\))+(?:(?!^[ \t]*/\*[\s-]*[\w-]*[\s-]*\*/).)*)").Cast<Match>().Select(m => m.Value);
var jobParameters = jobsWithVx.Select(j => Regex.Matches(j, #"(?ms)^([\w_]+\:) (.+?)$")).Select(m => m.Cast<Match>().Select(am => am.Groups));
jobParameters.Dump();
I've been parsing text files for over 40 years. If I can't do it nobody can. I tried for awhile to use Regex to split your 'name: value' inputs but was unsuccessful. So I finally wrote my own method. Take a look what I did with the days of the week
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.txt";
static void Main(string[] args)
{
Job.Load(FILENAME);
}
}
public class Job
{
public static List<Job> jobs = new List<Job>();
public string name { get;set;}
public string job_type { get;set;}
public int date_conditions { get; set;}
public DayOfWeek[] days_of_week { get; set; }
public string condition { get; set; }
public int alarm_if_fail { get; set; }
public int job_load { get; set; }
public int priority { get; set;}
public static void Load(string filename)
{
Job newJob = null;
StreamReader reader = new StreamReader(filename);
string inputLine = "";
while ((inputLine = reader.ReadLine()) != null)
{
inputLine = inputLine.Trim();
if ((inputLine.Length > 0) && (!inputLine.StartsWith("/*")))
{
List<KeyValuePair<string, string>> groups = GetGroups(inputLine);
foreach (KeyValuePair<string, string> group in groups)
{
switch (group.Key)
{
case "insert_job" :
newJob = new Job();
Job.jobs.Add(newJob);
newJob.name = group.Value;
break;
case "job_type":
newJob.job_type = group.Value;
break;
case "date_conditions":
newJob.date_conditions = int.Parse(group.Value);
break;
case "days_of_week":
List<string> d_of_w = new List<string>() { "su", "mo", "tu", "we", "th", "fr", "sa" };
newJob.days_of_week = group.Value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => (DayOfWeek)d_of_w.IndexOf(x)).ToArray();
break;
case "condition":
newJob.condition = group.Value;
break;
case "alarm_if_fail":
newJob.alarm_if_fail = int.Parse(group.Value);
break;
case "job_load":
newJob.job_load = int.Parse(group.Value);
break;
case "priority":
newJob.priority = int.Parse(group.Value);
break;
}
}
}
}
reader.Close();
}
public static List<KeyValuePair<string, string>> GetGroups(string input)
{
List<KeyValuePair<string, string>> groups = new List<KeyValuePair<string, string>>();
string inputLine = input;
while(inputLine.Length > 0)
{
int lastColon = inputLine.LastIndexOf(":");
string value = inputLine.Substring(lastColon + 1).Trim();
int lastWordStart = inputLine.Substring(0, lastColon - 1).LastIndexOf(" ") + 1;
string name = inputLine.Substring(lastWordStart, lastColon - lastWordStart);
groups.Insert(0, new KeyValuePair<string,string>(name,value));
inputLine = inputLine.Substring(0, lastWordStart).Trim();
}
return groups;
}
}
}

Grouping arrays together and sorting Multiple arrays around a chosen array

I have a set of different arrays that need to be grouped and sorted. However, I am unsure how I would go about grouping together the arrays so that they can be sorted. I am trying to make it so the user can choose which array within a set of grouped arrays will be the base of the sort.
By this I mean if I grouped together all the arrays titled as WS1 along with Month and Year (meaning Year, Month, afArray, rainArray, sunArray, tMaxArray, tMinArray) I would wish that I could target a certain array such as tmaxArray and sort all of the arrays to correspond with that array.
Data in the arrays would look sort of like:
Month | February March April May ...
Year | 1997 1997 1997 1997
afArray | 2 0 4 1
rainArray | 132.00 102.00 112.00 134.00
I'd wish that all of these arrays could be sorted according to that of (for example rainArray) leading to the output of:
Month | March April February May ...
Year | 1997 1997 1997 1997
afArray | 0 4 2 1
rainArray | 102.00 112.00 132.00 134.00
Can anyone give me any advice of how I could go about doing this if it can be done? And is it possible to be able to sort those via an actual algorithm not via Visual Studios built in sorting application?
Just to give some form of extra explanation of how the system is currently built
this is the current code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace Climate_Sorting_Application
{
public class Program
{
public static string cont = "Y";
public static string station;
public static string[] monthArray = File.ReadAllLines("Month.txt");
public static string[] yearArrayPre = File.ReadAllLines("Year.txt");
public static int[] afArray = File.ReadAllLines("WS1_AF.txt").Select(int.Parse).ToArray();
public static string[] rainArray = File.ReadAllLines("WS1_Rain.txt");
public static string[] sunArray = File.ReadAllLines("WS1_Sun.txt");
public static string[] tmaxArray = File.ReadAllLines("WS1_TMax.txt");
public static string[] tminArray = File.ReadAllLines("WS1_TMin.txt");
public static string[] af2Array = File.ReadAllLines("WS2_Rain.txt");
public static string[] rain2Array = File.ReadAllLines("WS2_Rain.txt");
public static string[] sun2Array = File.ReadAllLines("WS2_Sun.txt");
public static string[] tmax2Array = File.ReadAllLines("WS2_TMax.txt");
public static string[] tmin2Array = File.ReadAllLines("WS2_TMin.txt");
public static string arrayToAnalyse;
public static int t;
static void Main(string[] args)
{
while(cont == "Y")
{
Console.WriteLine("Please State which Station you wish to view data for");
Console.WriteLine("Please type either 1 or 2 now then hit enter");
station = Console.ReadLine();
if(station == "1")
{
}
if (station == "2")
{
}
else
{
Console.WriteLine("Not a valid input. Restarting process");
Console.WriteLine("---------------------------------------");
}
}
Console.WriteLine("Thank you for using the Data Sorting System");
Console.WriteLine("Hit Enter to Close Program");
Console.ReadLine();
}
private static void sortProcess()
{
}
}
}
Grouped arrays are an anti-pattern. It's a sign you should create a class with a property for each of the arrays you use currently, and then have one array of the new class type. Do this, and sorting your data becomes a simple .OrderBy() expression.
I wrote some code for you below, but it's all typed directly into the answer window, and even if it weren't I don't have your test data. But this should give you an idea of what you're going for... a little more code to load the data, but notice how little code you need to manipulate it once we have it ready:
namespace Climate_Sorting_Application
{
public class ClimateRecord
{
public DateTime RecordDate {get;set;}
public int StationId {get;set;}
public double RainFall {get;set;}
public double Sun {get;set;}
public double TMax {get;set;}
public double TMin {get;set;}
public double AF {get;set;}
public override string ToString()
{
return String.Format("{0,-15:MMMM yyyy}{1,4}{2,8:F4}{3,8:F4}{4,8:F4}{5,8:F4}{6,8:F4}{7,8:F4}",
RecordDate, StationId, AF, RainFail, Sun, TMax, TMin);
}
}
public class Program
{
static IList<ClimateRecord> LoadData()
{
var result = new List<ClimateRecord>();
using (var monthRdr = new StreamReader("Month.txt"))
using (var yearRdr = new StreamReader("Year.txt"))
using (var afRdr1 = new StreamReader("WS1_AF.txt"))
using (var rainRdr1 = new StreamReader("WS1_Rain.txt"))
using (var sunRdr1 = new StreamReader("WS1_Sun.txt"))
using (var tmaxRdr1 = new StreamReader("WS1_TMax.txt"))
using (var tminRdr1 = new StreamReader("WS1_TMin.txt"))
using (var afRdr2 = new StreamReader("WS2_AF.txt"))
using (var rainRdr2 = new StreamReader("WS2_Rain.txt"))
using (var sunRdr2 = new StreamReader("WS2_Sun.txt"))
using (var tmaxRdr2 = new StreamReader("WS2_TMax.txt"))
using (var tminRdr2 = new StreamReader("WS2_TMin.txt"))
{
string year = yearRdr.ReadLine();
while (year != null)
{
var recordDate = DateTime.ParseExact(year + " " + monthRdr.ReadLine() + " 01", "yyyy MMMM dd", null)
var ws1 = new ClimateRecord() {
RecordDate = recordDate,
StationId = 1,
AF = double.Parse(afRdr1.ReadLine()),
Sun = double.Parse(sunRdr1.ReadLine()),
RainFall = double.Parse(rainRdr1.ReadLine()),
TMax = double.Parse(tmaxRdr1.ReadLine()),
TMin = double.Parse(tminRdr1.ReadLine())
};
var ws2 = new ClimateRecord() {
RecordDate = recordDate,
StationId = 2,
AF = double.Parse(afRdr2.ReadLine()),
Sun = double.Parse(sunRdr2.ReadLine()),
RainFall = double.Parse(rainRdr2.ReadLine()),
TMax = double.Parse(tmaxRdr2.ReadLine()),
TMin = double.Parse(tminRdr2.ReadLine())
};
result.Add(ws1);
result.Add(ws2);
year = yearRdr.ReadLine();
}
}
return result;
}
static void PrintData(IEnumerable<ClimateRecord> data)
{
Console.WriteLine("{0,15}{1,4}{2,8}{3,8}{4,8}{5,8}{6,8}{7,8}",
"Month/Year", "WS", "AF", "Rain", "Sun", "T-Max", "T-Min");
foreach (var record in data) Console.WriteLine(record);
}
static void Main(string[] args)
{
var climateData = LoadData();
Console.WriteLine("Printing all data: ");
PrintData(climateData);
Console.WriteLine("\n\nPrinting Station 1 data:");
PrintData(climateData.Where(r => r.StationId == 1));
Console.WriteLine("\n\nPrinting Station 2 data:");
PrintData(climateData.Where(r => r.StationId == 2));
Console.WriteLine("\n\nPrinting Station 1 data ordered by rainfall descending:");
PrintData(climateData.Where(r => r.StationId == 1).OrderBy(r => r.RainFall * -1));
}
}
}

Towers of Hanoi Visualisation Problems in C#

I've got a Problem with my Console Output I receive always exceptions and can't fix the bug the solution already worked but the stack grows from top to bottom, so I tried to sort my Elements by
Whitespace.Count to reverse that order hope you can help me, here is my code:
public class TvH
{
#region
IDictionary<string, int> towerMapping = new Dictionary<string, int>()
{
{"Start", 0}, {"Mitte", 1}, {"Ziel", 2}
};
private string emptyTower = " | ";
private int turns = 0;
Stack<string>[] towers;
Dictionary<int, string> discs = new Dictionary<int, string>()
{
{1, "-----|-----"},
{2, " ----|---- "},
{3, " ---|--- "},
{4, " --|-- "},
{5, " -|- "}
};
#endregion
public TvH(int towerCount)
{
towers = new Stack<string>[towerCount];
initializeTowers();
}
private void initializeTowers()
{
for (int i = 0; i < towers.Length; i++)
{
towers[i] = new Stack<string>();
}
for (int i = 1; i <= discs.Count; i++)
{
towers[0].Push(discs[i]);
towers[1].Push(emptyTower);
towers[2].Push(emptyTower);
}
}
public void bewegeScheibe(int n, string a, string b, string c)
{
if (n > 0)
{
bewegeScheibe(n - 1, a, c, b);
turns++;
Console.Write("\nZug # ");
if (turns < 10)
{
Console.Write("0");
}
Console.WriteLine("{0} Disc # {1} {2} --> {3}\n", turns, n, a, c);
move(a, c);
bewegeScheibe(n - 1, b, a, c);
}
}
private void move(string start, string target)
{
var element = towers[towerMapping[start]].Pop();
towers[towerMapping[target]].Push(element);
printContent();
}
private void printContent()
{
IList<string> t1 = prepairTowerForPrint(towers[0].GetEnumerator());
IList<string> t2 = prepairTowerForPrint(towers[1].GetEnumerator());
IList<string> t3 = prepairTowerForPrint(towers[2].GetEnumerator());
int i = 0;
while (i < discs.Count)
{
object ob1 = t1[i];
object ob2 = t2[i];
object ob3 = t3[i];
Console.WriteLine("\t{0}\t{1}\t{2}", ob1, ob2, ob3);
i++;
}
}
private IList<string> prepairTowerForPrint(Stack<string>.Enumerator enumerator)
{
IList<string> towerList = new List<string>();
while (enumerator.MoveNext())
{
towerList.Add(TryReadNext(enumerator));
}
towerList = towerList.OrderByDescending(scheiben => scheiben.Count(Char.IsWhiteSpace)).ToList();
return towerList;
}
private string TryReadNext(IEnumerator ce)
{
if (ce.MoveNext())
{
return (string)ce.Current;
}
else
{
return emptyTower;
}
}
}
thank you very much
The problem is that you assume that each stack always has five discs, yet in the method move you pop an element from one and push it on another. Hence the error.
So you'd need to remove one element from towers[towerMapping[target]] and add one to towers[towerMapping[start]].
Can I also do a little code review?
Why is discs a dictionary? It would make for more sense to make it a List() and simply loop through it:
List<string> discs = new List<string>()
{
"-----|-----",
" ----|---- ",
" ---|--- ",
" --|-- ",
" -|- "
};
foreach(var dics in discs)
{
towers[0].Push(disc);
towers[1].Push(emptyTower);
towers[2].Push(emptyTower);
}
Why do you do towers = new Stack<string>[towerCount]; in the TvH constructor instead of in the method called initializeTowers()?
The method prepairTowerForPrint contains a typo, the verb is to prepare.
Method names in German are a bad idea, IMHO. Also, method names should be PascalCase.
The only public method is bewegeScheibe() but it's parameters are actually part of the TvH class: "Start", "Mitte", "Ziel". It's first parameter is int n, which says absolutely nothing; I only figured out what string a, string b, string c were expected to be by reading the code.
Ok I solved another way, here's the code if anybody needs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TuermeVonHanoi
{
public class TvH
{
#region
IDictionary<string, int> towerMapping = new Dictionary<string, int>()
{
{"start", 0}, {"middle", 1}, {"target", 2}
};
private string emptyTower = " | ";
private int turns = 0;
Stack<string>[] towers;
IList<string> discs = new List<string>()
{
{"-----|-----"},
{" ----|---- "},
{" ---|--- "},
{" --|-- "},
{" -|- "}
};
#endregion
public TvH(int towerCount)
{
towers = new Stack<string>[towerCount];
initializeTowers();
}
private void initializeTowers()
{
for (int i = 0; i < towers.Length; i++)
{
towers[i] = new Stack<string>();
}
foreach (var d in discs)
{
towers[0].Push(d);
}
}
public void moveAlgorithmic(int n, string a, string b, string c)
{
if (n > 0)
{
moveAlgorithmic(n - 1, a, c, b);
++turns;
Console.Write("\nturn # ");
if (turns < 10)
{
Console.Write("0");
}
Console.WriteLine("{0} disc # {1} {2} --> {3}\n", turns, n, a, c);
moveVisual(a, c);
moveAlgorithmic(n - 1, b, a, c);
}
}
private void moveVisual(string start, string target)
{
var element = towers[towerMapping[start]].Pop();
towers[towerMapping[target]].Push(element);
printContent();
}
private void printContent()
{
IList<string> t1 = prepareTowerForPrint(towers[0].GetEnumerator());
IList<string> t2 = prepareTowerForPrint(towers[1].GetEnumerator());
IList<string> t3 = prepareTowerForPrint(towers[2].GetEnumerator());
int i = 0;
while (i < discs.Count)
{
object ob1 = t1[i];
object ob2 = t2[i];
object ob3 = t3[i];
Console.WriteLine("\t{0}\t{1}\t{2}", ob1, ob2, ob3);
++i;
}
}
private IList<string> prepareTowerForPrint(Stack<string>.Enumerator enumerator)
{
IList<string> towerList = new List<string>();
int count = 0;
while (enumerator.MoveNext())
{
++count;
towerList.Add(enumerator.Current);
}
int toPush = discs.Count - count;
for (int i = 0; i < toPush; i++ )
{
towerList.Add(emptyTower);
}
if (toPush != 0 || toPush != 1)
{
towerList = towerList.OrderByDescending(d => d.Count(Char.IsWhiteSpace)).ToList();
}
return towerList;
}
}
}
instead of initializing all 3 stacks we calculate how many empty pin elements have to be printed out for every stack

Categories