diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 358 |
1 files changed, 358 insertions, 0 deletions
@@ -0,0 +1,358 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <termios.h> +#include <unistd.h> +#include <string.h> +#include <time.h> + +#define clear() printf("\033[H\033[J") +//the board as a 1D array. It's global due to the want to easily access in from any function. +char board[] ={"|---|---|---|\n| - | - | - |\n|---|---|---|\n| - | - | - |\n|---|---|---|\n| - | - | - |\n|---|---|---|\n"}; +struct termios oldt,newt;//the struct used by the terminal mode changer. Global due to want of easy access from any function. +int pos[3][3] = + { + {16,20,24}, + {44,48,52}, + {72,76,80} + }; //each number matches up to the position where the pieces should go on the board + +int moves = 0; //the amount of moves done by the computer. + +void checkWin(void)//check if the board is currently in a winning state +{ +//leftright +int x; +int y; +int Xcount = 0; +int Ocount = 0; +for (x=0;x<3;++x) + { + for (y=0;y<3;++y) + { + if(board[pos[x][y]] == 'X'){++Xcount;} + if(board[pos[x][y]] == 'O'){++Ocount;} + if (Xcount == 3){goto Xwin;} + if (Ocount == 3){goto Owin;} + } + Xcount = 0; + Ocount = 0; + } + +//up/down +for (x=0;x<3;++x) + { + for (y=0;y<3;++y) + { + if(board[pos[y][x]] == 'X'){++Xcount;} + if(board[pos[y][x]] == 'O'){++Ocount;} + if (Xcount == 3){goto Xwin;} + if (Ocount == 3){goto Owin;} + } + Xcount = 0; + Ocount = 0; + } + +//across topleft-bottomright +if ((board[pos[0][0]] == 'X') && (board[pos[1][1]] == 'X') && (board[pos[2][2]] == 'X') ){goto Xwin;} +if ((board[pos[0][0]] == 'O') && (board[pos[1][1]] == 'O') && (board[pos[2][2]] == 'O') ){goto Owin;} + +//across bottomleft-topright +if ((board[pos[2][0]] == 'X') && (board[pos[1][1]] == 'X') && (board[pos[0][2]] == 'X') ){goto Xwin;} +if ((board[pos[2][0]] == 'O') && (board[pos[1][1]] == 'O') && (board[pos[0][2]] == 'O') ){goto Owin;} + + + + + +goto skip;//Skip over the winning exit code + +//exit here due to lack of want to exit 2(?) layers deep of loops +Xwin: printf("Pathetic.\n"); tcsetattr( STDIN_FILENO, TCSANOW, &oldt ); exit(0); //return the terminal back to it's old state and exit +Owin: printf("You win! (Good job)\n"); tcsetattr( STDIN_FILENO, TCSANOW, &oldt ); exit(0); //return the terminal back to it's old state and exit + +skip:; +} + + + + + +void otherPlayer(void)//The other player takes a move when this function is called. +{ +int x; +int y; +bool tie = true; +for (x=0;x<3;++x) + { + for (y=0;y<3;++y) + { + if (board[pos[x][y]] == '-'){tie = false;} + } + } + +if (tie){printf("It's a tie. \n"); tcsetattr(STDIN_FILENO,TCSANOW,&oldt); exit(0);} + +//if it's the second turn, there are a limited amount of moves to make +if (!moves) + { + if (board[pos[1][1]] == 'O')//if first move was center, a move in the 4 non-diaginal places should be made + { + int randNum = rand() % 4;//generate a pseudorandom number from 0 to 3. + switch(randNum) + { + case 0: + board[pos[0][0]] = 'X'; + goto skip; + case 1: + board[pos[2][0]] = 'X'; + goto skip; + case 2: + board[pos[0][2]] = 'X'; + goto skip; + case 3: + board[pos[2][2]] = 'X'; + goto skip; + } + } + + //if the player placed anywhere else, place in the center + board[pos[1][1]] = 'X'; + goto skip; + + } + + +//leftright +int Xcount = 0; +for (x=0;x<3;++x) + { + for (y=0;y<3;++y) + { + if(board[pos[x][y]] == 'X'){++Xcount;} + if ((Xcount == 2)&&(board[pos[x][y+1]] == '-')){board[pos[x][y+1]] = 'X'; goto skip;} + } + Xcount = 0; + } + +//up/down +for (x=0;x<3;++x) + { + for (y=0;y<3;++y) + { + if(board[pos[y][x]] == 'X'){++Xcount;} + if ((Xcount == 2)&&(board[pos[x+1][y]] == '-')){board[pos[x+1][y]] = 'X'; goto skip;} + } + Xcount = 0; + } + +//across topleft-bottomright +if ((board[pos[0][0]] == 'X') && (board[pos[1][1]] == 'X') && (board[pos[2][2]] == '-') ){board[pos[2][2]] = 'X'; goto skip;} +if ((board[pos[0][0]] == '-') && (board[pos[1][1]] == 'X') && (board[pos[2][2]] == 'X') ){board[pos[0][0]] = 'X'; goto skip;} + +//across bottomleft-topright +if ((board[pos[2][0]] == '-') && (board[pos[1][1]] == 'X') && (board[pos[0][2]] == 'X') ){board[pos[2][0]] = 'X'; goto skip;} +if ((board[pos[2][0]] == 'X') && (board[pos[1][1]] == 'X') && (board[pos[0][2]] == '-') ){board[pos[0][2]] = 'X'; goto skip;} + + + +//copy the position of O's into an array for later processing +bool Ostate[3][3]; +for (x=0;x<3;++x) + { + for (y=0;y<3;++y) + { + if (board[pos[x][y]] == 'O'){Ostate[x][y] = true;} + else {Ostate[x][y] = false;} + } + } + +bool Nstate[3][3]; //state is empty +for (x=0;x<3;++x) + { + for (y=0;y<3;++y) + { + if (board[pos[x][y]] == '-'){Nstate[x][y] = true;} + else {Nstate[x][y] = false;} + } + } + + + +//check for double moves including the center piece +if (Ostate[1][1]) + { + int x; + int y; + int newx; + int newy; + for (x=0;x<3;++x) + { + for (y=0;y<3;++y) + { + if (Ostate[x][y]) + { + //calculate move by applying these rules; if (x == 0){x=2;} if (x == 1){x=1;} if (x == 2){x=0;} + if (!x){newx=2;} + if (x==1){newx=1;} + if (x==2){newx=0;} + if (!y){newy=2;} + if (y==1){newy=1;} + if (y==2){newy=0;} + if (board[pos[newx][newy]] == '-'){board[pos[newx][newy]] = 'X'; goto skip;} + } + } + } + + } + +//check for double moves including gap in space +if ((Ostate[0][0])&&(Ostate[0][2])&&(Nstate[0][1])){board[pos[0][1]] = 'X'; goto skip;} +if ((Ostate[0][2])&&(Ostate[2][2])&&(Nstate[1][2])){board[pos[1][2]] = 'X'; goto skip;} +if ((Ostate[2][2])&&(Ostate[2][0])&&(Nstate[2][1])){board[pos[2][1]] = 'X'; goto skip;} +if ((Ostate[2][0])&&(Ostate[0][0])&&(Nstate[1][0])){board[pos[1][0]] = 'X'; goto skip;} + +//check for double moves not including center diagonally and vertically +//top row +if ((Ostate[0][0])&&(Ostate[0][1])&&(Nstate[0][2])){board[pos[0][2]] = 'X'; goto skip;} +if ((Ostate[0][2])&&(Ostate[0][1])&&(Nstate[0][0])){board[pos[0][0]] = 'X'; goto skip;} + +//right down +if ((Ostate[0][2])&&(Ostate[1][2])&&(Nstate[2][2])){board[pos[2][2]] = 'X'; goto skip;} +if ((Ostate[2][2])&&(Ostate[1][2])&&(Nstate[0][2])){board[pos[0][2]] = 'X'; goto skip;} + +//bottom row +if ((Ostate[2][0])&&(Ostate[2][1])&&(Nstate[2][2])){board[pos[2][2]] = 'X'; goto skip;} +if ((Ostate[2][2])&&(Ostate[2][1])&&(Nstate[2][0])){board[pos[2][0]] = 'X'; goto skip;} + +//left down +if ((Ostate[2][0])&&(Ostate[1][0])&&(Nstate[0][0])){board[pos[0][0]] = 'X'; goto skip;} +if ((Ostate[0][0])&&(Ostate[1][0])&&(Nstate[2][0])){board[pos[2][0]] = 'X'; goto skip;} + +//if all above was passed, just peform a random move +redo: x = rand() % 4;//generate a pseudorandom number from 0 to 3. +y = rand() % 4;//ditto +if (board[pos[x][y]] == '-'){board[pos[x][y]] = 'X';} +else{goto redo;}//generate random numbers again if the space wasn't free + +skip: clear();//clear the terminal + printf("%s", board);//print the new board + ++moves; + +} + + + + +int main(int argc, char *argv[]) +{ +if (argc > 1) +{ +printf("Usage: %s\n\n", argv[0]); +printf("Controls:\nArrow keys to move cursor.\nPress any other key to take a move.\n\n"); +printf("I am aware that this is badly written.\n"); +exit(0); +} + +srand(time(NULL));//seed a srandom number generator very poorly with the time(should only be done once) +//modified is simply a copy of the board with the cursor written on it +char modified[] = +{ +"|---|---|---|\n| - | - | - |\n|---|---|---|\n| - | - | - |\n|---|---|---|\n| - | - | - |\n|---|---|---|\n" +}; + +char c;//char used to recieve user input +tcgetattr(STDIN_FILENO, &oldt);//get the current state of the terminal +newt = oldt;//set the new state to the old state +newt.c_lflag &= ~( ICANON | ECHO );//disable ICANON and ECHO +tcsetattr(STDIN_FILENO,TCSANOW,&newt);//set the terminal to the new state + +int cursor = 48;//the position of the cursor on the board(default is the center) +modified[cursor] = '#'; //Write the marker char to the current location of the cursor + +clear(); //clear the screen ready for the board +printf("%s", modified);//print board with marker on it + +while(1)//loop until a win or tie +{ +if (getchar() == '\033')//ingnore escape char in front the symbol used to carry arrow key presses + { + getchar();//ignore '[' + c = getchar();//Get th arrow state. + switch(c)//an arrow is pressed if 'A', 'B', 'C' or 'D' is recieved. + { + case 'A': + if (cursor-14 < 0){break;}//Don't try to go up if we are on the first row + cursor-=14;//move cursor to previous row + memcpy(modified,board,strlen(board)+1);//refresh modified with board + modified[cursor]='#';//write a marking char to the position of cursor + clear();//clear the screen + printf("%s", modified);//print the modified board + //printf("Up arrow\n"); + break; + + case 'B': + if (cursor+14 >= strlen(board)){break;}//If we are on the last row, don't increment further + cursor+=14;//move x to next row + memcpy(modified,board,strlen(board)+1);//refresh bord with a blank one + modified[cursor]='#';//write a marking char to the position + clear();//clear the screen + printf("%s", modified);//print the modified board + //printf("Down arrow\n"); + break; + case 'C': + if (cursor==(strlen(board+1))){break;}//don't go past the end of the board + ++cursor;//move cursor right + if ((board[cursor]) == '\n'){--cursor; break;}//If going right will lead to a newline, don't + memcpy(modified,board,strlen(board)+1);//refresh board with the default + modified[cursor]='#';//write a marking char to the position + clear();//clear the screen + printf("%s", modified);//print the modified board + //printf("Right arrow\n"); + break; + case 'D': + if (cursor-1<0){break;}//don't attempt to go to -1 in board + --cursor;//move cursor left + if ((board[cursor]) == '\n'){++cursor; break;}//If going left will lead to a newline, don't + memcpy(modified,board,strlen(board)+1);//refresh board with the default + modified[cursor]='#';//write a marking char to the position + clear();//clear the screen + printf("%s", modified);//print the modified board + //printf("Left arrow\n"); + break; + default: + clear(); //to correct an issue where is seems that any key resulted in the last pressed arrow key direction, the board is cleared and reset. + printf("%s", modified); + break; + } + } +else //if any other key than an arrow key was pressed, we end up here + { + int x;//x cord. + int y;//y cord. + for(x=0;x<3;++x) + { + for(y=0;y<3;++y) + { + if (pos[x][y] == cursor){goto checkBoard;}//If cursor is the position of a valid move place, keep the value of x and y + } + } + goto noMove; //if the above goto doesn't trigger, cursor is not in a valid move place + + checkBoard: if (board[pos[x][y]] != '-'){goto noMove;}//move has already been made + + board[pos[x][y]] = 'O';//write an 'O' to the board. + modified[pos[x][y]] = 'O';//write that to the modified board too. + clear();//clear the terminal + printf("%s", modified);//print the modified board + checkWin();//check if the move made was a winning move. + otherPlayer();//make the CPU take a move + checkWin();//check if the CPU move made was a winning one. + noMove: ; + } +} + + +tcsetattr(STDIN_FILENO,TCSANOW,&oldt);//return the terminal back to it's old state, this should never be reached though. +return 1;//if we exit here, something has gone wrong +} |