Well that felt rewarding. I got stuck a few times, got a little frustrated but persevered.
PSET2 to recap I had to make 3 programs using the C programming Language.
initials.c
caesar.c
vigenere.c
Initials.c
This code prompts a user for his/her name, and then prints out the initials.
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
//asks for name
string GetName = GetString();
//Prints First Initial
printf("%c", toupper(GetName[0]));
//Finds whitespace and prints next letter
for (int i=0, n = strlen(GetName); i <n; i++)
{
if (GetName[i] == ' ')
printf("%c", toupper(GetName[i+1])) ;
}
printf("\n");
//return 0;
}
Summary
I had troubles trying to figure out how to find the first character of each name. After many attempts I had a light-bulb go off, printing the first character after a space. So my code finds the whitespace, then prints out the next letter. Looking back at how long it took my I feel a little dumb, but I think that is a good thing as that means I have learned a lot!
Caesar Cipher
This program runs with a command line argument. The argument has to be an integer. If an integer is not ran when executing the program, it will return an error message and fail.
Key = 7
Example: If I execute: ./caesar 7
This program enciphers text using the Caesar Cipher.
It Spits out
Aopz wyvnyht lujpwolyz alea bzpun aol Jhlzhy Jpwoly
Here is my code.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main (int argc, string argv[])
{
//error checks 1 command line argument
if (argc != 2)
{
printf ("Enter 1 Command Line Integer");
return 1;
}
//converts string number into an integer
int k = atoi(argv[1]);
//grabs a string from the user
string UserInput = GetString();
//This will itereate through each character in user input
for (int i = 0, n = strlen(UserInput); i < n; i++)
{
int c = 0;
//IF input is a letter
if (isalpha(UserInput[i]))
{
//IF input is UpperCase
if (isupper(UserInput[i]))
{
c = (((int)UserInput[i] - 65 + k) % 26) + 65; //calculates integer value of upper character and adds caser cipher key
printf("%c",(char) c);
}
//If string Input is lowerCase
if (islower(UserInput[i])) //If is a letter and lowercase
{
c = (((int)UserInput[i] - 97 + k) % 26) + 97; //calculates integer value of lowercase character and adds caser cipher key
printf("%c",(char) c );
}
}
else
{
//prints a space if space in string
printf("%c", UserInput[i]);
}
}
printf("\n");
return 0;
}
Summary
I struggled with this quite mightily. I ended up quitting, then coming back to it the next day, and spending probably 9-10 hours on it. I knew I needed to iterate over the string, but after I was overwhelmed at the next step. When I attempted the next step I wasn't sure if i was doing it right.
I ended up creating and deleting my code multiple times.I found out that I don't break down the problems very well. I was overwhelmed trying to figure how upper/lower case figures out with the algorithm to solve.
This is what I should have done from the start.
- Really grasp how the modulo works first.
- ex 1 % 3 = 1 why?
- well 1 can't divide into 3, so 1 is the remainder
- likewise 2 % 3 = 2
- When figuring out the formula, forget everything else and write down an examples
- lower case a Key of 7 = h
- lower case a Key of 33 = h
- ascii a = 97
- ascii h = 104
- you can see you only need to apply modulo to the Key and not the ascii value. That is where I spent a lot of time banging my head against a wall, and the corresponding "duh" moment when I re-visited how modulo works.
Again looking back I feel a bit embarrassed I took so long to solve this. Here I learned a lot about how to convert and add letters to ints, and visa versa. more importantly I think I made a tiny step forward in learning how to break problems down more efficiently.
Vigenere
Instead of a key like Caesar, vigenere takes a keyword.
This program takes a keyword as a user argument. It then waits for a user to enter a string of text. This program then enciphers the text with vigenere
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main (int argc, string argv[])
{
//if their are less than 1 argument return an error and prompt user to try again
if (argc != 2)
{
printf ("Enter 1 Command Line Integer\n");
return 1;
}
string key = argv[1];
int keyLength = strlen(key) ;
//Iterate through argv and check to ensure everything is an alphabet character
for (int i = 0, n = strlen(key); i < n; i++)
{
if (!isalpha(key[i]))
{
printf("You have a number in your key, Try again\n");
return 1;
}
}
//Grabs a string to be ciphered
string UserInput = GetString();
//i tracks string position, j tracks keyLength position
//This will itereate through each character in user input string
for (int i = 0, j = 0, n = strlen(UserInput); i < n; i++)
{
int cipherLetter = 0;
int shift = 0;
//this checks for alphabet characters
if (isalpha(UserInput[i]))
{
//finds shift if letter is uppercase
if (isupper(UserInput[i]))
{
//calculates lowercase shift value
shift = (int)toupper(key[j]) - 65;
//adds shift value to letter value and wraps around alphabet
cipherLetter = (((int)UserInput[i] - 65 + shift) % 26) + 65;
//prints coresponding enciphered letter
printf("%c", (char)(cipherLetter));
j++;
}
//finds key shift if letter is lowercase
if (islower(UserInput[i]))
{
//calculates lwoercase shift value
shift = (int)tolower(key[j]) - 97;
//adds shift value to letter value and wraps around alphabet
cipherLetter = (((int)UserInput[i] - 97 + shift) % 26) + 97;
//prints coresponding enciphered letter
printf("%c", (char)(cipherLetter) );
j++;
}
}
else
{
printf("%c", UserInput[i]);
}
//wraps key back to first position
if (j >= keyLength)
{
j = 0;
}
}
printf("\n");
}
Summary:
This didn't take me as long as Caesar did. probably 5 hours. Still longer than I would like to admit. I did get a bit overwhelmed again and looked for help. I had an aha moment when I saw a loop with 2 counter variables being initialized in the condition. I didn't realize that was an option.
I took a small break, stepped back and tried to go through this step by step. I ended up building some test code as I went. I experimented with print f everytime I wrote a line of code to test my integer and character math. I think going forward I will continue to do this if I can as it will help me to break the problems down and not become overwhelmed at the big picture.
I felt I cemented my knowledge of modulo as well as learned how to keep track of 2 changing variables for a loop.
It feels very rewarding to finish this. I am probably going to spend some time watching the RSA encryption video again, as well as week 3's videos.
ProblemSet3
Week 3 has a total of 3.5 hours of video to not only watch, but understand. I found in the past I usually watch some videos more than once to understand a concept. Most people who have done the course say Pset3 is a slight notch more difficult, but far from the most difficult pset.
The problem sets will be changed at the end of the year. So I essentially have until the end of the year to complete a problem set. Knowing that their is only 2 weeks left in the year, with one of those being Christmas and multiple Christmas parties. I will only attempt one more pset before they change. It might be a tight fit, especially since my freetime after this weekend will be at a premium.
Hopefully I can get a few hours at work I can escape to learn.
No comments:
Post a Comment