Opened 4 years ago
Closed 4 years ago
#694 closed ожидается проверка (задача сдана)
HW #2 (XO)
Reported by: | Surkov Petr | Owned by: | Sokolov Viacheslav |
---|---|---|---|
Component: | HW #2 (X0) | Version: | 3.0 |
Keywords: | Cc: |
Description
Change History (5)
comment:1 Changed 4 years ago by
Type: | ожидается проверка → ожидаются исправления |
---|
comment:2 Changed 4 years ago by
Type: | ожидаются исправления → ожидается проверка |
---|---|
Version: | 1.0 → 2.0 |
comment:3 Changed 4 years ago by
Type: | ожидается проверка → ожидаются исправления |
---|
Поскольку Player - enum class, можно просто Player::X, Player::O
13 const Position forceEndGamePos = {-1, -1};
static, можно constexpr
In_progress
не camelCase, не snake_case, какой это стиль?
кажется, silent - это все же свойство stdioview, а не gamecontroller (поскольку в режиме curses все нужно отрисовывать)
6 assert(!std::cin.fail());
можно же исключениями, и надежнее и код проще
ввод сейчас обрабатывается не так, как требуется по условию.
Примеры невалидных вводов:
1)
1
2
2)
1 2a
3)
0-0
невалидный ввод все же нужно ожидать от пользователя
comment:4 Changed 4 years ago by
Type: | ожидаются исправления → ожидается проверка |
---|---|
Version: | 2.0 → 3.0 |
Исправления были закоммичены давно (ещё в срок), забыл обновить тикет
comment:5 Changed 4 years ago by
Resolution: | → задача сдана |
---|---|
Status: | assigned → closed |
src/StdioBoardView.cpp: In member function ‘virtual void StdioBoardView::drawField(const std::vector<std::vector<CellContent> >&)’: src/StdioBoardView.cpp:38:34: error: catching polymorphic type ‘class std::ios_base::failure’ by value [-Werror=catch-value=] 38 | catch (std::ostream::failure e) { | ^ cc1plus: all warnings being treated as errors Makefile:28: recipe for target 'obj/StdioBoardView.o' failed make: *** [obj/StdioBoardView.o] Error 1
12 using std::vector;
в целом так лучше не далеть в заголовочном файле в global namespace
57 const Position Directions[4] = {{0, 1}, {1, 0}, {1, 1}, {-1, 1}};
static
15 in_progress,
16 Win_X,
17 Win_O,
18 Draw
все еще вопрос по стилю именования
5 #include <ncurses.h>
не нужен в include/NcursesBoardView.hpp
зачем-то есть пустой
src/BoardView.cpp
обработка ошибок от std::cout не единообразная, лучше всего было бы в main.cpp выставлять флаги по исключениям и там же эти исключения и обрабатывать
Ход "0 0a" обрабатывается как валидный
std::vector<std::vector<Player> >
удобно сделать using (Field?), чтобы не дублировать тип в разных местах
Про Player
В целом можно оставить как есть, но хочу акцентировать внимание вот на чем:
Используется в двух разных ипостасях: очередность игрока и содержимое клетки. Между собой эти сущности связаны, но отличаются. None в качестве текущего игрока имеет мало смысла, возникает по техническим причинам, показывает, что игра окончена и никто походить не может.
Можно было бы разбить сущность на две:
CellContent?? (какой символ записан в клетке; X / O / None)
Player (игрок, XPlayer / OPlayer)
getCurPlayer может возвращать std::optional<Player>
Field мог бы состоять из CellContent?
Отличие между типами могло бы уберечь от ошибок - на этапе компиляции могла бы быть проверка, что программист подумал о разнице между содержимым клетки и очередностью хода и имеет в виду именно очередность хода при вызове метода. Больше кода, зато меньше возможностей ошибиться и проще модифицировать (вдруг Вы захотите добавить препятствия на игровое поле?)
isCorrectCell - непонятное название, лучше именовать конкретнее, например, isInsideField
isEq5OnLine можно было бы назвать просто 5OnLine
Классы стоит помечать как final, если от них не предполагается наследоваться
Про int &x, int &y:
http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-out
лучше всего сделать
struct Position{int x; int y;};
использовать его везде, где используются x и y
и в BoardView? сделать метод (например)
virtual std::optional<Position> retrieveNextPosition() = 0;
optional или нет зависит от того, как хочется устроить обработку ситуации "разрыв соединения" / предварительное окончание игры / ...
Предлагаю в BoardView? считать, что в наследнике доступен Board и убрать из интерфейса все, что может быть получено по Board (field, gameState, curPlayer, ...)
Что должно делать updateField не очень понятно, если речь про отображение, то можно использовать print / draw / redraw / ...
лучше принимать не bool silent, а сделать
enum Mode{DEFAULT, SILENT, ...}, чтобы легко поддерживать новые режимы, а также избежать ошибок при смене значения флага.
testGetCurPlayer1
Если curPlayer - это последний ходивший (а из названия это непонятно, что плохо), то на момент начала игры еще никто не ходил, тест некорректен
В тестах стоит проверить, что если игра закончилась, то нельзя сделать ход (canMove вернет false)
testGetField*
v можно сразу же инициализировать, есть необходимый конструктор
Сейчас в тестах не получится узнать, какой именно тест не пройден
Лучше использовать switch, потому что тогда компилятор сможет помочь проверить, что все значения перечисления обработаны
можно инициализировать в списке инициализации
Стоит завести массив Directions, в котором перечислены возможные направления
field_has_none можно переименовать в game_in_progress / field_not_full, станет понятнее
так плохо, потому что происходит нетривиальное связывание каких-то значений с каким-то конкретным смыслом, что не закреплено явно через отдельный метод / именованную константу / ...
Кажется, если Controller владеет Board, то пусть и View тоже владеет
const auto&
Отсутствует проверка успешности ввода / вывода
Сейчас ввод обрабатывается не так, как того требует условие.