making my CS50 solution more elegant and efficient - c

I am taking CS50, and I completed the first week problem of implementing the Luhn Check algorithm. Although my solution works, I feel it's very sloppy and not efficient. Can someone please suggest how I can improve my solution. (It's a first week problem; you are not intended to use arrays or functions.)
Here is the code:
#include<stdio.h>
#include<stdlib.h>
#include<cs50.h>
int main()
{
long long x,j=0;
int len,i,len_flag,flag=0,flag_val=0,sp_len=0,check_flag=0; //basic integers related to loop etc
int res,sum,fin_sum=0,h=0,d2_sum=0,d1_sum=0,ff_num=0; // variables related to extracting numbers
int sum_len=0,in_sum=0,in_fsum=0,len_sum=0,m=0; // extraing numbers from more than single sum result
int sum_f=0,sum_final=0;
do{
x = get_long("enter a valid card number \n");
j=x;
len_flag = 0;
len = 0;
while(len_flag!=1)
{
x = x / 10;
if(x==0)
{
len_flag = 1; //finding the lenght of the number
}
len++;
}
if(len==15||len==16||len==13)
{
flag = 1;
sp_len =1;
}
else
{
flag=1;
}
}while(flag!=1);
for(i=0;i<len;i++)
{
res = j % 10;
j = j / 10;
if(i%2!=0)
{
sum = res * 2;
//printf("multi_res : %d \n",sum);
len_flag = 0;
sum_len = 0;
len_sum = sum;
while(len_flag!=1)
{
len_sum = len_sum / 10;
if(len_sum==0)
{
len_flag=1; // checking if the sum is more than single digit
}
sum_len++;
//printf("trig\n");
}
if(sum_len>1)
{ x=0;
while(x<sum_len)
{
in_sum = sum % 10;
sum = sum/10;
in_fsum = in_fsum + in_sum;
//printf("double sum : %d \n",in_fsum);
x++;
}
}
fin_sum = fin_sum + sum;
}
if(i==len-1)
{
for(h=0;h < 1;h++)
{
fin_sum = fin_sum + in_fsum;
}
d1_sum = res;
}
else if(i%2==0)
{
sum_f = sum_f + res; // adding up the number that where not x2
}
if(i==len-2)
{
d2_sum = res; //5555555555554444
}
}
sum_final = sum_f + fin_sum;
//printf("sum_final : %d\n",sum_final);
//printf("sum_f_final : %d\n",sum_f);
//printf("sum_in_final : %d\n",fin_sum);
if(sum_final%10==0)
{
flag_val=1; // checking if the number is valid
}
if(ff_num == 0)
{
ff_num = (d1_sum*10) + d2_sum; //flip
}
do
{
if(sp_len==0)
{
printf("INVALID\n");
check_flag=1;
break;
}
if((flag==1&&flag_val==1&&ff_num==34)||ff_num==37)
{
printf("AMEX\n");
check_flag=1;
break;
}
else if(flag==1&&flag_val==1&&ff_num>50&&ff_num<56)
{
printf("MASTERCARD\n");
check_flag=1;
break;
}
else if(flag==1&&flag_val==1&&d1_sum==4)
{
printf("VISA\n");
check_flag=1;
break;
}
else
{
printf("INVALID\n");
check_flag=1;
break;
}
}while(check_flag!=1);
return 0;
}
I felt like I was fixing a leak while writing the code. I would try to correct one thing, and another thing would go wrong, and this is the final result.

Related

How do I make this code shorter and more efficient?

This is my solution for the Credit problem on CS50's Pset1. It involves using Luhn's Algorithm to test the validity of the Credit Card Number entered and based on a few conditions attempts to identify the Credit Card Company.
Check_Length attempts to find the length of the number entered.
Check_Company attempts to ID the company.
Check_Luhn validates the number based on Luhn's Algorithm.
I'd like to know if this could be done with fewer lines of code.
#include <stdio.h>
#include <cs50.h>
#include <stdbool.h>
int check_length(long);
void check_company(int,long);
bool check_luhn(long,int);
int length;
int main(void)
{
long c = get_long("Enter Credit Card Number: ");
check_length(c);
check_luhn(c,length);
if(check_luhn(c,length)==true)
{
check_company(length,c);
}
else printf("INVALID\n");
}
int check_length(long w)
{
for(int i=12;i<16;i++)
{
long power = 1;
for (int k=1;k<i+1;k++)
{
power = power * 10;
}
int scale = w/power;
if (scale<10 && scale>0)
{
length = i+1;
}
}
return length;
}
void check_company(int x,long z)
{
if(x == 15)
{
int y = z/10000000000000; //z/10^13
if(y==34||y==37)
{
printf("AMEX\n");
}
else
{
printf("INVALID\n");
}
}
else if(x==13)
{
int y = z/100000000000; //z/10^11
if(y==4)
{
printf("VISA\n");
}
}
else if(x==16)
{
int q = z/1000000000000000;
int y = z/100000000000000;
if(y==51||y==52||y==53||y==54||y==55)
{
printf("MASTERCARD\n");
}
else
if(q==4)
{
printf("VISA\n");
}
else printf("INVALID\n");
}
else printf("INVALID\n");
}
bool check_luhn(long a,int b)
{
int f = 0;
int j=0;
for(int d=1;d<b+1;d++)
{
int e = a%10;
a = a/10;
if(d%2==1)
{
f = f+e;
}
else
{
int m = 2*e;
int g = m%10;
int h = m/10;
j = j+g+h;
}
}
int l = j + f;
if(l%10==0)
{
return true;
}
else return false;
}

Why is the computer's input not being considered?

In the code below there is an error I can't locate causing the computer's selection to not be accounted for. The user's input is being considered in the Nim game yet the computer's pieces are not being subtracted.
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
void printInstructions();
int getUserInput(int);
int randomRange(int,int);
int PlayerTurn(int);
int smartCompMove(int);
int dumbCompMove(int);
int main()
{
srand(time(NULL));
int pieceAmount = randomRange(12,24);
char smartCompOrDumb;
printf("Do you want to play a smart computer or a dumb one? Select 'S' or 'D'.");
scanf("%c",&smartCompOrDumb);
bool gameOver = false;
bool playerTurn = true;
printInstructions();
while(pieceAmount > 0 && gameOver == false)
{
if (playerTurn == false)
{
if(pieceAmount <= 4)
{
printf("\nThe Computer has won :P ");
gameOver = true;
exit(0);
}
if (smartCompOrDumb == 's' || smartCompOrDumb == 'S')
{
playerTurn = true;
pieceAmount = smartCompMove(pieceAmount);
printf("%d",pieceAmount);
}
else if (smartCompOrDumb == 'd' || smartCompOrDumb == 'D')
{
playerTurn = true;
pieceAmount = dumbCompMove(pieceAmount);
printf("%d",pieceAmount);
}
}
else
{
if(pieceAmount <= 4)
{
printf("\nYou have won :) ");
gameOver = true;
exit(0);
}
playerTurn = false;
pieceAmount = PlayerTurn(pieceAmount);
printf("%d",pieceAmount);
}
}
return 0;
}
void printInstructions()
{
printf("\nThis game is called Nim and it is thousands of years old.");
printf("\nTake turns picking one to three pieces from a pile and whomever picks the last piece wins.");
printf("\n__________________________________________________________________________________________");
}
int randomRange(int low,int high)
{
return rand()% (high - low) + low;
}
int PlayerTurn(int pieceAmount)
{
pieceAmount = getUserInput(pieceAmount);
return pieceAmount;
}
int getUserInput(int pieceAmount)
{
int userInput = 0;
bool flag = true;
while (flag == true)
{
if (pieceAmount > 4)
{
printf("\nThere are %d pieces remaining.\n",pieceAmount);
printf("\nHow many pieces do you want to select? ");
scanf("%d", &userInput);
if (userInput >= 1 && userInput < 5)
{
pieceAmount = pieceAmount - userInput;
flag = false;
}
else
{
printf("This is not a valid move so try again.");
}
}
}
return pieceAmount;
}
int dumbCompMove(int pieceAmount)
{
int dumbPick = rand() % 3 + 1;
printf("\nComputer will pick from the stack. \n");
pieceAmount = pieceAmount - dumbPick;
printf("\nComputer picked %d pieces. \n", dumbPick );
return pieceAmount;
}
int smartCompMove(int pieceAmount)
{
int smartPick = 1;
printf("\nThe computer will select their pieces. \n");
if (pieceAmount >= 15 && pieceAmount < 24)
{
smartPick = 2;
pieceAmount = pieceAmount - smartPick;
}
else if (pieceAmount >= 10 && pieceAmount < 15)
{
smartPick = 4;
pieceAmount = pieceAmount - smartPick;
}
else if (pieceAmount >= 6 && pieceAmount < 10)
{
smartPick = 1;
pieceAmount = pieceAmount -smartPick;
}
else
pieceAmount = 3;
printf("\nThe computer selected %d pieces. \n",smartPick);
return pieceAmount;
}
I had this code working earlier yet somehow I must have altered something minor and now it will not function properly. I am using the Cloud9 program to run it.

Code seems to continue running after return statement (in C)

I am trying to create a binary search algorithm and have used two sets of if statements for when the sample is even/uneven. The uneven side currently works as planned and returns true, the even side returns true but then goes to the "catch all" piece of code at the bottom of the function and returns false:
bool search(int value, int values[], int n)
{
//searching algorithm
if (n <= 0)
{
return false;
}
//searching algorithm where n is even, if b is not the searched for value, split the sample and run recursively until value is equal to b or n<=0
if (n % 2 == 0)
{
int starte = n / 2;
eprintf("starte is %i", starte);
int startpluse = starte + 1;
int b = values[starte];
eprintf("b is %i", b);
//for (int i=0; i<n; i++){
//printf("%i,",values[i]);}
if (b == value)
{
printf("true\n");
return true;
}
else
{
if (value > b)
{
int o = starte - 1;
int searcharrayc[o];
for (int h = startpluse, l = 0; l < o; h++, l++)
{
searcharrayc[l] = values[h];
}
search(value, searcharrayc, o);
}
if (value < b)
{
int searcharrayd[starte];
for (int m = 0; m < starte; m++)
{
searcharrayd[m] = values[m];
}
search(value, searcharrayd, starte);
}
}
}
//searching algorithm where n is uneven, if a is not the searched for value, split the sample and run recursively until a is equal to the value or n<=0
if (n % 2 == 1)
{
eprintf("n is %i", n);
int start = (n / 2) - 0.5;
int startplus = start + 1;
int a = values[start];
eprintf("a is %i", a);
if (a == value)
{
return true;
}
else
{
if (value > a)
{
int searcharray[start];
for (int i = startplus, j = 0; j < start; i++, j++)
{
searcharray[j] = values[i];
eprintf("i is %i", i);
}
search(value, searcharray, start);
}
if (value < a)
{
int searcharrayb[start];
for (int k = 0; k < start; k++)
{
searcharrayb[k] = values[k];
eprintf("k is %i", k);
}
search(value, searcharrayb, start);
}
}
}
return false;
}
Your code looks like this:
search(...)
{
if(cond)
return false
if(cond)
return true
else
search(...)
return false
}
You need to change it to:
search(...)
{
if(cond)
return false
if(cond)
return true
else
return search(...)
}
Note the extra return before the recursive call to search

scanf doesn't work (integer)

When I execute my code, scanf("%d", &n); don't scan anything, I mean, if I introduce any number it doesn't do anything, regardless of the numbers I introduce.
void testEsPrimo() {
int n;
printf("Comprobando si un número es o no primo\n");
printf("Teclee un número entero: ");
fflush(stdout);
scanf("%d", &n); //<---- The problem ?
if(esPrimo(n) == cierto){
printf("%d es primo\n", n);
}else{
printf("%d NO es primo\n", n);
}
fflush(stdout);
}
Logico esPrimo(int n){
int divisor;
int esPrimox;
for(divisor = 2; sqrt(n); divisor++) {
if(n <= 0) {
return falso;
} else {
if(n%divisor == 0) {
esPrimox = 0;
} else {
esPrimox =1;
}
}
}
if(esPrimox == 1) {
return cierto;
}
return falso;
}
This is my esPrimo code that is about decide if a number is prime or not.
typedef enum {falso, cierto} Logico;
and this is Logico, defined in a .h file
PD: This are my first steps on C so my code might be bad.
PD2: Excuse me for my bad English I'm not native and my English isn't really good.
Your scanf is perfect.
I think that your mistake is the loop for from esPrimo. Actually you have an infinite loop, because sqrt(n) has always the same value and it isn't a boolean expression.
Change your loop:
for(divisor = 2; sqrt(n); divisor++) {
if(n <= 0) {
return falso;
} else {
if(n%divisor == 0) {
esPrimox = 0;
} else {
esPrimox =1;
}
}
}
for this:
for(divisor = 2; divisor < sqrt(n); divisor++) {
if(n <= 0) {
return falso;
} else {
if(n%divisor == 0) {
esPrimox = 0;
} else {
esPrimox =1;
}
}
}
But then you have a problem when you know that your number is not prime: you have to finish the loop.
You can do this:
for(divisor = 2; divisor < sqrt(n); divisor++) {
if(n <= 0) {
return falso;
} else {
if(n%divisor == 0) {
esPrimox = 0;
} else {
esPrimox =1;
break;
}
}
}
But if you can avoid using breakinside a loop for, don't use that.
With complicated algorithms you have a clean code with that, but when you read a loop for, usually your understand that the loop do a exactly number of iterations. If you have another flag to end the loop, use while.
While (divisor < sqrt(n) && esPrimox == 0){
if(n <= 0) {
return falso;
} else {
if(n%divisor == 0) {
esPrimox = 0;
} else {
esPrimox =1;
}
}
}
There are 2 main problems in esPrimo.
First, the for loop will not terminate:
for(divisor = 2; sqrt(n); divisor++) {
Change the condition to:
for(divisor = 2; divisor <= sqrt(n); divisor++) {
Second is in the logic. If you find that n is not a prime, you need to break the loop or the function will always return true. You could do it either with the break statement or by checking the value of esPrimox in the loop condition.
Here's how to do it using break:
for(divisor = 2; divisor <= sqrt(n); divisor++) { /* fixed loop condition */
if(n <= 0) {
return falso;
} else {
if(n%divisor == 0) {
esPrimox = 0;
break; /* break the loop */
} else {
esPrimox =1;
}
}
}

Hanoi Towers non-recursive wrong steps

I have to write a program that will solve the hanoi towers.
I have 3 columns, A-B-C and all the discs will have to be on the B column as the result. I have to write out the steps that each disc performs and in what order.
I tried to write it on my own, it works to some extent.
Some problems are:
The numbers are not written out correctly, at the n-j it should
calculate the n-j but it's always 1, but it shouldn't be.
The steps that the program performs are good only to some extent,
for example the last 3 or 4 steps are always wrong.
What did I write incorrectly?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main() {
int n,i,j,k,first_pos,last_pos,num_ofsteps,num;
char first_peg,next_peg;
printf("Enter the number of disks: ");
scanf("%d",&n);
int a[n];
for (i=0;i<n;++i) {
a[i]=0;
}
num_ofsteps = pow(2,n);
first_pos = 0;
last_pos = n-1;
for (i=0;i<num_ofsteps-1;++i) {
if (i%2==0) {
if (a[n-1]==0) {
a[n-1] = 1;
printf("1 steps: A->B\n");
} else if (a[n-1]==1) {
a[n-1] = 2;
printf("1 steps: B->C\n");
} else if (a[n-1]==2) {
a[n-1] = 0;
printf("1 steps: C->A\n");
}
} else {
for (j=n-1;j>=0;--j) {
if (a[j]!=a[j-1]) {
if ((a[j]==0 && a[j-1]==1) || (a[j]==1 && a[j-1]==0)) {
next_peg = 'C';
} else if ((a[j]==1 && a[j-1]==2) || (a[j]==2 && a[j-1]==1)) {
next_peg = 'A';
} else if ((a[j]==0 && a[j-1]==2) || (a[j]==2 && a[j-1]==0)) {
next_peg = 'B';
}
num=n-j;
if (a[j-1]==0) {
first_peg = 'A';
a[j-1] = 1;
printf("%d steps: %c->%c\n",num,first_peg,next_peg);
break;
} else if (a[j-1]==1) {
first_peg = 'B';
a[j-1] = 2;
printf("%d steps: %c->%c\n",num,first_peg,next_peg);
break;
} else if (a[j-1]==2) {
first_peg = 'C';
a[j-1] = 0;
printf("%d steps: %c->%c\n",num,first_peg,next_peg);
break;
}
}
}
}
}
return 0;
}

Resources