Saturday 25 May 2013

Let Us C: Matchstick Game

There is an exercise in Let us C, Chapter 3, Question C-f

Write a program for a matchstick game being played between the computer and a user.
Your program should ensure that the computer always wins. Rules for the game are as follows:

- There are 21 matchsticks.
- The computer asks the player to pick 1, 2, 3 or 4 matchsticks.
- After the person picks, the computer does its picking.
- Whoever is forced to pick up the last matchstick loses the game.

This is what I came up with. I know it is a lot of stuff for a simple question, but I enjoy tweaking stuff trying it make it a bit more 'joy giving' to me :D. I couldn't figure out my own program :O so i decided to sit down and comment it line by line, and as I'd hoped it reminded me how it does what it does.

The logic here is this:
Since the player always goes first, you must remove enough so that the sum of what you removed and the player removed is 5.
Player removes 4, you remove 1.
Player removes 3, you remove 2.
Player removes 2, you remove 3.
Player removes 1, you remove 4.

Following this simple rule, you always win.
If I remember correctly, I read in a book that this was a stunt that famed British TV Magician Paul Daniels used in his TV shows. He would do it with candy. Whoever had to pick up the last candy had to forfeit all his/her candy to the other (The winner was always the magician).

It looks very messy when pasted and posted here. Copy and paste the code into Code Blocks, it should look better. I tried it, and it looks just as it did originally & is a lot easier to comprehend.
Here is the code:



#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <conio.h>
#define TRUE 1
#define FALSE !TRUE

int rmd=21,x,rmv,y=244,z=0,a,state,turns; //A. global variables are declared. rmd=21(number of matchsticks),x for loops,
                                            //rmv for number of sticks removed,y=244 for the matchstick ASCII character
                                            //z=0 for calculating win (see 15), a to calculate the number of sticks
                                            //the program will remove,state for TRUE FALSE loops,turns to store
                                            //number of turns taken

unsigned t;                             //B. t for pause loops. It stores upto 500 mil hence unsigned
void match1(void);      //1. this function processes user input
void match2(void);      //2. processes program output.
void SetColorAndBackground(int ForgC,int BackC);   //3. small function for colours.

main()
{
    do  //4. do this till there is only one matchstick remaining(variable rmd) see 14.
    {
        SetColorAndBackground(10,0); //5. text is set to green (10) and background remains at 0(black)
        state=TRUE;                    //6. This is required in function match1() later in the program
        system("cls");                 //7. Clears the screen using DOS cls command
        printf("Assume these are 21 matchsticks. Please remove 1 to 4 stick/s\n");
        printf("and I will do the same. The person who has to pick the last stick loses.\n");
        printf("\nStick/s Left %i \tTurns taken %i\n\n\n",rmd,turns);   //8. shows sticks left and turns taken rmd,turns

        for(x=0;x<rmd;x++)                  //9. prints the number of sticks remaining to the screen,
        {
            SetColorAndBackground(6,0);     //10. colour of the sticks is set to yellow(6)
            printf("%c\t",y);               //11. y has been declared as 244. This will print its ASCII character.
        }
        match1();   //12. Processes user input
        match2();      //13. processes program output.
    }

    while(rmd>1); //14. above 'do' runs till this condition is met

    z=z%2;         //15. when condition is met number of turns taken is divided by 2,
                    //if it is divisible(IE remainder will be zero stored in z)
                    //it was an even number of turns with one match remaining. Means the computer won
    if(z==0)    //16. The computer won.
    {
        SetColorAndBackground(10,0); //17. text colour is set to green again because it
                                        //has been set to yellow when printing the matchsticks (see 17.5)
        system("cls");
        printf("Assume these are 21 matchsticks. Please remove 1 to 4 stick/s\n");
        printf("and I will do the same. The person who has to pick the last stick loses.\n");
        printf("\nStick/s Left %i \tTurns taken %i\n\n\n",rmd,turns);

        for(x=0;x<rmd;x++)
        {
            SetColorAndBackground(6,0);         //17.5 Look here
            printf("%c\t",y);
        }
        SetColorAndBackground(12,0);    //18. The ending note is displayed in red(12)
        printf("\n\n\n\aYou lose. *NOTE* This game cannot be beaten. It was designed that way."); // 19. \a makes the computer beep
                                                                                                    //when the end note is displayed.
    }
    else                            //20. This part of the program is put here as a courtesy.
                                        //It will never run because the user will never win.
    {
        SetColorAndBackground(10,0);
        system("cls");
        printf("Assume these are 21 matchsticks. Please remove 1 to 4 stick/s\n");
        printf("and I will do the same. The person who has to pick the last stick loses.\n");
        printf("\nStick/s Left %i \tTurns taken %i\n\n\n",rmd,turns);

        for(x=0;x<rmd;x++)
        {
            SetColorAndBackground(6,0);
            printf("%c\t",y);
        }
        SetColorAndBackground(12,0);
        printf("\a\n\n\nYou Win!");
    }
}

void match1(void)                   //function to process user input
{
    SetColorAndBackground(10,0);       //text colour green (10)
    if(z==2 || z==4)                    //if number of turns is 2 or 4 a newline character is introduced
                                        //to prevent the prompt from appearing to go up one line as the
                                        //matchsticks dissapear
        {
            printf("\n");
        }
    else if(z==6)                       //if turns = 6 2 newlines are introduced for same reason as above.
        {
            printf("\n\n");
        }
    printf("\n\n\nPlease enter number of stick/s to remove: ");
    while(state)                    //Start of loop for user input
    {
        scanf(" %i",&rmv);          //scans user input
        if(rmv>=1 && rmv <=4)       //If users input is valid IE 1,2,3 or 4
        {
            state=FALSE;            //state is set to false and loop breaks
        }
        else                        //If users input is invalid
        {
            printf("You may only remove 1,2,3 or 4 sticks: ");
        }
    }
    printf("\nYou remove %i stick/s.",rmv); //shows user how many sticks s/he removed
    a=5-rmv;                                //a is the number of sticks the program will remove. We want the number of
                                            //sticks removed to always be 5 so that the program never loses.
    rmd=rmd-rmv;                            //rmd(remainder) stores the number of matchsticks remaining.
    z++;                                    //z(number of turns taken) is incremented by 1. We need this variable
                                            //even if we also store the number of turns in the 'turns' variable.
                                            //We need it to decide who won. See 15
}
void match2(void)
{
    printf("\t\tThe Computer removes: ");
    for(t=0;t<500000000;t++);               //computer counts to 500 million to provide a pause of about 1 second.
    printf(" %i stick/s",a);                //computer removes a to equal the # of sticks removed to 5
    rmd=rmd-a;                              //remainder of sticks is updated.
    for(t=0;t<500000000;t++);               //another pause so user sees what the program removed.
    z++;                                    //z(number of turns taken) is incremented by 1
    turns=z;                                //'turns' number of turns taken gets its value from z
                                            //since we will be using z to modolus the win. See 15.
}

void SetColorAndBackground(int ForgC, int BackC)    //small function for colours.
{
     WORD wColor=((BackC&0x0F)<<4)+(ForgC&0x0F);
     SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),wColor);
     return;
}



This uses the function for colours that I mentioned in my previous post. Besides that everything else is what I learnt from C For Dummies.



No comments:

Post a Comment