Крестики-нолики: критика кода - C (СИ)
Формулировка задачи:
В качестве практики, написал консольные крестики-нолики. Хотелось бы услышать мнение опытных людей. Над чем стоит поработать? Что в коде "не так"?
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
struct coordinates{int x; int y;};
void manual()
{
printf("*******************************\n");
printf("W/S/A/D - choose cell\n");
printf("Space - put X/O\n");
printf("Esc - exit\n");
printf("*******************************\n");
printf("Press any key to start...\n");
}
void initCellCoordinates(struct coordinates *cellCoord, int index)
{
int i=0,cellX,cellY;
for(cellY=1;cellY<=17;cellY+=8)
{
for(cellX=1;cellX<=21;cellX+=10)
{
cellCoord[i].x=cellX;
cellCoord[i].y=cellY;
i++;
}
}
return;
}
void initMatrix(char *matrix, int y, int x)
{
int i,j;
for(i=0;i<x;i++)
{
for(j=0;j<y;j++)
{
*(matrix + i*y + j)='0';
}
}
return;
}
void initGrMatrix(char *matrix, int y, int x)
{
int i,j;
for(i=0;i<y;i++)
{
for(j=0;j<x;j++)
{
if(i==0 || i==8 || i==16 || i==24)
{
if(j==0 || j==10 || j==20 || j==30)
*(matrix + i*x + j)='+';
else *(matrix + i*x + j)= '-';
}
else if(j==0 || j==10 || j==20 || j==30)
*(matrix + i*x + j)='|';
else *(matrix + i*x + j) = ' ';
}
}
return;
}
void printMatrix(char *matrix, int y, int x)
{
int i,j;
for(i=0;i<y;i++)
{
for(j=0;j<x;j++)
{
printf("%c", *(matrix + i*x + j));
}
printf("\n");
}
return;
}
void moveFrame(char *matrix, int my, int mx, struct coordinates *frameCoord, struct coordinates *cellCoord, struct coordinates *lastFrameCoord)
{
*(matrix + cellCoord[frameCoord->y * 3 + frameCoord->x].y * mx + cellCoord[frameCoord->y * 3 + (frameCoord->x)].x)='#';
*(matrix + cellCoord[lastFrameCoord->y * 3 + lastFrameCoord->x].y * mx + cellCoord[lastFrameCoord->y * 3 + lastFrameCoord->x].x)=' ';
return;
}
void addPlayerSymbol(char *checkMatrix, char *grMatrix, int gmX, struct coordinates *frameCoord, struct coordinates *cellCoord, char *player, char *paternX, char *paternO)
{
int i,j;
switch(*player)
{
case 'X':
for(i=0;i<5;i++)
{
for(j=0;j<5;j++)
{
*(grMatrix + (cellCoord[frameCoord->y * 3 + frameCoord->x].y+1+i) * gmX + cellCoord[frameCoord->y * 3 + (frameCoord->x)].x+2+j) = *(paternX + i*5 + j);
}
}
return;
case 'O':
for(i=0;i<5;i++)
{
for(j=0;j<5;j++)
{
*(grMatrix + (cellCoord[frameCoord->y * 3 + frameCoord->x].y+1+i) * gmX + cellCoord[frameCoord->y * 3 + (frameCoord->x)].x+2+j) = *(paternO + i*5 + j);
}
}
return;
default:
return;
}
}
void changePlayer(char *player)
{
if((*player)=='X')
(*player)='O';
else
(*player)='X';
return;
}
int control(struct coordinates *frameCoord, struct coordinates *lastFrameCoord, char *checkMatrix,int cmY,int cmX, char *player, int *quit)
{
//return 0 - ничего не делать; return 1 - передвинуть #(frame); return 2 - ввести символ Х/О
switch(getch())
{
case 'w':
if(frameCoord->y > 0)
{
lastFrameCoord->x=frameCoord->x;
lastFrameCoord->y=frameCoord->y;
frameCoord->y--;
return 1;
}
else
return 0;
case 's':
if(frameCoord->y < 2)
{
lastFrameCoord->x=frameCoord->x;
lastFrameCoord->y=frameCoord->y;
frameCoord->y++;
return 1;
}
else
return 0;
case 'a':
if(frameCoord->x > 0)
{
lastFrameCoord->x=frameCoord->x;
lastFrameCoord->y=frameCoord->y;
frameCoord->x--;
return 1;
}
else
return 0;
case 'd':
if(frameCoord->x < 2)
{
lastFrameCoord->x=frameCoord->x;
lastFrameCoord->y=frameCoord->y;
frameCoord->x++;
return 1;
}
else
return 0;
case 32/*space*/:
if(*(checkMatrix + frameCoord->y * cmX + frameCoord->x)=='0')
{
*(checkMatrix + frameCoord->y * cmX + frameCoord->x)=*player;
return 2;
}
else
return 0;
case 27/*ESC*/:
*quit=1;
return;
}
}
int check(char *checkMatrix, int cmX, char *winner)
{
int i,j;
if(!(*(checkMatrix + 0*cmX + 0)=='0') && *(checkMatrix + 0*cmX + 0)==*(checkMatrix + 0*cmX + 1) && *(checkMatrix + 0*cmX + 0)==*(checkMatrix + 0*cmX + 2))//первая строчка(1)
{
*winner=*(checkMatrix + 0*cmX + 0);
return 1;
}
else if(!(*(checkMatrix + 1*cmX + 0)=='0') && *(checkMatrix + 1*cmX + 0)==*(checkMatrix + 1*cmX + 1) && *(checkMatrix + 1*cmX + 0)==*(checkMatrix + 1*cmX + 2))//вторая строчка(2)
{
*winner=*(checkMatrix + 1*cmX + 0);
return 2;
}
else if(!(*(checkMatrix + 2*cmX + 0)=='0') && *(checkMatrix + 2*cmX + 0)==*(checkMatrix + 2*cmX + 1) && *(checkMatrix + 2*cmX + 0)==*(checkMatrix + 2*cmX + 2))//третья строчка(3)
{
*winner=*(checkMatrix + 2*cmX + 0);
return 3;
}
else if(!(*(checkMatrix + 0*cmX + 0)=='0') && *(checkMatrix + 0*cmX + 0)==*(checkMatrix + 1*cmX + 0) && *(checkMatrix + 0*cmX + 0)==*(checkMatrix + 2*cmX + 0))//первый столбец(4)
{
*winner=*(checkMatrix + 0*cmX + 0);
return 4;
}
else if(!(*(checkMatrix + 0*cmX + 1)=='0') && *(checkMatrix + 0*cmX + 1)==*(checkMatrix + 1*cmX + 1) && *(checkMatrix + 0*cmX + 1)==*(checkMatrix + 2*cmX + 1))//второй столбец(5)
{
*winner=*(checkMatrix + 0*cmX + 1);
return 5;
}
else if(!(*(checkMatrix + 0*cmX + 2)=='0') && *(checkMatrix + 0*cmX + 2)==*(checkMatrix + 1*cmX + 2) && *(checkMatrix + 0*cmX + 2)==*(checkMatrix + 2*cmX + 2))//третий столбец(6)
{
*winner=*(checkMatrix + 0*cmX + 2);
return 6;
}
else if(!(*(checkMatrix + 0*cmX + 0)=='0') && *(checkMatrix + 0*cmX + 0)==*(checkMatrix + 1*cmX + 1) && *(checkMatrix + 0*cmX + 0)==*(checkMatrix + 2*cmX + 2))//первая диагональ(7)
{
*winner=*(checkMatrix + 0*cmX + 0);
return 7;
}
else if(!(*(checkMatrix + 2*cmX + 0)=='0') && *(checkMatrix + 2*cmX + 0)==*(checkMatrix + 1*cmX + 1) && *(checkMatrix + 2*cmX + 0)==*(checkMatrix + 0*cmX + 2))//вторая диагональ(8)
{
*winner=*(checkMatrix + 2*cmX + 0);
return 8;
}
else //если нет пустых клеток возвращать 9
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
if(*(checkMatrix + i*cmX + j)=='0')
return 0;
}
}
return 9;
}
void putWinLine(char *grMatrix, int gmX, int *winLine)
{
int i,j;
switch(*winLine)
{
case 1:
for(i=0;i<27;i++)
{
*(grMatrix + 4*gmX + 2+i)='o';
}
return;
case 2:
for(i=0;i<27;i++)
{
*(grMatrix + 12*gmX + 2+i)='o';
}
return;
case 3:
for(i=0;i<27;i++)
{
*(grMatrix + 20*gmX + 2+i)='o';
}
return;
case 4:
for(i=0;i<23;i++)
{
*(grMatrix + (i+1)*gmX + 5)='o';
}
return;
case 5:
for(i=0;i<23;i++)
{
*(grMatrix + (i+1)*gmX+ + 15)='o';
}
return;
case 6:
for(i=0;i<23;i++)
{
*(grMatrix + (i+1)*gmX+2 + 23)='o';
}
return;
}
}
void addWins(int *winsX, int *winsO, char *winner)
{
switch(*winner)
{
case 'X':
(*winsX)++;
(*winner)='0';
break;
case 'O':
(*winsO)++;
(*winner)='0';
break;
default:
(*winner)='0';
}
*winsX++;
return;
}
void printWins(int *winsX, int *winsO)
{
printf(" Wins\n");
printf(" X:%d O:%d\n", *winsX, *winsO);
printf("===============================\n");
return;
}
//******************************************************** Main **************************************************
void main()
{
system("mode con cols=32 lines=36");
system("title TicTacToe");
int winLine=0, quit=0, winsX=0, winsO=0;
struct coordinates frameCoord, lastFrameCoord, cellCoord[9];
char grMatrix[25][31],
checkMatrix[3][3],
player='X',
winner='0',
paternX[5][5]={
{'*',' ',' ',' ','*'},
{' ','*',' ','*',' '},
{' ',' ','*',' ',' '},
{' ','*',' ','*',' '},
{'*',' ',' ',' ','*'}
},
paternO[5][5]={
{' ','*','*','*',' '},
{'*',' ',' ',' ','*'},
{'*',' ',' ',' ','*'},
{'*',' ',' ',' ','*'},
{' ','*','*','*',' '}
};
initCellCoordinates(cellCoord, 9);
frameCoord.x=0;
frameCoord.y=0;
manual();
while(quit==0)
{
initGrMatrix(&grMatrix[0][0],25,31);
initMatrix(&checkMatrix[0][0],3,3);
getch();
grMatrix[cellCoord[frameCoord.y * 3 + frameCoord.x].y][cellCoord[frameCoord.y * 3 + (frameCoord.x)].x]='#';
system("cls");
printWins(&winsX, &winsO);
printMatrix(&grMatrix[0][0],25,31);
printf("===============================\n");
printf("Your move, %c.\n\n", player);
while(check(&checkMatrix[0][0], 3, &winner)==0)
{
switch(control(&frameCoord, &lastFrameCoord, &checkMatrix[0][0],3,3, &player, &quit))
{
case 1://передвинуть #
moveFrame(&grMatrix[0][0],25,31, &frameCoord, cellCoord, &lastFrameCoord);
system("cls");
printWins(&winsX, &winsO);
printMatrix(&grMatrix[0][0],25,31);
printf("===============================\n");
printf("Your move, %c.\n\n", player);
break;
case 2: //нарисовать Х/О
addPlayerSymbol(&checkMatrix[0][0], &grMatrix[0][0], 31, &frameCoord, cellCoord, &player, &paternX[0][0], &paternO[0][0]);
changePlayer(&player);
system("cls");
printWins(&winsX, &winsO);
printMatrix(&grMatrix[0][0],25,31);
printf("===============================\n");
printf("Your move, %c.\n\n", player);
break;
case 0:
break;
}
if(quit==1)
break;
}
winLine=check(&checkMatrix[0][0], 3, &winner);
putWinLine(&grMatrix[0][0], 31, &winLine);
system("cls");
printWins(&winsX, &winsO);
printMatrix(&grMatrix[0][0],25,31);
printf("===============================\n");
if(winLine!=9)
printf("Winner: %c\n", winner);
else
printf("No empty cells\n");
addWins(&winsX, &winsO, &winner);
printf("\n\n");
printf("Press any key to continue");
}
return;
}Решение задачи: «Крестики-нолики: критика кода»
textual
Листинг программы
#define MAX_Y 17 #define MAX_X 21 ... //etc