Quick actions

cmd+k|ctrl+k

Navigation

Languages

XO rewrite

Snippet info

Language

C

Visibility

public

Author

mrsimb

Created

2017-04-10T16:58:57Z

Updated

2017-05-31T10:49:44Z

//---------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>

/*
  если один из игроков заполнил всю горизонталь / вертикаль / диагональ,
  возвращает символ, которым он играет

  если никто еще на заполнил линию, возвращает пробел
*/
int check(int** field, int size) {
  // итераторы
  int i, j;
  // первый символ по горизонтали и первый по вертикали
  int g, v;
  // диагонали
  int d1, d2;

  // начинается цикл в n заходов, n равно размеру поля
  for (i = 0; i < size; i++) {
    // ПРОВЕРКА ПО ГОРИЗОНТАЛИ
    // запоминаем символ из начала i строки поля
    g = field[i][0];

    // проходимся по i строке поля
    for (j = 0; j < size; j++) {
      // если натенемся на несовпадение с первым символом
      // или если первый символ был пробелом, то
      if (field[i][j] != g || g == ' ') {
        // забиваем на проверку, записываем в g символ ' '
        g = ' ';
        // и выходим цикла принудительно
        break;
      }
    }

    // если в g хранится символ, отличный от пробела, это значит что в начале
    // строки был крестик или нолик, и проходя по всей строке (в цикле выше)
    // мы не наткнулись на символ, отличающийся от того, что в начале
    // иными словами, один из игроков заполнил всю строку одним символом
    // и выйграл
    if (g != ' ') {
      // если это условие выполнено, просто возвращаем символ, которым
      // заполнена вся строка
      return g;
    }

    // ПРОВЕРКА ПО ВЕРТИКАЛИ
    // записываем символ из начала i столбца поля
    v = field[0][i];

    // проходим по i столбцу
    for (j = 0; j < size; j++) {
      // если натенемся на несовпадение с первым символом
      // или если первый символ был пробелом, то
      if (field[j][i] != v || v == ' ') {
        // забиваем на проверку, записываем в v символ ' '
        v = ' ';
        // и выходим цикла принудительно
        break;
      }
    }

    // если в v хранится символ, отличный от пробела, это значит что в начале
    // строки был крестик или нолик, и проходя по всей строке (в цикле выше)
    // мы не наткнулись на символ, отличающийся от того, что в начале
    // иными словами, один из игроков заполнил всю строку одним символом
    // и выйграл
    if (v != ' ') {
      // в таком случае возвращаем этот символ
      // это означает, что игрок с этим символом выйграл
      return v;
    }
  }

  // Записываем, какие символы в начале основной и побочной диагонали
  d1 = field[0][0];
  d2 = field[0][size - 1];

  // проверка по основной диагонали
  // ?##
  // #?#
  // ##?
  for (i = 0; i < size; i++) {
    // если наткнемся на несовпадение
    if (field[i][i] != d1) {
      // забиваем на проверку, записываем в d1 символ ' '
      d1 = ' ';
      // принудительно выходим их цикла
      break;
    }
  }

  // если все знаки на диагонали одинаковые, и знак не пробел, возвращаем знак
  if (d1 != ' ') {
    return d1;
  }

  // проверка по побочной диагонали
  // ##?
  // #?#
  // ?##
  for (i = 0; i < size; i++) {
    // если наткнемся на несовпадение
    if (field[i][size - 1 - i] != d2) {
      // забиваем на проверку, записываем в d1 символ ' '
      d2 = ' ';
      // принудительно выходим их цикла
      break;
    }
  }

  // если все знаки на диагонали одинаковые, и знак не пробел, возвращаем знак
  if (d2 != ' ') {
    return d2;
  }

  // если ни одна из полос не заполнена, возвращаем пробел
  return ' ';
}

// вывод поля
void out(int** field, int size) {
  int i, j;

  // очистка экрана
  system("cls");

  // верхняя граница поля
  for (j = 0; j < size; j++) {
    printf("--");
  }
  printf("-\n");

  // выводим по очереди все ряды и деления
  for (i = 0; i < size; i++) {

    // ряд символов
    for (j = 0; j < size; j++) {
      printf("|%c", field[i][j]);
    }
    printf("|\n");

    // деление
    for (j = 0; j < size; j++) {
      printf("--");
    }
    printf("-\n");
  }
}

int main() {
  // поле (массив массивов), размер
  int **field;
  int size;

  // текущий игрок
  int player = 'x';

  // результат проверки игрового поля на заполнение полосы
  int result;

  // индикатор работы игры
  int running = 1;

  // итераторы
  int i, j;

  // вводим размер поля
  printf("Enter field size: ");
  scanf("%i", &size);

  // выделяем память под массив из size указателей на массивы
  // (читай size строк)
  field = malloc(size * sizeof(int*));

  // заполняем массив указателей указателями на новые массивы
  // (читай size ячеек в каждой строке)
  for (i = 0; i < size; i++) {
    field[i] = malloc(size * sizeof(int));

    // заполняем каждую ячейку пробелом
    for (j = 0; j < size; j++)
      field[i][j] = ' ';
  }

  // пока игра продолжается
  while (running) {
    do {
      // выводим поле
      out(field, size);

      // выводим чей ход
      if (player == 'x') {
        printf("x turn\n");
      } else {
        printf("o turn\n");
      }

      // вводим координаты хода (от 1 до size)
      printf("Type x y (separated by space): ");
      scanf("%d %d", &i, &j);

      // если пользователь введет что-то неправильно, цикл продолжается
      // и спрашивает заново
      // как только игрок введет координаты правильно, цикл остановится
    } while(i > size || j > size || i < 0 || j < 0 || field[i - 1][j - 1] != ' ');

    // зачеркиваем ячейку поля
    field[i - 1][j - 1] = player;

    // проверяем поле
    result = check(field, size);

    // если result не пробел, значит кто-то выйграл
    if (result != ' ') {
      // выводим символ победителя (хранится в result)
      printf("%c wins!", result);

      // останавливаем игру
      running = 0;
    }

    // передаем ход другому игроку
    if (player == 'x') {
      player = 'o';
    } else {
      player = 'x';
    }
  }

  return 0;
}
INFO