How do I make this code shorter and more efficient? - c

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;
}

Related

making my CS50 solution more elegant and efficient

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.

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.

recursion sum of subsets keeping getting error message

I am working on this problem on this online judge site(http://zerojudge.tw/ShowProblem?problemid=a981#). Sorry for that it's only in Mandarin :(.Basically it's a sum-of-subsets-problem.
Keep getting same error message on my submit:
RE (SIGSEGV)
Segmentation fault
My C code below:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
int w[35]= {0};
bool is_included[35]= {false};
bool is_promising(int);
void sum_of_subsets(int,int,int);
int n = 0,W = 0,weight = 0,total = 0,i = 0,j = 0,k = 0,flag = 0,temp = 0;
int main(int argc,char* argv[]) {
while(scanf("%d %d",&n,&W)==2) {
memset(w,0,sizeof(w));
memset(is_included,false,sizeof(is_included));
total = 0;
i = 1;
temp = n;
while(temp--) {
scanf("%d",&w[i++]);
}
//ascending bubble sort
for(j = n; j >= 1; --j) {
flag=0;
for(k = 1; k < j; ++k) {
if(w[k]>w[k+1]) {
temp = w[k];
w[k] = w[k+1];
w[k+1] = temp;
flag=1;
}
}
if(!flag) {
break;
}
}
for(i=1; i<=n; ++i) {
total+=w[i];
}
sum_of_subsets(0,0,total);
}
return 0;
}
bool is_promising(int index) {
return (weight+total>=W)&&(weight==W||weight+w[index+1]<=W);
}
void sum_of_subsets(int index,int weight,int total) {
int j=1;
if(is_promising(index)) {
if(weight==W) {
for(j=1; j<=index; ++j) {
if(is_included[j]) {
printf("w[%d] = %d\n",j,w[j]);
}
}
} else {
//include w[index+1]
is_included[index+1]=true;
sum_of_subsets(index+1,weight+w[index+1],total-w[index+1]);
//exclude w[index+1]
is_included[index+1]=false;
sum_of_subsets(index+1,weight,total-w[index+1]);
}
}
}
Thanks for any advice.

exception in thread main java.lang.arrayindexoutofboundsexception 1

well i have to make a java program which determinate if a given number is capicua(131,12121,13431) the same number from last to initial digit. but it gives me the error, in the line 23 (while(i>=0).....) the question is how can i call the array into thath while. pls help me im really sad :c. Here is the code:
public class Capi {
/**
*
**/
public static int num(int a) { // counting digits from the number
int n = 0;
while(a>=10) { a = a/10;
n = n+1;
}
return n;
}
public static boolean det(int a, int n) {
int z = a;
double y =0;
n = n-1;
int i = 0;
int x[] = new int[n];
for(i=0; i<x.length; i++) { // saving the digits into x[i]
x[i] = a%10;
a = a/10;
}
while(i>=0) { y = x[i]*Math.pow(10,n-1); // calling the digits x[i],x[i-1] untill it gets 0
i = i - 1;
n = n -1;
}
double num1= y + a*Math.pow(10,n);
if(num1 == z) { return true; }
else { return false; }
}
}
I feel the issue is that the value of i is set to x.length, before you attempt while(i>=0). I have hence added i-- before you run the loop.
See if the following does the trick.
public class Capi {
public static int num(int a) { // counting digits from the number
int n = 0;
while(a>=10) {
a = a/10;
n = n+1;
}
return n;
}
public static boolean det(int a, int n) {
int z = a;
double y = 0;
n = n-1;
int i = 0;
int x[] = new int[n];
for(i=0; i<x.length; i++) { // saving the digits into x[i]
x[i] = a%10;
a = a/10;
}
//i is now set to x.length, thus decrement it as index runs from 0 to x.length-1
i=i-1;
while(i>=0) {
y = x[i]*Math.pow(10,n-1); // calling the digits x[i],x[i-1] untill it gets 0
i = i - 1;
n = n -1;
}
double num1= y + a*Math.pow(10,n);
if(num1 == z) {
return true;
}
else {
return false;
}
}
}

MiniMax TicTacToe doesn't work (c)

I have implemented a TicTacToe algorythm with MiniMax, but the problem is that the computer always just places an 'x' on the next possible spot instead of evaluating the game. Does anybody know why ? (The problem can only be in the MiniMax function, or the nextMove function.)
Thanks a lot in advance !!
Here's the code :
int MiniMax(struct Game g, enum Symbol pl){
int score;
if (pl==CROSS)
{
score = -98765;
}
else score = 98765;
int temp_cross =0;
int temp_circle =0;
//base case
if (game_over(g) == CROSS)
return 10;
else if (game_over(g) == CIRCLE)
return -10;
else if (game_over(g) == FULL)
return 0;
int x,y;
for (y=0; y<SIZE_Y_AXIS; y++)
{
for (x=0; x<SIZE_X_AXIS; x++)
{
if (g.board.fields[x][y] == NONE)
{
if (pl == CROSS)
g.board.fields[x][y] = CROSS;
else g.board.fields[x][y] = CIRCLE;
if (pl == CROSS)
temp_cross= MiniMax(g, CIRCLE);
else temp_circle = MiniMax(g, CROSS);
g.board.fields[x][y] = NONE;
if ((pl == CROSS) && (temp_cross > score))
score = temp_cross;
else if ((pl == CIRCLE) && (temp_circle < score))
score = temp_circle;
}
}
}
return score;
};
int nextMove(struct Game g, enum Symbol player){
int score_cross = -865435;
int score_cross_temp = 0;
int cross_position = 1;
int score_circle = 876545;
int score_circle_temp = 0;
int circle_position = 1;
int x,y;
for (y=0; y<SIZE_Y_AXIS; y++)
{
for (x=0; x<SIZE_X_AXIS; x++)
{
if (g.board.fields[x][y] == NONE)
{
if (player == CROSS)
{
score_cross_temp = MiniMax(g, CROSS);
printf("%d ",MiniMax(g, CROSS));
if (score_cross_temp > score_cross)
{
score_cross = score_cross_temp;
cross_position = (y)*3 + x+1;
}
}
else if (player == CIRCLE)
{
score_circle_temp = MiniMax(g, CIRCLE);
if (score_cross_temp < score_circle)
{
score_circle = score_circle_temp;
circle_position = (y)*3 + x+1;
}
}
}
}
}
if (player == CROSS)
{
//printf("%d",cross_position);
return cross_position;
}
else
{
//printf("%d",circle_position);
return circle_position;
}
};
I believe there is a bug in your code. You initialize score as 10, and the temp variables as arbitrarily high and low numbers. This is backwards. TempCircle and TempCross are being overwritten anyway my the calls to minimax. It is the score variable that must be set like that. replace
int score = 10;
int temp_cross = -9876543;
int temp_circle = 9876543;
with
int score;
if(pl==cross){
score = 9876543
}
else{
score = -9876543
}
int temp_cross;
int temp_circle;
There also seems to be another bug in your nextMove function. I assume that its purpose is to iterate over all possible moves, find the one with the highest minimax value, and return that move (correct me if I'm wrong). That is not what the function does. It iterates over all the moves, but does't make any of them. x and y are never even used, except to update the move. You are essentially calling the same minimax several times. Instead, I would either get rid of the function completely, as there is a way to do this inside the minimax function, or fix this function. To fix the function, I would change it to this:
int nextMove(struct Game g, enum Symbol player){
int score_cross = -865435;
int score_cross_temp = 0;
int cross_position = 1;
int score_circle = 876545;
int score_circle_temp = 0;
int circle_position = 1;
int x,y;
for (y=0; y<SIZE_Y_AXIS; y++)
{
for (x=0; x<SIZE_X_AXIS; x++)
{
if (g.board.fields[x][y] == NONE)
{
if (player == CROSS)
{
g.board.fields[x][y] = CROSS;
score_cross_temp = MiniMax(g, CIRCLE);
printf("%d ",MiniMax(g, CROSS));
g.board.fields[x][y] = NONE;
if (score_cross_temp > score_cross)
{
score_cross = score_cross_temp;
cross_position = (y)*3 + x+1;
}
}
else if (player == CIRCLE)
{
g.board.fields[x][y] = CIRCLE;
score_circle_temp = MiniMax(g, CROSS);
g.board.fields[x][y] = NONE;
if (score_cross_temp < score_circle)
{
score_circle = score_circle_temp;
circle_position = (y)*3 + x+1;
}
}
}
}
}
if (player == CROSS)
{
//printf("%d",cross_position);
return cross_position;
}
else
{
//printf("%d",circle_position);
return circle_position;
}
};
Or you can edit minimax to keep track of which call to the function it is. If it is the first recursive call (the root) , keep track of the move itself as well as its value. Then return the move.

Resources