I would like to preface this by saying it is for an assessment, so I don't want you to directly give me the answer, I would like you to point me in the right direction, slightly tweak what I have done or just tell me what I should look into doing.
I am trying to create a Caesar Cipher to decipher a text document we have been given. It needs to print all the possible shifts in the console and output the final one to a text document. I'm thinking of trying to add frequency analysis to this later to find the correct one, but I have some problems now that I need to sort out before I can do that.
This is what I have made so far:
using System;
using System.IO;
class cipher
{
public static void Main(string[] args)
{
string output = "";
int shift;
bool userright = false;
string cipher = File.ReadAllText("decryptme.txt");
char[] decr = cipher.ToCharArray();
do {
Console.WriteLine("How many times would you like to shift? (Between 0 and 26)");
shift = Convert.ToInt32(Console.ReadLine());
if (shift > 26) {
Console.WriteLine("Over the limit");
userright = false;
}
if (shift < 0) {
Console.WriteLine("Under the limit");
userright = false;
}
if (shift <= 26 && shift >= 0)
{
userright = true;
}
} while (userright == false);
for (int i = 0; i < decr.Length; i++)
{
{
char character = decr[i];
character = (char)(character + shift);
if (character == '\'' || character == ' ')
continue;
if (character > 'Z')
character = (char)(character - 26);
else if (character < 'A')
character = (char)(character + 26);
output = output + character;
}
Console.WriteLine("\nShift {0} \n {1}", i + 1, output);
}
StreamWriter file = new StreamWriter("decryptedtext.txt");
file.WriteLine(output);
file.Close();
}
}
Right now it compiles and read the document but when it runs in the console it prints shift one as 1 letter from the encoded text, shift 2 as 2 letters from it, etc.
I have no idea what I have done wrong and any help would be greatly appreciated. I have also started thinking about ASCII values for letters but have no idea how to implement this.
Once again, please don't just give me the answer or I will not have learned anything from this - and I have been trying to crack this myself but had no luck.
Thanks.
Break the problem down into smaller bite-sized chunks. Start by printing a single shifted line, say with a shift of 1.
When you have that part working correctly (and only then) extend your code to print 26 lines with shifts of 0, 1, 2, 3, ... 26. I am not sure if your instructor wants either or both of shift 0 at the start and shift 26 at the end. You will need to ask.
Again, get that working correctly, and write new code to analyse one line only, and give it some sort of score. Get that working properly.
Now calculate the scores for all the lines and pick out the line with the best score. That should be the right answer. If it isn't then you will need to check your scoring method.
Writing small incremental changes to a very simple starting program is usually a lot easier than trying to go straight from a blank screen to the full, complex, program. Add the complexity gradually, one piece at a time, testing as you go.
Related
This question already has answers here:
What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?
(5 answers)
Closed 3 months ago.
Hi just needed a little bit of help with a crash im having, so im putting together a little program that will work similar to a Caesar cipher by shifting the letters by a set value, however each subsequent letter is shifted to a different letter, rather then all letters being shifted by the same value (which is easy to crack with frequency analysis).
Anyway the program works fine if the word being encoded is shorter or the same length as the code (like a 7 letter word being encoded by a 7 digit code), but as soon as you try to encode a word longer than it, it crashes with an array out of bounds error or something.
What needs to happen is it needs to loop back around to the start of the code until no more letters need encoding.
```
```
static char ZipherEncode(char input, int shift)
{
char letter = (char)(input + shift);
if (letter > 'z')
{
letter = (char)(letter - 26);
}
else if (letter < 'a')
{
letter = (char)(letter + 26);
}
return letter;
}
static char ZipherDecode(char input, int shift)
{
char letter = (char)(input - shift);
if (letter > 'z')
{
letter = (char)(letter - 26);
}
else if (letter < 'a')
{
letter = (char)(letter + 26);
}
return letter;
}
int[] codeShift = new int[] { 4, 2, 6, 3, 0, 5, 1 };
Console.WriteLine("Please enter a word to encode: ");
string input = Console.ReadLine();
char[] zipherEncoded = new char[input.Length];
zipherEncoded = input.ToCharArray();
Console.WriteLine("\n\nENCODED: ");
int currCode = codeShift[0];
int counter = 0;
for (int i = 0; i < zipherEncoded.Length; i++)
{
if (zipherEncoded[i] != '\0')
{
//DEBUG
Console.WriteLine("WE ARE HERE!");
Console.Write("{0}", ZipherEncode(zipherEncoded[i], codeShift[i]));
}
else
{
//DEBUG
Console.WriteLine("WE ARE HERE (ELSE)!");
Console.Write("{0}", ZipherEncode(zipherEncoded[i], codeShift[currCode]));
//Console.Write("{0}", ZipherEncode(zipherEncoded[i], codeShift[counter]));
//Console.Write("{0}", ZipherEncode(zipherEncoded[i], Array.IndexOf(codeShift, currCode)));
counter++;
}
}
Console.ReadLine();
```
```
The output when I encode the word "volcano" reads -
ENCODED:
zqrfasp
This is correct, however when I try and encode "volcanocat", because the word is longer than the 7 digits in the code it crashes, the output should read -
ENCODED:
zqrfaspgcz
the "cat" part of the phrase should be encoded with a shift of 426 <<< loops back to the start of the codeShift array storing our shifts.
C (Shift of 4) > G
A (Shift of 2) > C
T (Shift of 6) > Z
As from the parts that are commented out you can see im trying to find a way to have it loop back around to the start of the shift code to finish off the final letters.
Im really new to C# so there may be a function built in to do what I want, but I cant get my head around it!
I think I cant see the forrest through the trees!
The problem is here:
ZipherEncode(zipherEncoded[i], codeShift[i])
In this code, i represents an index in the input string, but you're also using it as an index in the codeShift array. Since the input string may be longer than the array, you'll get an out of bounds error.
One way to resolve this would be to use a modulus operation (the% operator), which returns the remainder of a division. This can be used to always constrain the index to a value within the size of the codeShift array.
For example, let's pretend that the word has 6 characters but we only have 3 items in the codeShift array. We're fine for indexes 0, 1, and 2, but when we get to 3 we need to access the value at 0 again in the array. To do this, we can say:
int codeShiftIndex = i % codeShift.Length;
As we stated, codeShift has a length of 3, so when i is 3, i % 3 == 0 (the remainder of three divided by three), and when i is 4, i % 3 == 1, etc.
So your code change would look like:
ZipherEncode(zipherEncoded[i], codeShift[i % codeShift.Length])
I created an IF Statement for my XNA game which makes my characters leave their classroom(screen). There are 40 characters, in lines of 10. 'Dest' means destination of the character. This code is in my update method and I have a list of characters in my initialize method:
if (activeCharacter.DestX < 680)
{
activeCharacter.DestX = activeCharacter.DestX + 6;
}
else if (activeCharacter.DestY < 600) //600
{
activeCharacter.DestY = activeCharacter.DestY + 6;
}
else if (activeCharacter.DestY == 600)
{
activeCharacter = classroom[(Random.Next(classroom.Count))];
Console.WriteLine(activeCharacter.DestY);
The aim is to have random characters leave the classroom. When a character from the 1st row leaves, another random character will leave straight after and another depending on if it's from the first row. However if a character from any other row except the 1st leaves, only one character will go.
Can someone please tell me stop this from happening?
Thanks!
DestY is incremented by 6, until it is bigger then or equal to 600. However the final else if only checks for equal to 600.
Changing the final check to:
else if (activeCharacter.DestY >= 600)
Or simply:
else
Will most likely solve your problem.
I've searched online for a diff algorithm but none of them do what I am looking for. It is for a texting contest (as in cell phone) and I need the entry text compared to the master text recording the errors along the way. I am semi-new to C# and I get most of the string functions and didn't think this was going to be that hard of a problem, but alas I just can't wrap my head around it.
I have a form with 2 rich-text-boxes (one on top of the other) and 2 buttons. The top box is the master text (string) and the bottom box is the entry text (string). Every contestant is sending a text to an email account, from the email we copy and paste the text into the Entry RTB and compare to the Master RTB. For each single word and single space counts as a thing to check. A word, no matter how many errors it has, is still 1 error. And for every error add 1 sec. to their time.
Examples:
Hello there! <= 3 checks (2 words and 1 space)
Helothere! <= 2 errors (Helo and space)
Hello there!! <= 1 error (extra ! at end of there!)
Hello there! How are you? <= 9 checks (5 words and 4 spaces)
Helothere!! How a re you? <= still 9 checks, 4 errors(helo, no space, extra !, and a space in are)
Hello there!# Ho are yu?? <= 3 errors (# at end of there!, no w, no o and extra ? (all errors are still under the 1 word)
What I have so far:
I've created 6 arrays (3 for master, 3 for entry) and they are
CharArray of all chars
StringArray of all strings(words) including the spaces
IntArray with length of the string in each StringArray
My biggest trouble is if the entry text is wrong and it's shorter or longer than the master. I keep getting IndexOutOfRange exceptions (understandably) but can't fathom how to go about checking and writing the code to compensate.
I hope I have made myself clear enough as to what I need help with. If anyone could give some code examples or something to shoot me in the right path would be very helpful.
Have you looked into the Levenshtein distance algorithm? It returns the number of differences between two strings, which, in your case would be texting errors. Implementing the algorithm based off the pseudo-code found on the wikipedia page passes the first 3 of your 4 use cases:
Assert.AreEqual(2, LevenshteinDistance("Hello there!", "Helothere!");
Assert.AreEqual(1, LevenshteinDistance("Hello there!", "Hello there!!"));
Assert.AreEqual(4, LevenshteinDistance("Hello there! How are you?", "Helothere!! How a re you?"));
Assert.AreEqual(3, LevenshteinDistance("Hello there! How are you?", "Hello there!# Ho are yu??")); //fails, returns 4 errors
So while not perfect out of the box, it is probably a good starting point for you. Also, if you have too much trouble implementing your scoring rules, it might be worth revisiting them.
hth
Update:
Here is the result of the string you requested in the comments:
Assert.AreEqual(7, LevenshteinDistance("Hello there! How are you?", "Hlothere!! Hw a reYou?"); //fails, returns 8 errors
And here is my implementation of the Levenshtein Distance algorithm:
int LevenshteinDistance(string left, string right)
{
if (left == null || right == null)
{
return -1;
}
if (left.Length == 0)
{
return right.Length;
}
if (right.Length == 0)
{
return left.Length;
}
int[,] distance = new int[left.Length + 1, right.Length + 1];
for (int i = 0; i <= left.Length; i++)
{
distance[i, 0] = i;
}
for (int j = 0; j <= right.Length; j++)
{
distance[0, j] = j;
}
for (int i = 1; i <= left.Length; i++)
{
for (int j = 1; j <= right.Length; j++)
{
if (right[j - 1] == left[i - 1])
{
distance[i, j] = distance[i - 1, j - 1];
}
else
{
distance[i, j] = Min(distance[i - 1, j] + 1, //deletion
distance[i, j - 1] + 1, //insertion
distance[i - 1, j - 1] + 1); //substitution
}
}
}
return distance[left.Length, right.Length];
}
int Min(int val1, int val2, int val3)
{
return Math.Min(val1, Math.Min(val2, val3));
}
You need to come up with a scoring systems that works for you're situation.
I would make a word array after each space.
If a word is found on the same index +5.
If a word is found on the same index +-1 index location +3 (keep a counter how much words differ to increase the +- correction
If a needed word is found as part of another word +2
etc.etc. Matching words is hard, getting up with a rules engine that works is 'easier'
I once implemented an algorithm (which I can't find at the moment, I'll post code when I find it) which looked at the total number of PAIRS in the target string. i.e. "Hello, World!" would have 11 pairs, { "He", "el", "ll",...,"ld", "d!" }.
You then do the same thing on an input string such as "Helo World" so you have { "He",...,"ld" }.
You can then calculate accuracy as a function of correct pairs (i.e. input pairs that are in the list of target pairs), incorrect pairs (i.e. input pairs that do not exists in the list of target pairs), compared to the total list of target pairs. Over long enough sentences, this measure would be very accurate fair.
A simple algorithm would be to check letter by letter. If the letters differ increment the num of errors. If the next pairing of letters match, its a switched letter so just continue. If the messup matches the next letter, it is an omission and treat it accordingly. If the next letter matches the messed up one, its an insertion and treat it accordingly. Else the person really messed up and continue.
This doesn't get everything but with a few modifications this could become comprehensive.
a weak attempt at pseudocode:
edit: new idea. look at comments. I don't know the string functions off the top of my head so you'll have to figure that part out. The algorithm kinda fails for words that repeat a lot though...
string entry; //we'll pretend that this has stuff inside
string master; // this too...
string tempentry = entry; //stuff will be deleted so I need a copy to mess up
int e =0; //word index for entry
int m = 0; //word index for master
int errors = 0;
while(there are words in tempentry) //!tempentry.empty() ?
string mword = the next word in master;
m++;
int eplace = find mword in tempentry; //eplace is the index of where the mword starts in tempentry
if(eplace == -1) //word not there...
continue;
else
errors += m - e;
errors += find number of spaces before eplace
e = m // there is an error
tempentry = stripoff everything between the beginning and the next word// substring?
all words and spaces left in master are considered errors.
There are a couple of bounds checking errors that need to be fixed here but its a good start.
I am looking for a c# function or routine that will center justify text.
For example, if I have a sentence, I have noticed that when the sentence is justified to the edges of the screen, that spaces are placed in the line. The inserted spaces start in the center and move out from there on both sides as needed as needed.
Is there a C# function that I can pass my string, say 50 chars, and get back a pretty 56 char string?
Thanks in advance,
Rob
Nice task. Here's a solution based on Linq extension methods. If you do not wish to use them, see history for previous version of code. In this example spaces on the left and right sides from center are 'equal' with respect to order of inserting.
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
public static String Justify(String s, Int32 count)
{
if (count <= 0)
return s;
Int32 middle = s.Length / 2;
IDictionary<Int32, Int32> spaceOffsetsToParts = new Dictionary<Int32, Int32>();
String[] parts = s.Split(' ');
for (Int32 partIndex = 0, offset = 0; partIndex < parts.Length; partIndex++)
{
spaceOffsetsToParts.Add(offset, partIndex);
offset += parts[partIndex].Length + 1; // +1 to count space that was removed by Split
}
foreach (var pair in spaceOffsetsToParts.OrderBy(entry => Math.Abs(middle - entry.Key)))
{
count--;
if (count < 0)
break;
parts[pair.Value] += ' ';
}
return String.Join(" ", parts);
}
static void Main(String[] args) {
String s = "skvb sdkvkd s kc wdkck sdkd sdkje sksdjs skd";
String j = Justify(s, 5);
Console.WriteLine("Initial: " + s);
Console.WriteLine("Result: " + j);
Console.ReadKey();
}
}
As far as I know, there is no "built-in" C# or .net library function for this, so you'd have to implement something on your own (or find some code online whose license suits your needs).
A simple greedy algorithm shouldn't be too difficult to implement, however:
Until the required number of characters is reached:
Extend the shortest sequence of spaces by one
(choose one randomly if there is more than one such sequence).
I'd distribute the spaces randomly rather than starting at the center, to make sure the spaces are evenly distributed among your text (rather than concentrated at one position). Oh, and keep in mind that some people consider fully-justified fixed-font text harder to read than left-justified fixed-font text.
I'm trying to work my way through Ron Jeffries's Extreme Programming Adventures in C#. I am stuck, however, in Chapter 3 because the code does not, and cannot, do what the author says it does.
Basically, the text says that I should be able to write some text in a word-wrap enabled text box. If I then move the cursor to an intermediate line and hit enter, the code should re-display the lines before the cursor, add a couple of lines and a set of HTML paragraph tags, then append the rest of the lines. The code doesn't match the text because it uses the textbox.lines property. Well, no matter how many word-wrapped lines there are in a text box, there's only ONE line in the Lines property until you hit a carriage return. So, the statement that the code should, "Copy the rest of the lines into the buffer" appears wrong to me.
I'd appreciate anybody having experience with the book telling me what I'm reading, or doing, wrong!
Thanks.
EoRaptor
Try emailing Ron Jeffries directly. I have the book - somewhere, but I don't remember it not working. His email address is ronjeffries at acm dot org and put [Ron] in the subject line.
(And for those wondering - his email info was right from his website Welcome page)
I've also just started this book and had exactly the same problem although the code you have included looks further along than where I am.
The 'subscript out of range' occurred for 2 reasons, first as Ron explains he was just testing and so returned a hard-coded value of 3 before he wrote the CursorLine() function, which means you I think at least 4? lines of text which as you say need to be pasted in, or maybe set the text to this value before running, also as you say they need to have carriage returns to make txtbox.Lines return an array of strings.
The second reason occurs even after CursorLine() has been implemented but only happens if the text box is empty as txtbox.Lines returns string[0] but I think Ron is implementing a 'User Story' which says that when text has been entered and user presses enter, so not sure if he fixes this later, but will probably find out!
The author's do state that they are learning C# and will show the development wart's and all, which is one of the reasons I have chosen to study this book as I think it is encouraging me to develop projects. I also try to do the code first before looking at his solutions to see if I'm thinking the same way, but maybe I know C# a little better than I give myself credit for, or I'm completly crap, but I've noticed a few things, first he says that overriding OnKeyDown() doesn't work, but I think he must have got confused and tried to do in Form, instead of deriving from TextBox and overriding there.
This was my code when reading the 'User Story':
int curPos = txtbox.SelectionStart;
string Wrd = Environment.NewLine + "<P></P>" + Environment.NewLine;
txtbox.SelectedText = Wrd;
int pl = Environment.NewLine.Length + 3; // "<P>" length is 3
// Put text cursor inbetween <P> tags
txtbox.SelectionStart = curPos + pl;
It works differently to Ron's code, but was just my interpretation of the 'User Story' and not sure how should act if text is selected or wether to split line if text cursor in the middle etc.
Also in 'My Adventures' in Extreme Programming Adventures in C#
txtbox.GetLineFromCharIndex(txtbox.SelectionStart)
gets the cursor line position and doesn't matter if no carriage returns or resized,
as far as I can tell, I done little test with:
txtbox.GetLineFromCharIndex(txtbox.TextLength)
which returns the total amount of lines, which will vary if you resize the text box.
Using C# I always look for solutions which already exsist and people may slate me for this but I think MS have created a great language with great components which do what you expect them to do, so don't have to re-create the wheel each time.
Although like I say it's early days in this book and perhaps these simple solutions aren't extensible enough and maybe Ron's taking that into account, although he did mention just get it working then worry about that later is more the XP way.
Warren.
print("using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace NotepadOne {
public class TextModel {
private String[] lines;
private int selectionStart;
private int cursorPosition;
public TextModel() {
}
public String[] Lines {
get {
return lines;
}
set {
lines = value;
}
}
public int SelectionStart {
get {
return selectionStart;
}
set {
selectionStart = value;
}
}
public int CursorPosition {
get {
return cursorPosition;
}
set {
cursorPosition = value;
}
}
public void InsertControlPText() {
lines[lines.Length - 1] += "ControlP";
}
public void InsertParagraphTags() {
int cursorLine = CursorLine();
String[] newlines = new String[lines.Length + 2];
for (int i = 0; i <= cursorLine; i++) {
newlines[i] = lines[i];
}
newlines[cursorLine + 1] = "";
newlines[cursorLine + 2] = "<P></P>";
for (int i = cursorLine + 1; i < lines.Length; i++) {
newlines[i + 2] = lines[i];
}
lines = newlines;
selectionStart = NewSelectionStart(cursorLine + 2);
}
private int CursorLine() {
int length = 0;
int lineNr = 0;
foreach (String s in lines) {
if (length <= SelectionStart && SelectionStart <= length + s.Length + 2) {
break;
length += s.Length + Environment.NewLine.Length;
lineNr++;
}
lineNr++;
}
return lineNr;
}
private int NewSelectionStart(int cursorLine) {
int length = 0;
for (int i = 0; i < cursorLine; i++) {
length += lines[i].Length + Environment.NewLine.Length;
}
return length + 3;
}
}
}
");
The InsertParagraphTags method is called by pressing the enter key in the textbox.
BTW, the break here is that there is a subscript out of range error if you try to hit enter at the end of the text. I'm sure I could figure out how to get around this but then my code won't look like his code; which is what I'm trying to learn.
Randy