Related
I have an Excel template that has a table (range: A4:AM5) which I need to expand by inserting rows via EPPlus. My code inserts the cell values in the file with no problem, but I need to extend the rows of the table according to each new value inserted in the first column.
I tried to use the InsertRow(5,1) method but it shows an exception
"System.ArgumentOutOfRangeException: 'Row cannot be less than 1.
Parameter name: value'"
And the value presents:
{System.ArgumentOutOfRangeException: Row cannot be less than 1. Parameter name: value > at OfficeOpenXml.ExcelCellAddress.set_Row(Int32 value) > at OfficeOpenXml.ExcelNamedRangeCollection.InsertRows(Int32 rowFrom, Int32 rows, ExcelNamedRange namedRange) > at OfficeOpenXml.ExcelNamedRangeCollection.Insert(Int32 rowFrom, Int32 colFrom, Int32 rows, Int32 cols, Func`2 filter) > at OfficeOpenXml.ExcelWorksheet.InsertRow(Int32 rowFrom, Int32 rows, Int32 copyStylesFromRow) > at TestInsertRow.Program.Main(String[] args)}
I minimized the functions of the code into this one which also shows the same exception:
class Dnp3
{
private static ExcelPackage _dnp3Package;
private static ExcelWorksheet _worksheet1;
private static FileInfo _templateInfo;
private static FileInfo _newDnp3FileInfo;
public static bool TempFile
{
get
{
if (_templateInfo != null) return true;
return false;
}
set
{
if (value == true)
{
_templateInfo = new FileInfo(#" Existing template path ");
}
}
}
public static bool NewFile
{
get
{
if (_newDnp3FileInfo != null) return true;
return false;
}
set
{
if (value == true)
{
_newDnp3FileInfo = new FileInfo(#" Existing new file path ");
_dnp3Package = new ExcelPackage(_newDnp3FileInfo, _templateInfo);
{
_worksheet1 = Dnp3._dnp3Package.Workbook.Worksheets["DNP3_RTUs"];
{
_worksheet1.DataValidations.Clear();
}
}
}
}
}
public static bool Save
{
set
{
if (value == true)
{
Dnp3._dnp3Package.Save();
}
}
}
public class DNP3_RTUs : Dnp3
{
private int _idobj_nameCol;//IDOBJ_NAME
private int _idobj_aliasCol;//IDOBJ_ALIAS
private int _idobj_customidCol;//IDOBJ_CUSTOMID
private int _idobj_aorgroupCol;//IDOBJ_AORGROUP
public bool Header
{
set
{
int _column = 1;
_idobj_nameCol = 1;
_idobj_aliasCol = 1;
_idobj_customidCol = 1;
_idobj_aorgroupCol = 1;
if (value == true)
{
while (_worksheet1.Cells[Row: 3, Col: _column].Value != null)
{
switch (_worksheet1.Cells[Row: 3, Col: _column].Value)
{
case "IDOBJ_NAME":
_idobj_nameCol = _column;
break;
case "IDOBJ_ALIAS":
_idobj_aliasCol = _column;
break;
case "IDOBJ_CUSTOMID":
_idobj_customidCol = _column;
break;
case "IDOBJ_AORGROUP":
_idobj_aorgroupCol = _column;
break;
}
_column++;
}
}
}
}
public bool AddRow(int _line)
{
_line = _line + 5;
_worksheet1.InsertRow(_line, 2);
return false;
}
public string IDOBJ_NAME(int _line, string _data)
{
_line = _line + 5;//Pq a entrada de dados começa na linha
_worksheet1.Cells[_line, _idobj_nameCol].Value = _data;
_worksheet1.Cells[_line, _idobj_nameCol].Style.Font.Size = 11;
_worksheet1.Cells[_line, _idobj_nameCol].Style.Font.Name = "Calibri";
return "";
}
public string IDOBJ_ALIAS(int _line, string _data)
{
_line = _line + 5;//Pq a entrada de dados começa na linha 5
_worksheet1.Cells[_line, _idobj_aliasCol].Value = _data;
_worksheet1.Cells[_line, _idobj_aliasCol].Style.Font.Size = 11;
_worksheet1.Cells[_line, _idobj_aliasCol].Style.Font.Name = "Calibri";
return "";
}
public string IDOBJ_CUSTOMID(int _line, string _data)
{
_line = _line + 5;//Pq a entrada de dados começa na linha 5
_worksheet1.Cells[_line, _idobj_customidCol].Value = _data;
_worksheet1.Cells[_line, _idobj_customidCol].Style.Font.Size = 11;
_worksheet1.Cells[_line, _idobj_customidCol].Style.Font.Name = "Calibri";
return "";
}
public string IDOBJ_AORGROUP(int _line, string _data)
{
_line = _line + 5;//Pq a entrada de dados começa na linha 5
_worksheet1.Cells[_line, _idobj_aorgroupCol].Value = _data;
_worksheet1.Cells[_line, _idobj_aorgroupCol].Style.Font.Size = 11;
_worksheet1.Cells[_line, _idobj_aorgroupCol].Style.Font.Name = "Calibri";
return "";
}
}
}
class Program
{
static void Main(string[] args)
{
Dnp3.TempFile = true;
Dnp3.NewFile = true;
Dnp3.DNP3_RTUs dNP3_RTUs = new Dnp3.DNP3_RTUs() { Header = true };
int _mappingCount = 1;
dNP3_RTUs.IDOBJ_NAME(_mappingCount, "BOQ_1");
dNP3_RTUs.IDOBJ_ALIAS(_mappingCount,"nome_se_ordem");
dNP3_RTUs.IDOBJ_AORGROUP(_mappingCount, "mnem_se");
dNP3_RTUs.AddRow(_mappingCount);
Dnp3.Save = true;
}
}
I faced the same exception and was able to resolve it by fixing the excel template names collection.
Press Ctrl+F3 (Name Manager) and search for names containing any #REF! values and referrers and delete them from the template.
If Ctrl + F3 doesn't work for finding Name Manager
Hover over "sheet.Names" you will find all Name Managers And
you can remove them throw code
var refName = sheet.Names.FirstOrDefault(x => x.Name == "nameOfNameManager");
if (refName != null)
{
sheet.Names.Remove("nameOfNameManager");
}
My C# classes will create a GUI that takes in csv files and plot a line graph accordingly. Currently, my graphs are plotted and saved using the GUI file dialog.
What I am trying to do now is to read, plot and save the graph using command-line instead (NO GUI needed).
May I know how could I call my Read and Plot classes using the "-f" flag (file path, can have multiple csv file) and save the plotted graph using the "-o" flag (output file path, only 1 file produced)?
Thanks.
You can use this:
class Program:
static class Program
{
[System.Runtime.InteropServices.DllImport("kernel32.dll")] // ### Edit 3 ###
static extern bool AttachConsole(int dwProcessId); // ### Edit 3 ###
/// <summary>The main entry point for the application.</summary>
[STAThread]
static void Main(string[] args)
{
// redirect console output to parent process;
// must be before any calls to Console.WriteLine()
AttachConsole(-1);// ### Edit 3 ###
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//program.exe -f c:\\desktop\\1.csv -o c:\\desktop\\1.png
var inputFile = new List<string>();
string outputFile = null;
if (args.Length > 0)
{
for (int i = 0; i < args.Length; i++)
{
string a = args[i].ToLower();
switch (a)
{
case "-f":
for (i = i + 1; i < args.Length ; i++)
{
string f = args[i]; if (f.StartsWith("-")) { i--; break; }
inputFile.Add(f); //get next arg as inputFile
}
break;
case "-o":
outputFile = args[++i]; //get next arg as outputFile
break;
}
}
if (inputFile.Count > 0 && outputFile != null)
{
var form = new Form2(); //specify your form class
form.showErrorsInConsole = true; // ### Edit 3 ###
//form.Visible = true;
form.DoReadFiles(inputFile.ToArray());
form.DoPlot();
form.SavePic(outputFile);
form.Dispose();
return;
}
}
//else
Application.Run(new Form2()); //show GUI
//MessageBox.Show("Args:\r\n" + s);
}
}
Form class (the form conatining your chart, in my code it is Form2):
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
}
List<Read> rList = new List<Read>();
public bool showErrorsInConsole = false; //### Edit 3 ###
public void DoReadFiles(string[] fileNames)
{
try
{
rList.Clear();
foreach (String file in fileNames) //if ((myStream = ff.OpenFile()) != null)
{
Read r = new Read(file);
rList.Add(r);
}
}
catch (Exception err)
{
//Inform the user if we can't read the file
if (showErrorsInConsole) //### Edit 3 ###
Console.WriteLine("\r\n *** Error: " + err.Message); //### Edit 3 ###
else
MessageBox.Show(err.Message);
}
}
public void DoPlot(int indX = 0, int indY = 1)
{
Plot.Draw(chart, rList, indX, indY);
}
public void SavePic(string outputFile)
{
bool isPng = outputFile.EndsWith(".png", StringComparison.OrdinalIgnoreCase);
chart.SaveImage(outputFile, isPng ? ChartImageFormat.Png : ChartImageFormat.Jpeg);
}
void openToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFileDialog ff = new OpenFileDialog();
ff.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); //"C:\\";
ff.Filter = "csv files (*.csv)|*.csv|All files (*.*)|*.*";
ff.Multiselect = true;
ff.FilterIndex = 1;
ff.RestoreDirectory = true;
if (ff.ShowDialog() == DialogResult.OK)
{
try
{
DoReadFiles(ff.FileNames);
//Populate the ComboBoxes
if (rList.Count > 0)
{
string[] header = rList[0].header; //header of first file
xBox.DataSource = header;
yBox.DataSource = header.Clone(); //without Clone the 2 comboboxes link together!
}
if (yBox.Items.Count > 1) yBox.SelectedIndex = 1; //select second item
}
catch (Exception err)
{
//Inform the user if we can't read the file
MessageBox.Show(err.Message);
}
}
}
private void button1_Click(object sender, EventArgs e)
{
DoPlot(xBox.SelectedIndex, yBox.SelectedIndex);
}
} //end class Form2
class Read:
public class Read
{
public int nLines { get; private set; }
public int nColumns { get; private set; }
public string[] header { get; private set; }
public float[,] data { get; private set; }
public string fileName { get; set; }
public string[] section { get; private set; }
public Read(string file)
{
string[] pieces;
fileName = Path.GetFileName(file);
string[] lines = File.ReadAllLines(file); // read all lines
if (lines == null || lines.Length < 2) return; //no data in file
header = lines[0].Split(','); //first line is header
nLines = lines.Length - 1; //first line is header
nColumns = header.Length;
//read the numerical data and section name from the file
data = new float[nLines, nColumns - 1]; // 1 less than nColumns as last col is sectionName
section = new string[nLines];
for (int i = 0; i < nLines; i++)
{
pieces = lines[i + 1].Split(','); // i(+1) is because first line is header
if (pieces.Length != nColumns) { MessageBox.Show("Invalid data at line " + (i + 2) + " of file " + fileName); return; }
for (int j = 0; j < nColumns - 1; j++)
{
float.TryParse(pieces[j], out data[i, j]); //data[i, j] = float.Parse(pieces[j]);
}
section[i] = pieces[nColumns - 1]; //last item
}
}
}
class Plot:
public class Plot
{
public static void Draw(Chart chart, List<Read> rList, int indX = 0, int indY = 1)
{
chart.Series.Clear(); //ensure that the chart is empty
chart.Legends.Clear();
Legend myLegend = chart.Legends.Add("myLegend");
myLegend.Title = "myTitle";
Color[] colors = new Color[] { Color.Black, Color.Blue, Color.Red, Color.Green, Color.Magenta, Color.DarkCyan, Color.Chocolate, Color.DarkMagenta };
var sectionColors = new Dictionary<string, int>();
bool separateSections = (rList.Count == 1); // #Edit: 4
int i = 0;
int iColor = -1, maxColor = -1;
foreach (Read rr in rList)
{
float[,] data = rr.data;
int nLines = rr.nLines;
int nColumns = rr.nColumns;
string[] header = rr.header;
chart.Series.Add("Series" + i);
chart.Series[i].ChartType = SeriesChartType.Line;
chart.Series[i].LegendText = rr.fileName; // #Edit: 4
if (separateSections) chart.Series[i].IsVisibleInLegend = false; // #Edit: 4
chart.ChartAreas[0].AxisX.LabelStyle.Format = "{F2}";
chart.ChartAreas[0].AxisX.Title = header[indX];
chart.ChartAreas[0].AxisY.Title = header[indY];
for (int j = 0; j < nLines; j++)
{
int k = chart.Series[i].Points.AddXY(data[j, indX], data[j, indY]);
if (separateSections) // #Edit: 4
{
string curSection = rr.section[j];
if (sectionColors.ContainsKey(curSection))
{
iColor = sectionColors[curSection];
}
else
{
maxColor++;
iColor = maxColor; sectionColors[curSection] = iColor;
}
chart.Series[i].Points[k].Color = colors[iColor];
}
}
i++; //series#
} //end foreach rr
//fill legend based on series
foreach (var x in sectionColors)
{
string section = x.Key;
iColor = x.Value;
myLegend.CustomItems.Add(colors[iColor], section); //new LegendItem()
}
}
}
If you are looking for something simple then you can just have a loop and get the values like this:
string f=null;
string o=null;
for (var i = 0; i < args.Length; i++)
{
if (args[i] == "-f") { f = args[i + 1]; }
else if (args[i] == "-o") { o = args[i + 1]; }
}
if (f != null)
{
}
if (o != null)
{
}
You can use command parser libraries. Command Line Parser ( http://commandline.codeplex.com/ ) is very easy to use.
[Option("f", "input", Required = true]
public string InputFile { get; set; }
[Option("o", "output", Required = true]
public string OutputFile { get; set; }
I am trying to create a program which can sort the number of results associated with any specified google search. I need a big table very fast so I thought about using a loop. Each time I try it though, the debugger crashes due to a "System.Windows.Markup.XamlParseException".
public long resultStat(string a)
{
var req = (HttpWebRequest)WebRequest.Create("https://www.google.ca/search?hl=fr&output=search&sclient=psy-ab&q=a" + a + "&btnK=");
using (req as IDisposable)
{
WebResponse rep = req.GetResponse();
Stream str = rep.GetResponseStream();
StreamReader rdr = new StreamReader(str);
string res = rdr.ReadToEnd();
rdr.Close();
//This is my code to get the number results (it works perfectly)
int index = res.IndexOf(">Environ");
int cond = 0;
string final = "";
try
{
while (res[++index] != '<')
{
if (cond-- == 0 && res[index] != '&')
{ final += res[index]; cond = 0; }
else if (res[index] == '&') cond = 5;
}
}
catch { return 0; }
string temp = "";
foreach (char i in final) if (i < 48 && i > 58) temp += i;
return Int64.Parse(temp);
}
}
This whole method is simply used in the main in a for loop such as :
public void main()
{
//Other code
for (int i = 0; i < 3; i++) resultStat(i.ToString()); // For example
//Other code
}
I know it's the problem because as soon as I comment the loop, or lower it to one rep, nothing goes wrong. I've tried:
HttpWebRequest().Abort();
HttpWebRequest().KeepAlive = false;
It didn't work
I don't think the away you are doing is the correct way to do this. The simple one i can tell you is use Lib curl c#. You can send in an array of urls and get response as an array. That would be perfect for what you require here. Here is a sample class code below that does the multitasking itself. You just send in the urls.
public class MultiHttp
{
public static string UserAgent = "Mozilla 5.0";
public static string Header = "Content-Type: application/x-www-form-urlencoded; charset=UTF-8";
private static string[] Result;
public static string[] MultiPost(string[] Url, string post, int timeOut)
{
Result = new string[post.Length];
try
{
Curl.GlobalInit((int)CURLinitFlag.CURL_GLOBAL_ALL);
Easy.WriteFunction wf = new Easy.WriteFunction(OnWriteData);
//Easy.HeaderFunction hf = new Easy.HeaderFunction(OnHeaderData);
Easy[] easy = new Easy[Url.Length];
Multi multi = new Multi();
for (int i = 0; i < Url.Length; i++)
{
if (Url[i] != null)
{
easy[i] = new Easy();
easy[i].SetOpt(CURLoption.CURLOPT_URL, Url[i]);
easy[i].SetOpt(CURLoption.CURLOPT_WRITEFUNCTION, wf);
easy[i].SetOpt(CURLoption.CURLOPT_WRITEDATA, i);
//easy[i].SetOpt(CURLoption.CURLOPT_HEADERFUNCTION, hf);
//easy[i].SetOpt(CURLoption.CURLOPT_HEADERDATA, i);
easy[i].SetOpt(CURLoption.CURLOPT_TIMEOUT, timeOut);
easy[i].SetOpt(CURLoption.CURLOPT_USERAGENT, UserAgent);
Slist sl = new Slist();
sl.Append(Header);
easy[i].SetOpt(CURLoption.CURLOPT_HTTPHEADER, sl);
easy[i].SetOpt(CURLoption.CURLOPT_POSTFIELDS, post);
easy[i].SetOpt(CURLoption.CURLOPT_FOLLOWLOCATION, true);
easy[i].SetOpt(CURLoption.CURLOPT_POST, true);
//easy[i].SetOpt(CURLoption.CURLOPT_NOBODY, true);
if (Url[i].Contains("https"))
{
easy[i].SetOpt(CURLoption.CURLOPT_SSL_VERIFYHOST, 1);
easy[i].SetOpt(CURLoption.CURLOPT_SSL_VERIFYPEER, 0);
}
multi.AddHandle(easy[i]);
}
}
int stillRunning = 1;
while (multi.Perform(ref stillRunning) == CURLMcode.CURLM_CALL_MULTI_PERFORM) ;
while (stillRunning != 0)
{
multi.FDSet();
int rc = multi.Select(1000); // one second
switch (rc)
{
case -1:
stillRunning = 0;
break;
case 0:
default:
{
while (multi.Perform(ref stillRunning) == CURLMcode.CURLM_CALL_MULTI_PERFORM) ;
break;
}
}
}
// various cleanups
multi.Cleanup();
for (int i = 0; i < easy.Length; i++)
{
easy[i].Cleanup();
}
Curl.GlobalCleanup();
}
catch (Exception)
{
//r = ex+"";
}
return Result;
}
public static Int32 OnWriteData(Byte[] buf, Int32 size, Int32 nmemb,
Object extraData)
{
int tmp = Convert.ToInt32(extraData.ToString()); ;
Result[tmp] += System.Text.Encoding.UTF8.GetString(buf);
return size * nmemb;
}
}
Call it like :
String[] url= new String[2];
url[1]="https://www.google.ca/search?hl=fr&output=search&sclient=psy-ab&q=a1&btnK=";
url[2]="https://www.google.ca/search?hl=fr&output=search&sclient=psy-ab&q=a2&btnK=";
string postString=""; // IF YOU DO NOT WANT TO POST ANYTHING YOU CAN DO THE SAME THING KEEP URL THE SAME SEND POST ARRAY AND CHANGE THE CLASS IT WORKS BOTH WAYS
String[] result = MultiHttp.MultiPost(url, postString, timeOut);
Its just a sample but will get you the working idea to sort out your problem.
I´m having trouble picking a random word from a list in another file.
Actually I can´t even get it to choose any word. I´m not sure how to connect the 2 files so to say.
Hoping someone can help out, I´m a beginner so please explain as easy as possible:)
I have 2 files, one is called program.cs and the other is called WordList.cs
I´m gonna paste all my code but first the little snip that I´m having problem with. I just can´t figure out how to write the code correct.
Here is the little part which is called Pick word:
//PICK WORD
static string pickWord()
{
string returnword = "";
TextReader file = new StreamReader(words);
string fileLine = file.ReadLine();
Random randomGen = new Random();
returnword = words[randomGen.Next(0, words.Count - 1)];
return returnword;
}
And here is all the code in Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
class Hangman
{
static void Main(string[] args)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Title = "C# Hangman";
Console.WriteLine("Welcome To C# Hangman!");
//MENU
int MenuChoice = 0;
while (MenuChoice != 4)
{
Console.Write("\n\t1) Add words");
Console.Write("\n\t2) Show list of words");
Console.Write("\n\t3) Play");
Console.Write("\n\t4) Quit\n\n");
Console.Write("\n\tChoose 1-4: "); //Choose meny item
MenuChoice = Convert.ToInt32(Console.ReadLine());
WordList showing = new WordList();
switch (MenuChoice)
{
case 1:
Console.Write("\n\tAdd a word\n\n");
var insert = Console.ReadLine();
showing.AddWord(insert);
Console.Write("\n\tList of words\n\n");
showing.ListOfWords();
break;
case 2:
Console.Write("\n\tList of words\n\n");
showing.ListOfWords();
break;
case 3: //Running game
int numGuessesInt = -1;
while (numGuessesInt == -1)
{
/* Sets the number of guesses the user has to guess the word*/
pickNumGuesses(ref numGuessesInt);
}
/* Randomly picks a word*/
string word = pickWord();
/* Creates a list of characters that will show */
List<char> guessedLetters = new List<char>();
bool solved = false;
while (solved == false)
{
/* Displaying a string to the user based on the user's correct guesses.
* If nothing is correct string will return "_ _ _ " */
string wordToDisplay = displayWord(guessedLetters, word);
/* If the string returned contains the "_" character, all the
* correct letters have not been guessed, so checking if user
* has lost, by checking if numGuessesLeft is less than 1.*/
if (!wordToDisplay.Contains("_"))
{
solved = true;
Console.WriteLine("You Win! The word was " + word);
/* Check if the user wants to play again. If they do,
* then solved is set to true, will end the loop,
* otherwise, checkIfPlayAgain will close the program.*/
checkIfPlayAgain();
}
else if (numGuessesInt <= 0)
{
solved = true;
Console.WriteLine("You Lose! The word was " + word);
checkIfPlayAgain();
}
else
{
/* If the user has not won or lost, call guessLetter,
* display the word, minus guesses by 1*/
guessLetter(guessedLetters, word, wordToDisplay, ref numGuessesInt);
}
}
break;
case 4:
Console.WriteLine("\n\tEnd game?\n\n");
break;
default:
Console.WriteLine("Sorry, invalid selection");
break;
}
}
}
// ****** PICK NUMBER OF GUESSES ******
static void pickNumGuesses(ref int numGuessesInt)
{
string numGuessesString = "";
Console.WriteLine("Pick a number of guesses");
numGuessesString = Console.ReadLine();
try
{
numGuessesInt = Convert.ToInt32(numGuessesString);
if (!(numGuessesInt <= 20 & numGuessesInt >= 1))
{
throw new Exception();
}
}
catch (Exception)
{
numGuessesInt = -1;
Console.WriteLine("Error: Invalid Number of Guesses");
}
}
//PICK WORD
static string pickWord()
{
string returnword = "";
TextReader file = new StreamReader(words);
string fileLine = file.ReadLine();
Random randomGen = new Random();
returnword = words[randomGen.Next(0, words.Count - 1)];
return returnword;
}
// ****** Display word ******
static string displayWord(List<char> guessedCharacters, string word)
{
string returnedWord = "";
if (guessedCharacters.Count == 0)
{
foreach (char letter in word)
{
returnedWord += "_ ";
}
return returnedWord;
}
foreach (char letter in word)
{
bool letterMatch = false;
foreach (char character in guessedCharacters)
{
if (character == letter)
{
returnedWord += character + " ";
letterMatch = true;
break;
}
else
{
letterMatch = false;
}
}
if (letterMatch == false)
{
returnedWord += "_ ";
}
}
return returnedWord;
}
// ****** Guess letter ******
static void guessLetter(List<char> guessedCharacters, string word, string wordToDisplay, ref int numGuessesLeft)
{
string letters = "";
foreach (char letter in guessedCharacters)
{
letters += " " + letter;
}
Console.WriteLine("Guess a letter");
Console.WriteLine("Guessed Letters: " + letters);
Console.WriteLine("Guesses Left: " + numGuessesLeft);
Console.WriteLine(wordToDisplay);
string guess = Console.ReadLine();
char guessedLetter = 'a';
try
{
guessedLetter = Convert.ToChar(guess);
if (!Char.IsLetter(guessedLetter))
{
throw new Exception();
}
}
catch (Exception)
{
Console.WriteLine("Error: Invalid Letter Choice");
//guessLetter(guessedCharacters, word, wordToDisplay, ref numGuessesLeft);
}
bool repeat = false;
for (int i = 0; i < guessedCharacters.Count; i++)
{
if (guessedCharacters[i] == guessedLetter)
{
Console.WriteLine("Error: Invalid Letter Choice");
repeat = true;
//guessLetter(guessedCharacters, word, wordToDisplay, ref numGuessesLeft);
}
}
if (repeat == false)
{
guessedCharacters.Add(guessedLetter);
numGuessesLeft -= 1;
}
}
// ****** Check to see if player wants to play again. ******
static void checkIfPlayAgain()
{
Console.WriteLine("Would you like to play again? (y/n)");
string playAgain = Console.ReadLine();
if (playAgain == "n")
{
Environment.Exit(1);
}
}
}
And here is the code for WordList.cs
using System;
using System.Collections.Generic;
class WordList
{
List <string> words = new List<string>();
public void ListOfWords()
{
words.Add("test"); // Contains: test
words.Add("dog"); // Contains: test, dog
words.Insert(1, "shit"); // Contains: test, shit, dog
words.Sort();
foreach (string word in words) // Display for verification
{
Console.WriteLine(word);
}
}
public void AddWord(string value){
words.Add(value);
}
}
I have made some changes to your code. The code works now but is far from perfect.
Your solution has two files Program.cs and Wordlist.cs, which looks like this
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
public class Hangman
{
/*
* Some notes on your code:
* use naming convention for methods and fields, i.e. methods names start with a capital letter
* use modifiers for methods, i.e private, public, protected in your method declarations
* make variables private if you use them on several methods
* and finally: read a book on c#
*
*/
private static WordList words;
private static Random randomGen = new Random();
public static void Main(string[] args)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Title = "C# Hangman";
Console.WriteLine("Welcome To C# Hangman!");
initializeWordList();
//MENU
int MenuChoice = 0;
while (MenuChoice != 4)
{
Console.Write("\n\t1) Add words");
Console.Write("\n\t2) Show list of words");
Console.Write("\n\t3) Play");
Console.Write("\n\t4) Quit\n\n");
Console.Write("\n\tChoose 1-4: "); //Choose meny item
MenuChoice = Convert.ToInt32(Console.ReadLine());
switch (MenuChoice)
{
case 1:
Console.Write("\n\tAdd a word\n\n");
var insert = Console.ReadLine();
words.Add(insert);
Console.Write("\n\tList of words\n\n");
foreach (string w in words) // Display for verification
Console.WriteLine(w);
break;
case 2:
Console.Write("\n\tList of words\n\n");
foreach (string w in words) // Display for verification
Console.WriteLine(w);
break;
case 3: //Running game
int numGuessesInt = -1;
while (numGuessesInt == -1)
{
/* Sets the number of guesses the user has to guess the word*/
pickNumGuesses(ref numGuessesInt);
}
/* Randomly picks a word*/
string word = PickWord();
/* Creates a list of characters that will show */
List<char> guessedLetters = new List<char>();
bool solved = false;
while (solved == false)
{
/* Displaying a string to the user based on the user's correct guesses.
* If nothing is correct string will return "_ _ _ " */
string wordToDisplay = displayWord(guessedLetters, word);
/* If the string returned contains the "_" character, all the
* correct letters have not been guessed, so checking if user
* has lost, by checking if numGuessesLeft is less than 1.*/
if (!wordToDisplay.Contains("_"))
{
solved = true;
Console.WriteLine("You Win! The word was " + word);
/* Check if the user wants to play again. If they do,
* then solved is set to true, will end the loop,
* otherwise, checkIfPlayAgain will close the program.*/
checkIfPlayAgain();
}
else if (numGuessesInt <= 0)
{
solved = true;
Console.WriteLine("You Lose! The word was " + word);
checkIfPlayAgain();
}
else
{
/* If the user has not won or lost, call guessLetter,
* display the word, minus guesses by 1*/
guessLetter(guessedLetters, word, wordToDisplay, ref numGuessesInt);
}
}
break;
case 4:
Console.WriteLine("\n\tEnd game?\n\n");
break;
default:
Console.WriteLine("Sorry, invalid selection");
break;
}
}
}
private static void initializeWordList()
{
words = new WordList();
words.Add("test"); // Contains: test
words.Add("dog"); // Contains: test, dog
words.Insert(1, "shit"); // Contains: test, shit, dog
words.Sort();
}
// ****** PICK NUMBER OF GUESSES ******
private static void pickNumGuesses(ref int numGuessesInt)
{
string numGuessesString = "";
Console.WriteLine("Pick a number of guesses");
numGuessesString = Console.ReadLine();
try
{
numGuessesInt = Convert.ToInt32(numGuessesString);
if (!(numGuessesInt <= 20 & numGuessesInt >= 1))
{
throw new Exception();
}
}
catch (Exception)
{
numGuessesInt = -1;
Console.WriteLine("Error: Invalid Number of Guesses");
}
}
//PICK WORD
private static string PickWord()
{
return words[randomGen.Next(0, words.Count() - 1)];
}
// ****** Display word ******
private static string displayWord(List<char> guessedCharacters, string word)
{
string returnedWord = "";
if (guessedCharacters.Count == 0)
{
foreach (char letter in word)
{
returnedWord += "_ ";
}
return returnedWord;
}
foreach (char letter in word)
{
bool letterMatch = false;
foreach (char character in guessedCharacters)
{
if (character == letter)
{
returnedWord += character + " ";
letterMatch = true;
break;
}
else
{
letterMatch = false;
}
}
if (letterMatch == false)
{
returnedWord += "_ ";
}
}
return returnedWord;
}
// ****** Guess letter ******
static void guessLetter(List<char> guessedCharacters, string word, string wordToDisplay, ref int numGuessesLeft)
{
string letters = "";
foreach (char letter in guessedCharacters)
{
letters += " " + letter;
}
Console.WriteLine("Guess a letter");
Console.WriteLine("Guessed Letters: " + letters);
Console.WriteLine("Guesses Left: " + numGuessesLeft);
Console.WriteLine(wordToDisplay);
string guess = Console.ReadLine();
char guessedLetter = 'a';
try
{
guessedLetter = Convert.ToChar(guess);
if (!Char.IsLetter(guessedLetter))
{
throw new Exception();
}
}
catch (Exception)
{
Console.WriteLine("Error: Invalid Letter Choice");
//guessLetter(guessedCharacters, word, wordToDisplay, ref numGuessesLeft);
}
bool repeat = false;
for (int i = 0; i < guessedCharacters.Count; i++)
{
if (guessedCharacters[i] == guessedLetter)
{
Console.WriteLine("Error: Invalid Letter Choice");
repeat = true;
//guessLetter(guessedCharacters, word, wordToDisplay, ref numGuessesLeft);
}
}
if (repeat == false)
{
guessedCharacters.Add(guessedLetter);
numGuessesLeft -= 1;
}
}
// ****** Check to see if player wants to play again. ******
static void checkIfPlayAgain()
{
Console.WriteLine("Would you like to play again? (y/n)");
string playAgain = Console.ReadLine();
if (playAgain == "n")
{
Environment.Exit(1);
}
}
}
Wordlist.cs
using System;
using System.Collections.Generic;
public class WordList : List<string>
{
}
Here is the very simple solution:
Populate your list just one time, or when ever you add any word, call this method. Code:
private void PopulateTheWordList()
{
Console.Write("\n\tAdd a word\n\n");
WordList.Add(Console.ReadLine());
}
Now just call this method to get random words:
private string PickWord()
{
Random ran = new Random();
return WordList[ran.Next(0, WordList.Count)];
}
If you need to create List of words in another class, then use keyword static:
static List<string> WordList = new List<string>();
Now you can call it by just writing the class name, like YourClassName.WordList
Try creating a Static Class and add a method for returning your List, you will then be able to access your wordlist.
example:
static class WordList
{
static List<string> words = new List<string>();
public static void ListOfWords()
{
words.Add("test"); // Contains: test
words.Add("dog"); // Contains: test, dog
words.Insert(1, "shit"); // Contains: test, shit, dog
words.Sort();
foreach (string word in words) // Display for verification
{
Console.WriteLine(word);
}
}
public static List<string> GetWords()
{
return words;
}
public static void AddWord(string value)
{
words.Add(value);
}
}
You would then change your switch statement to look something like this.
switch (MenuChoice)
{
case 1:
Console.Write("\n\tAdd a word\n\n");
var insert = Console.ReadLine();
WordList.AddWord(insert);
Console.Write("\n\tList of words\n\n");
WordList.ListOfWords();
break;
case 2:
Console.Write("\n\tList of words\n\n");
WordList.ListOfWords();
break;
....
and your pickWord Method would look like this:
static string pickWord()
{
string returnword = "";
Random randomGen = new Random();
returnword = WordList.GetWords()[randomGen.Next(0, WordList.GetWords().Count() - 1)];
return returnword;
}
I modified your Wordlist class so that it can use a file to maintain your Words between uses of your program, just incase that is what was being asked of you.
static class WordList
{
static string filePath = #"C:\temp\Word.txt";
static List<string> words = new List<string>();
private static void CheckFile()
{
//Makes sure our base words are saved to the file
if (!File.Exists(#"C:\temp\Word.txt"))
{
using (TextWriter writer = new StreamWriter(filePath))
{
writer.WriteLine("test");
writer.WriteLine("dog");
writer.WriteLine("shit");
}
}
}
public static void ListOfWords()
{
CheckFile();
words.Clear();
using (TextReader file = new StreamReader(filePath))
{
char[] delineators = new char[] { '\r', '\n' };
string[] tempWords = file.ReadToEnd().Split(delineators, StringSplitOptions.RemoveEmptyEntries);
foreach (string line in tempWords)
{
words.Add(line);
}
}
foreach (string word in words) // Display for verification
{
Console.WriteLine(word);
}
}
public static List<string> GetWords()
{
return words;
}
public static void AddWord(string value)
{
CheckFile();
using (TextWriter writer = new StreamWriter(filePath,true ))
{
writer.WriteLine(value);
}
}
}
What C# template engine
that uses 'pure' HTML having only text and markers
sans any control flow like if, while, loop or expressions,
separating html from control code ?
Below is the example phone book list code,
expressing how this should be done:
string html=#"
<html><head><title>#title</title></head>
<body>
<table>
<tr>
<td> id</td> <td> name</td> <td> sex</td> <td>phones</td>
</tr><!--#contacts:-->
<tr>
<td>#id</td> <td>#name</td> <td>#sex</td>
<td>
<!--#phones:-->#phone <br/>
<!--:#phones-->
</td>
</tr><!--:#contacts-->
</table>
</body>
</html>";
var contacts = from c in db.contacts select c;
Marker m = new Marker(html);
Filler t = m.Mark("title");
t.Set("Phone book");
Filler c = m.Mark("contacts", "id,name,sex");
// **foreach** expressed in code, not in html
foreach(var contact in contacts) {
int id = contact.id;
c.Add(id, contact.name, contact.sex);
Filler p = c.Mark("phones", "phone");
var phones = from ph in db.phones
where ph.id == id
select new {ph.phone};
if (phones.Any()) {
foreach(var ph in phones) {
p.Add(ph);
}
} else {
fp.Clear();
}
}
Console.Out.WriteLine(m.Get());
Use this code:
Templet.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
namespace templaten.com.Templaten
{
public class tRange
{
public int head, toe;
public tRange(int _head, int _toe)
{
head = _head;
toe = _toe;
}
}
public enum AType
{
VALUE = 0,
NAME = 1,
OPEN = 2,
CLOSE = 3,
GROUP = 4
}
public class Atom
{
private AType kin;
private string tag;
private object data;
private List<Atom> bag;
public Atom(string _tag = "",
AType _kin = AType.VALUE,
object _data = null)
{
tag = _tag;
if (String.IsNullOrEmpty(_tag))
_kin = AType.GROUP;
kin = _kin;
if (_kin == AType.GROUP)
bag = new List<Atom>();
else
bag = null;
data = _data;
}
public AType Kin
{
get { return kin; }
}
public string Tag
{
get { return tag; }
set { tag = value; }
}
public List<Atom> Bag
{
get { return bag; }
}
public object Data
{
get { return data; }
set { data = value; }
}
public int Add(string _tag = "",
AType _kin = AType.VALUE,
object _data = null)
{
if (bag != null)
{
bag.Add(new Atom(_tag, _kin, _data));
return bag.Count - 1;
}
else
{
return -1;
}
}
}
public class Templet
{
private string content;
string namepat = "\\w+";
string justName = "(\\w+)";
string namePre = "#";
string namePost = "";
string comment0 = "\\<!--\\s*";
string comment1 = "\\s*--\\>";
private Atom tokens; // parsed contents
private Dictionary<string, int> iNames; // name index
private Dictionary<string, tRange> iGroups; // groups index
private Atom buffer; // output buffer
private Dictionary<string, int> _iname; // output name index
private Dictionary<string, tRange> _igroup; // output index
public Templet(string Content = null)
{
Init(Content);
}
private int[] mark(string[] names, string group)
{
if (names == null || names.Length < 1) return null;
tRange t = new tRange(0, buffer.Bag.Count - 1);
if (group != null)
{
if (!_igroup.ContainsKey(group)) return null;
t = _igroup[group];
}
int[] marks = new int[names.Length];
for (int i = 0; i < marks.Length; i++)
marks[i] = -1;
for (int i = t.head; i <= t.toe; i++)
{
if (buffer.Bag[i].Kin == AType.NAME)
{
for (int j = 0; j < names.Length; j++)
{
if (String.Compare(
names[j],
buffer.Bag[i].Tag,
true) == 0)
{
marks[j] = i;
break;
}
}
}
}
return marks;
}
public Filler Mark(string group, string names)
{
Filler f = new Filler(this, names);
f.di = mark(f.names, group);
f.Group = group;
tRange t = null;
if (_igroup.ContainsKey(group)) t = _igroup[group];
f.Range = t;
return f;
}
public Filler Mark(string names)
{
Filler f = new Filler(this, names);
f.di = mark(f.names, null);
f.Group = "";
f.Range = null;
return f;
}
public void Set(int[] locations, object[] x)
{
int j = Math.Min(x.Length, locations.Length);
for (int i = 0; i < j; i++)
{
int l = locations[i];
if ((l >= 0) && (buffer.Bag[l] != null))
buffer.Bag[l].Data = x[i];
}
}
public void New(string group, int seq = 0)
{
// place new group copied from old group just below it
if (!( iGroups.ContainsKey(group)
&& _igroup.ContainsKey(group)
&& seq > 0)) return;
tRange newT = null;
tRange t = iGroups[group];
int beginRange = _igroup[group].toe + 1;
for (int i = t.head; i <= t.toe; i++)
{
buffer.Bag.Insert(beginRange,
new Atom(tokens.Bag[i].Tag,
tokens.Bag[i].Kin,
tokens.Bag[i].Data));
beginRange++;
}
newT = new tRange(t.toe + 1, t.toe + (t.toe - t.head + 1));
// rename past group
string pastGroup = group + "_" + seq;
t = _igroup[group];
buffer.Bag[t.head].Tag = pastGroup;
buffer.Bag[t.toe].Tag = pastGroup;
_igroup[pastGroup] = t;
// change group indexes
_igroup[group] = newT;
}
public void ReMark(Filler f, string group)
{
if (!_igroup.ContainsKey(group)) return;
Map(buffer, _iname, _igroup);
f.di = mark(f.names, group);
f.Range = _igroup[group];
}
private static void Indexing(string aname,
AType kin,
int i,
Dictionary<string, int> dd,
Dictionary<string, tRange> gg)
{
switch (kin)
{
case AType.NAME: // index all names
dd[aname] = i;
break;
case AType.OPEN: // index all groups
if (!gg.ContainsKey(aname))
gg[aname] = new tRange(i, -1);
else
gg[aname].head = i;
break;
case AType.CLOSE:
if (!gg.ContainsKey(aname))
gg[aname] = new tRange(-1, i);
else
gg[aname].toe = i;
break;
default:
break;
}
}
private static void Map(Atom oo,
Dictionary<string, int> dd,
Dictionary<string, tRange> gg)
{
for (int i = 0; i < oo.Bag.Count; i++)
{
string aname = oo.Bag[i].Tag;
Indexing(oo.Bag[i].Tag, oo.Bag[i].Kin, i, dd, gg);
}
}
public void Init(string Content = null)
{
content = Content;
tokens = new Atom("", AType.GROUP);
iNames = new Dictionary<string, int>();
iGroups = new Dictionary<string, tRange>();
// parse content into tokens
string namePattern = namePre + namepat + namePost;
string patterns =
"(?<var>" + namePattern + ")|" +
"(?<head>" + comment0 + namePattern + ":" + comment1 + ")|" +
"(?<toe>" + comment0 + ":" + namePattern + comment1 + ")";
Regex jn = new Regex(justName, RegexOptions.Compiled);
Regex r = new Regex(patterns, RegexOptions.Compiled);
MatchCollection ms = r.Matches(content);
int pre = 0;
foreach (Match m in ms)
{
tokens.Add(content.Substring(pre, m.Index - pre));
int idx = -1;
if (m.Groups.Count >= 3)
{
string aname = "";
MatchCollection x = jn.Matches(m.Value);
if (x.Count > 0 && x[0].Groups.Count > 1)
aname = x[0].Groups[1].ToString();
AType t = AType.VALUE;
if (m.Groups[1].Length > 0) t = AType.NAME;
if (m.Groups[2].Length > 0) t = AType.OPEN;
if (m.Groups[3].Length > 0) t = AType.CLOSE;
if (aname.Length > 0)
{
tokens.Add(aname, t);
idx = tokens.Bag.Count - 1;
}
Indexing(aname, t, idx, iNames, iGroups);
}
pre = m.Index + m.Length;
}
if (pre < content.Length)
tokens.Add(content.Substring(pre, content.Length - pre));
// copy tokens into buffer
buffer = new Atom("", AType.GROUP);
for (int i = 0; i < tokens.Bag.Count; i++)
buffer.Add(tokens.Bag[i].Tag, tokens.Bag[i].Kin);
// initialize index of output names
_iname = new Dictionary<string, int>();
foreach (string k in iNames.Keys)
_iname[k] = iNames[k];
// initialize index of output groups
_igroup = new Dictionary<string, tRange>();
foreach (string k in iGroups.Keys)
{
tRange t = iGroups[k];
_igroup[k] = new tRange(t.head, t.toe);
}
}
public string Get()
{
StringBuilder sb = new StringBuilder("");
for (int i = 0; i < buffer.Bag.Count; i++)
{
switch (buffer.Bag[i].Kin)
{
case AType.VALUE:
sb.Append(buffer.Bag[i].Tag);
break;
case AType.NAME:
sb.Append(buffer.Bag[i].Data);
break;
case AType.OPEN:
case AType.CLOSE:
break;
default: break;
}
}
return sb.ToString();
}
}
public class Filler
{
private Templet t = null;
public int[] di;
public string[] names;
public string Group { get; set; }
public tRange Range { get; set; }
private int seq = 0;
public Filler(Templet tl, string markers = null)
{
t = tl;
if (markers != null)
names = markers.Split(new char[] { ',' },
StringSplitOptions.RemoveEmptyEntries);
else
names = null;
}
public void init(int length)
{
di = new int[length];
for (int i = 0; i < length; i++)
di[i] = -1;
seq = 0;
Group = "";
Range = null;
}
// clear contents inside marked object or group
public void Clear()
{
object[] x = new object[di.Length];
for (int i = 0; i < di.Length; i++)
x[i] = null;
t.Set(di, x);
}
// set value for marked object,
// or add row to group and set value to columns
public void Set(params object[] x)
{
t.Set(di, x);
}
public void Add(params object[] x)
{
if (Group.Length > 0)
{
t.New(Group, seq);
++seq;
t.ReMark(this, Group);
}
t.Set(di, x);
}
}
}
Testing program
Program.cs
Templet m = new Templet(html);
Filler f= m.Mark("title");
f.Set("Phone book");
Filler fcontacts = m.Mark("contacts", "id,name,sex,phone");
fcontacts.Add(1, "Akhmad", "M", "123456");
fcontacts.Add(2, "Barry", "M", "234567");
fcontacts.Add(1, "Charles", "M", "345678");
Console.Out.WriteLine(m.Get());
Still can't do nested loop- yet.
Just use ASP.NET. Whether you use webforms or MVC, it's super easy to have C# in your .cs files, and HTML in your .aspx files.
As with anything in programming, it's 99% up to you to do things right. Flexible UI engines aren't going to enforce that you follow good coding practices.
In principle most any template engine you choose can separate HTML from control logic with the proper architecture. using an MVC (Or MVVM) pattern, if you construct your model in such a way that the controller contains the if/then logic instead of the view you can eliminate it from the view.
That said, the syntax you use is very close to Razor syntax which is easily available for ASP.NET MVC through NuGet packages.
I totally hear you. I built SharpFusion, which has some other stuff in it but if you look for the template.cs file you will see the handler that parses a HTML file and simply replaces out tokens with values that you've made in c#.
Because no XML parsing is done like ASP.NET the framework loads much faster than even an MVC site.
Another alternative is ServiceStack.