Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Игра в кости

87
21 декабря 2009 года
Kogrom
2.7K / / 02.02.2008
У меня появилась следующая идея. В данном разделе есть несколько человек, которые постоянно решают мелкие задачки для студентов: Ghox, koodeer и т.д. Но, возможно им захочется сделать что-то большее. Вот я выкопал такую задачку:

http://forum.codenet.ru/showthread.php?t=57128

Вроде бы не особо сложная, но и не очень мелкая. Можно было бы поиграть в создание "настоящей программы". Составить нормальное ТЗ (просто выкинуть из того что есть двузначности, добавить пояснения), придумать требования к взаимодействию с пользователем, выбрать тип лога, обосновать этот выбор, создать программу в хорошем ООП-шном стиле и т.д.

Предполагается, что кто-то начнёт, кто-то продолжит, а я буду критиковать и подсказывать (не потому что шибко умный, а потому что люблю критиковать). За интересные ходы возможно буду раздавать зелёные квадраты (вроде это правилам не противоречит).

Язык программирования конечно же C++, как наиболее популярный :)

Как идея? Найдутся желающие?
Страницы:
297
22 декабря 2009 года
koodeer
1.2K / / 02.05.2009
Отлично! Я готов поучаствовать. К сожалению, не смог принять участия в учебном проекте, т. к. в Пайтоне не волоку, хотя желание было.

Вот только меня несколько смущает
Цитата:
создать программу в хорошем ООП-шном стиле


Вроде как не очень сложная задачка и я с трудом могу представить в ней несколько классов, а уж тем более наследование и прочие вкусности ООП. Если бы я писал нечто подобное, то, думаю, ограничился бы несколькими функциями (сколько понадобится). Однако, именно поэтому мне это интересно.

Цитата:
выбрать тип лога

то есть историю игры тоже будем сохранять? Ладно, подумаем.

И насчёт взаимодействия с пользователем: думаю, ограничимся консолью?

87
22 декабря 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: koodeer
Вроде как не очень сложная задачка и я с трудом могу представить в ней несколько классов, а уж тем более наследование и прочие вкусности ООП.


Тем интереснее попробовать написать с применением ООП. Для целесообразности можно предположить, что в ТЗ будут вносить изменения. Например, компьютер будет предоставлять несколько игроков, или будут несколько стратегий для компьютера, или изменятся правила (например, кость будут бросать не до выпадания единицы, а определенное число раз).

Цитата: koodeer
то есть историю игры тоже будем сохранять? Ладно, подумаем.


Вот что пишут в исходном ТЗ:

Цитата:
Разработать программу, реализующую игру в кости человека с компьютером. Правила игры следующие: каждый игрок в свою очередь хода бросает кость столько раз, сколько хочет. Если он не выбрасывает единицу, то записывает себе сумму выпавших за эти бросания очков. Если он выбрасывает единицу, то он не записывает на свой счет ничего (его ход оканчивается единицей). Выигравшим считается тот, кто первый наберет (превысит) 100 очков. Предусмотреть возможность изменения стратегии игры со стороны компьютера, а так же запись всех шагов игры в лог файл и определение случайным образом игрока делающего первый ход.


А раз есть запись, то возможно надо сделать и чтение. Хотя в ТЗ пока про это ничего не говорится.

Цитата: koodeer
тИ насчёт взаимодействия с пользователем: думаю, ограничимся консолью?


Для начала - да. И тексты вначале будут английские, чтобы не морочиться. Интересно было бы потом перейти к GUI, чтобы ООП показал свои возможности, но думаю, тут будет много ненужных споров.

87
22 декабря 2009 года
Kogrom
2.7K / / 02.02.2008
Стив Макконнелл в своей книге "Совершенный код" выделяет следующие пункты разработки ПО:
  1. определение проблемы;
  2. выработка требований;
  3. создание плана конструирования;
  4. разработка архитектуры ПО, или высокоуровневое проектирование;
  5. детальное проектирование;
  6. кодирование и отладка;
  7. блочное тестирование;
  8. интеграционное тестирование;
  9. интеграция;
  10. тестирование системы;
  11. корректирующее сопровождение.
Но предполагаю, что в нашем случае можно список сократить до:
  1. определение проблемы;
  2. выработка требований;
  3. детальное проектирование;
  4. кодирование и отладка;
Конечно, интереснее сразу перейти к кодированию, но это мы и так умеем. Ну, хоть как-то, но умеем. Интереснее попробовать другие пункты. Это позволит по другому посмотреть на процесс создания ПО.

Поэтому для начала надо сформулировать адекватное ТЗ.
Затем надо определиться с инструментами и технологиями. Например, будем ли для лога использовать xml или csv, или какой-то свой формат. Да и компилятор надо выбрать.
297
23 декабря 2009 года
koodeer
1.2K / / 02.05.2009
Цитата: Kogrom
Интереснее попробовать другие пункты.


Тут я полностью согласен. Закодить такую программу без всяких предварительных планов можно довольно быстро. Однако на собственном опыте много раз убеждался, что едва проект по сложности превысит некоторый порог, так сразу начинаются проблемы без предварительного тщательного планирования. Когда пишу что-то для себя, для души, постоянно добавляю в уже почти готовую программу какие-нибудь фичи, и так до бесконечности... У меня что ни программа - то симфония. Неоконченная... :(

Цитата: Kogrom
будем ли для лога использовать xml или csv, или какой-то свой формат.


Мне без разницы. Но склоняюсь к csv. Свой формат городить вроде ни к чему, а xml несколько сложнее, чем csv, но его широкие возможности здесь не дадут выгоды.

Цитата: Kogrom
Да и компилятор надо выбрать.


Мне опять же без разницы. Вообще я пользуюсь Visual Studio, но если появятся ещё желающие (ау-у! есть кто?), то готов перейти на что-нибудь иное, по требованию коллектива.

Цитата: Kogrom
  1. определение проблемы;


Думал-думал над этим пунктом... В итоге надумал: Kogrom, раз уж вызвался критиковать и управлять, то выставляй задание, выступай в роли заказчика :).

PS: Макконнелла читал, "Совершенный код" у меня в бумажном варианте имеется. Превосходная вещь.

87
23 декабря 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: koodeer
Мне без разницы. Но склоняюсь к csv. Свой формат городить вроде ни к чему, а xml несколько сложнее, чем csv, но его широкие возможности здесь не дадут выгоды.


Ок. Плюс к тому - его проще читать сторонними программами. То есть можно спокойно не добавлять функцию чтения лога.

Цитата: koodeer
Мне опять же без разницы. Вообще я пользуюсь Visual Studio, но если появятся ещё желающие (ау-у! есть кто?), то готов перейти на что-нибудь иное, по требованию коллектива.


Я бы предпочел что-то свободное и простое. Типа этого:
http://www.codeblocks.org/

Если смущает, то, что официальный дистрибутив обновлялся больше года назад, то можно собрать свой. Я когда-то развлекался так:
https://code.google.com/p/codeblocks-mix/

Цитата: koodeer
Думал-думал над этим пунктом... В итоге надумал: Kogrom, раз уж вызвался критиковать и управлять, то выставляй задание, выступай в роли заказчика :).



Ок. Управлять я не брался, но играть роль заказчика вероятно смогу :)

297
23 декабря 2009 года
koodeer
1.2K / / 02.05.2009
Ночью приснился виртуальный игральный кубик: такой, что на нём могут выпадать значения не только от 1 до 6, но и любые другие, в том числе 0. :)

Вопрос по техзаданию: сколько будет кубиков в игре - 1, 2 или больше? Если больше одного, то как выводить выброшенные очки: одним числом-суммой, или несколькими числами (по количеству костей)?

Понимаю, что ещё не завершено проектирование, но меня так и тянет покодить. Набросок класса "Игральный кубик"
Код:
// Игральная кость (кубик)
class Dice
{
public:
    unsigned int count; // количество бросков за всю игру

    Dice()
    {
        srand(time(0));
        count = 0;
    }

    enum DiceValue // нужно ли?
    {
        one   = 1,
        two   = 2,
        three = 3,
        four  = 4,
        five  = 5,
        six   = 6
    };

    DiceValue Roll() // бросить кость
    {
        count++;
        return (DiceValue)(rand() % 6);
    }
};

Бегу вперёд паровоза, по ещё непроложенным путям :).
87
23 декабря 2009 года
Kogrom
2.7K / / 02.02.2008
Решил использовать старое ТЗ от студента, но с внесением некоторых пояснений:

Разработать программу, реализующую игру в кости человека с компьютером. Правила игры следующие: каждый игрок (компьютер или пользователь) в свою очередь хода бросает кость столько раз, сколько хочет, до выпадения единицы.

Если игрок заканчивает ход до выпадения единицы (по своему желанию), то записывает себе сумму выпавших за эти бросания очков. Если он выбрасывает единицу, то он не записывает на свой счет ничего. То есть в данном случае весь ход будет потрачен впустую. После выпадения единицы ход заканчивается принудительно.

Выигравшим считается тот, кто первый наберет (превысит) 100 очков.

Предусмотреть возможность изменения стратегии игры со стороны компьютера. Например, компьютер может вести более жадную стратегию (больше бросков за ход) если проигрывает и более надежную (меньше бросков за ход), если выигрывает. Или наоборот.

Предусмотреть запись всех шагов игры в лог файл и определение случайным образом игрока делающего первый ход.

Предполагаемые изменения во второй версии программы: вводится несколько игроков (ботов), за которых играет компьютер, предусматривается режим игры без пользователя, предусматривается загрузка файлов с описанием стратегий ботов.

Так же могут быть изменены правила: например, будет введён бонус за дубль и т.п.
87
23 декабря 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: koodeer
Вопрос по техзаданию: сколько будет кубиков в игре - 1, 2 или больше? Если больше одного, то как выводить выброшенные очки: одним числом-суммой, или несколькими числами (по количеству костей)?


Пока кубик будет один. В будущих версиях может и два будет. Это позволит сделать правила более интересными.

Цитата: koodeer
Понимаю, что ещё не завершено проектирование, но меня так и тянет покодить.



Класс-кость нужен, это очевидно. Но не понял зачем там count. Кость будет считать сколько раз её бросили?

На счет enum DiceValue тоже не уверен. Но больше смущает rand() % 6. А вдруг кубик не шестисторонний. Был у меня когда-то восьмисторонний кубик :)

297
23 декабря 2009 года
koodeer
1.2K / / 02.05.2009
Вариант 2
Код:
// Игральная кость (кубик)
class Dice
{
private:
    int facets; // количество граней кости

public:
    unsigned int count; // количество бросков за всю игру

    Dice(int facets = 6)
    {
        if (facets < 2 /* && facets > ? */)
        {
            throw exception("Argument out of range"); // вариант 1
            //facets = 6; // вариант 2
        }

        this->facets = facets;
        srand((unsigned int)time(0));
        count = 0;
    }
    int Roll() // бросить кость
    {
        count++;
        return rand() % facets + 1;
    }
};

Мне всё же кажется, что сделать подсчёт общего количества бросков в самом классе кубика вполне разумно. Вне класса можно считать кол-во бросков отдельными игроками.

Каким значением ограничим максимальное количество граней кости?
Как будем сигнализировать о превышении этого значения? Выбрасыванием исключения или установкой значения по умолчанию?
Заменить ли магические числа на
 
Код:
#define MinFacets 2
#define MaxFacets ?
#define DefaultFacets 6
12K
23 декабря 2009 года
Ghox
297 / / 26.07.2009
Цитата: Kogrom
Как идея? Найдутся желающие?


Идея неплохая, на мой взгляд. Мог бы поучаствовать (тем более я обозначен в теме как один из предполагаемых участников), но, в настоящее время, в силу нехватки времени, мое участие может иногда быть запоздалым... Тем более, что тут требуется выделить время на осмысление ТЗ и на проектирование, а не не накидать за 10-15 минут нерадивому студенту решение задачки или ответить на вопрос... А перед Новым Годом и несколько дней после него буду отсутствовать, по причине отъезда, и участвововать вообще не смогу. Так что полноценным участником в ближайшее время вряд ли буду, может буду время от времени появляться и что-то писать в теме, но на серъезное участие с моей стороны рассчитывать пока не приходится. А поскольку проект простой, к тому времени как активно смогу включиться - скорее всего будет закончен. :)

Цитата: Kogrom
Решил использовать старое ТЗ от студента, но с внесением некоторых пояснений:
...
Предусмотреть возможность изменения стратегии игры со стороны компьютера. Например, компьютер может вести более жадную стратегию (больше бросков за ход) если проигрывает и более надежную (меньше бросков за ход), если выигрывает. Или наоборот.


Вот тут следует расписать поподробнее и поточнее, на мой взгляд. Наверно, под стратегией компьютера правильней понимать алгоритм принятия компьютером тактических решений в ходе игры (сколько раз пытаться бросить кость), в зависимости от текущей ситуации (ближе ли к выигрышу компьютер, чем человек, или дальше). И тогда фразу "Предусмотреть возможность изменения стратегии игры со стороны компьютера" можно перефразировать в "В стратегии компьютера предусмотреть возможность изменения тактики игры компьютера", и / или "Должен быть реализован набор нескольких стратегий компьютера, перед началом игры игрок-человек имеет возможность выбора, с какой стратегией будет с ним играть его компьютерный противник". Так что требуется, ИМХО, уточнение данного пункта.

Цитата: koodeer
Вроде как не очень сложная задачка и я с трудом могу представить в ней несколько классов, а уж тем более наследование и прочие вкусности ООП. Если бы я писал нечто подобное, то, думаю, ограничился бы несколькими функциями (сколько понадобится). Однако, именно поэтому мне это интересно.


Ну почему же, у меня вот сразу вырисовывается пример, как можно использовать несколько классов:

  • Абстрактный класс "игрок", имеет переменную - количество накопленных за предыдущие ходы очков, метод бросания кости, и метод принятия решения (чисто виртуальная функция) - прекращать броски или нет.
От класса "Игрок" наследуются классы:
  • "Игрок-человек" - соответствует пользователю, играющему с программой, для этого класса метод принятия решения будет запрашиванием в консоли от пользователя, прекращать броски или нет.
  • Несколько классов "Игрок-компьютер", каждый класс со своей стратегией игры, соответственно у каждого класса будет своя реализация метода принятия решений.
Цитата: Kogrom
Я бы предпочел что-то свободное и простое. Типа этого:
http://www.codeblocks.org/


Поддерживаю, т.к. для такого простого проекта навороты Visual Studio не нужны, а для учебных целей вполне сгодится Code::Blocks (который я сам для учебных целей использую). Но поскольку, как я уже сказал, я пока не могу быть полноценным участником - можете мое мнение спокойно проигнорить. :)

87
23 декабря 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: koodeer

Мне всё же кажется, что сделать подсчёт общего количества бросков в самом классе кубика вполне разумно. Вне класса можно считать кол-во бросков отдельными игроками.


Среди паттернов GRASP есть так называемый Information Expert, который утверждает, что обязанности должны быть назначены объекту, который владеет максимумом необходимой информации для выполнения обязанности. Возможно, для подсчета бросков это будет кость. Может даже для подсчета очков за ход. Но пока мы не выяснили, какие объекты у нас есть, поэтому трудно рассуждать.

Цитата: koodeer
Каким значением ограничим максимальное количество граней кости?
Как будем сигнализировать о превышении этого значения? Выбрасыванием исключения или установкой значения по умолчанию?


Я намекал на то, что используется магическая переменная. На самом деле, наверняка кость сама должна знать, сколько граней у неё. То есть это может быть константа класса, записываемая прямо в классе: static const int facets = 6;

87
23 декабря 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: Ghox
Так что полноценным участником в ближайшее время вряд ли буду, может буду время от времени появляться и что-то писать в теме...


Тоже неплохо.

Цитата: Ghox
Наверно, под стратегией компьютера правильней понимать алгоритм принятия компьютером тактических решений в ходе игры (сколько раз пытаться бросить кость), в зависимости от текущей ситуации (ближе ли к выигрышу компьютер, чем человек, или дальше).


На данном этапе я понимаю именно так. То есть не человек выбирает как будет играть бот, а бот меняет тактику.

Цитата: Ghox
Ну почему же, у меня вот сразу вырисовывается пример, как можно использовать несколько классов:
  • Абстрактный класс "игрок", имеет переменную - количество накопленных за предыдущие ходы очков, метод бросания кости, и метод принятия решения (чисто виртуальная функция) - прекращать броски или нет.
От класса "Игрок" наследуются классы:
  • "Игрок-человек" - соответствует пользователю, играющему с программой, для этого класса метод принятия решения будет запрашиванием в консоли от пользователя, прекращать броски или нет.
  • Несколько классов "Игрок-компьютер", каждый класс со своей стратегией игры, соответственно у каждого класса будет своя реализация метода принятия решений.



До прочтения этого сообщения я пытался анализировать предметную область. В первом приближении у меня получилось так:

У нас есть 2 игрока. Игроки делятся на 2 подкласса: бот и пользователь. Также должен быть некий диспетчер хода, ведущий. Он определяет очередность ходов, момент передачи хода и момент завершения игры. Есть объект-кость, который используется во время хода. В общем, кость может создаваться на время хода, или быть статическим объектом (некая замена модулю).

Кроме того, должны быть объекты взаимодействия с пользователем и объект записи в лог.

В чем-то идеи сходятся. Хорошо бы ещё нарисовать пару эскизных диаграмм UML (классов и взаимодействия). Было бы нагляднее.

87
24 декабря 2009 года
Kogrom
2.7K / / 02.02.2008
Так, UML-ом всех людей распугал... Ок, попробую описать игру как сценарий. Пока без лога, без подробностей.

1. Создается объект - Ведущий.
2. Ведущий создает другие объекты: игроков, объект интерфейса.
3. Ведущий определяет игрока, который будет ходить первым. Пусть игроком вначале будет бот.
4. Ведущий сообщает боту, чтобы тот сделал ход.
5. Бот создаёт объект "кость".
6. Бот бросает кость некоторое количество раз (зависит от текущей стратегии бота).
7. Бот сообщает ведущему, что ход закончен.
8. Ведущий сообщает объекту-игроку, чтобы тот сделал ход.
9. Игрок создаёт объект "кость".
10. Игрок бросает кость.
11. Если не выпала единица, то игрок через объект интерфейса обращается к пользователю, чтобы тот ответил, нужно ли ещё бросать кость.
12. Если игрок подтверждает, то переходим на 2 пункта назад.
13. Повторяем пункты 4-12 пока у одного игрока не накопится 100 очков.
14.Если у кого-то накопилось не менее 100 очков, то игра завершается. Пользователю выводится соответствующее сообщение.
297
24 декабря 2009 года
koodeer
1.2K / / 02.05.2009
Цитата: Kogrom
Так, UML-ом всех людей распугал...


В точку :)
У меня никак руки не дойдут вплотную заняться освоением UML.
Понять схему не проблема, так что можешь делать UML, если есть такое желание. Вернее, это даже нужно - мне пойдёт на пользу.

Сценарий принят. Постараюсь набросать каркас приложения.

12K
26 декабря 2009 года
Ghox
297 / / 26.07.2009
Цитата: Kogrom
Так, UML-ом всех людей распугал... Ок, попробую описать игру как сценарий. Пока без лога, без подробностей.

1. Создается объект - Ведущий.
2. Ведущий создает другие объекты: игроков, объект интерфейса.
3. Ведущий определяет игрока, который будет ходить первым. Пусть игроком вначале будет бот.
4. Ведущий сообщает боту, чтобы тот сделал ход.
5. Бот создаёт объект "кость".
6. Бот бросает кость некоторое количество раз (зависит от текущей стратегии бота).
7. Бот сообщает ведущему, что ход закончен.
8. Ведущий сообщает объекту-игроку, чтобы тот сделал ход.
9. Игрок создаёт объект "кость".
10. Игрок бросает кость.
11. Если не выпала единица, то игрок через объект интерфейса обращается к пользователю, чтобы тот ответил, нужно ли ещё бросать кость.
12. Если игрок подтверждает, то переходим на 2 пункта назад.
13. Повторяем пункты 4-12 пока у одного игрока не накопится 100 очков.
14.Если у кого-то накопилось не менее 100 очков, то игра завершается. Пользователю выводится соответствующее сообщение.


Итак, от этапа составления ТЗ уже произошел переход к проектированию решения...

По данному сценарию, думаю также требуется кое-какое пояснение. Каждый игрок, перед началом хода, имеет накопленное за предыдущие ходы количество очков. И тут есть два варианта в плане того, "знает" ли каждый игрок, помимо количества своих очков, текущее количество очков игрока-противника:

1. Знает - объекты игрок (человек) и бот раполагают информацией о том сколько очков у другого игрока (эта информация может, например, передаваться ведущим перед совершением хода), при этом пользователю это число высвечивается на экране, а для бота - хранится в виде переменной (переменной класса, либо локальной переменной - входным параметром функции - метода принятия решений по части текущей тактики игры). Игроки соответственно имеют возможность менять тактику игры, исходя из того насколько близок он и противник к победе.

2. Не знает (информация игроку о количестве очков противника не передается), и соответственно игрок знает напрямую только насколько он сам близок к победе, а насчет противника - может судить только косвенно (например, по количеству уже сделанных ходов - если ходов сделано уже много, то есть вероятность что противник скоро победит). Т.е. этакая "игра вслепую".

И тут нужно определиться: взять ли первый вариант (для обоих игроков), либо второй, либо опционально (по выбору пользователя в начале игры) - "в открытую" либо "игра вслепую". Можно даже реализовать возможность выбора, чтобы один из игроков знал о количестве очков другого игрока, а другой - нет.
И еще можно реализовать возможность переключения от одного варианта к другому прямо в ходе игры, по обоюдному согласию игроков. Правда, тогда придется для игрока-бота создавать алгоритм решения - стоит ли предложить противнику перейти к игре вслепую либо наоборот - к игре в открытую. А также - если от противника поступает предложение о смене стиля игры - согласиться или нет.

87
26 декабря 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: Ghox
И тут есть два варианта в плане того, "знает" ли каждый игрок, помимо количества своих очков, текущее количество очков игрока-противника



Сказал два, а рассказал о трёх, если учесть комбинированный :)

Я предполагаю, что и игроку будет интереснее знать, сколько очков набрал бот, и у бота будет больше данных для стратегии, если он будет знать, сколько очков у игрока.

Предлагаю остановиться на таком варианте.

Думаю, игроки будут узнавать данные о сопернике через ведущего (если такой объект будет). В случае, если участников в игре будет больше двух, то ведущий будет вероятно передавать максимум. Для бота вроде бы и не нужно большего.

В данном случае, структура связей будет в виде звёздочки. Если играющие будут обмениваться данными напрямую, то структура будет сложнее.

12K
26 декабря 2009 года
Ghox
297 / / 26.07.2009
Цитата: Kogrom
Я предполагаю, что и игроку будет интереснее знать, сколько очков набрал бот, и у бота будет больше данных для стратегии, если он будет знать, сколько очков у игрока.

Предлагаю остановиться на таком варианте.


Для первой версии программы (простой вариант игры - два игрока, одна стратегия бота, в рамках которой он может менять тактику) - согласен. Но для второй версии считаю нужным реализовать возможность игры вслепую. Для нее кстати стратегия бота должна быть другой.

Цитата: Kogrom
Думаю, игроки будут узнавать данные о сопернике через ведущего (если такой объект будет). В случае, если участников в игре будет больше двух, то ведущий будет вероятно передавать максимум. Для бота вроде бы и не нужно большего.


Ну если хотя бы исходить из теории вероятности, то все равно может быть полезно знать количество очков у каждого из противников. Допустим у бота два противника. Согласись, что в ситуации, когда у обоих противников бота по 70 очков, в общем случае шансов проиграть больше, чем когда у одного противника 70, а у другого - всего 10? И соответственно стратегия может быть разной.

И еще в случае, если игроков будет больше двух (второй этап разработки игры), то можно также придумать разные варианты завершения игры:
1. Как только какой-нибудь игрок наберет 100 очков - игра заканчивается, игрок объявляется победителем, остальные - проигравшими.
2. После того как какой-нибудь игрок наберет 100 очков, но при этом есть два или более игроков, еще не набравших 100 очков, то игра не заканчивается. Не набравшие 100 очков игроки продолжают делать ходы, пока кто-нибудь также 100 очков не наберет. Так до тех пор, пока не останется только один игрок, который не набрал 100 очков, который объявляется проигравшим. Остальные игроки занимают места: кто первым набрал 100 очков - первое, кто вторым - второе и т.д.

Возможно, что в зависимости от вариантов, стратегия также может быть разной, т.к. добиться больше шансов выиграть - это одно, а добиться более-менее гарантированно получить какое-либо место (пусть не первое) - это другое.

И еще у меня возникла идея, но это возможно для второго этапа игры, а возможно что и для третьего (возможно что она потребует более тщательной проработки). Реализовать самообучающегося бота, который, играя с полььзователем, пробует разные варианты стратегий, копит статистику - при какой стратегии чаще получается выиграть, и затем ее придерживается. Если начал проигрывать при выбранной стратегии - то опять пытается менять стратегию, и т.д. Например, можно было бы реализовать так. У бота есть предопределенный набор мини-стратегий (например, стремиться бросить 1 раз; 2 раза; 3 раза; 4 раза; стремиться бросать пока в течение хода не выброшено какое-то кол-во очков, и т.д.), и предопределенный набор событий, при которых, возможно, стоит поменять текущую мини стратегию на другую (например, такими событиями могут быть накопление ботом либо его противником 20, 40, 60, 80 очков; разница в накоплении очков между ботом и противником -80; -60; -40; -20; 0; 20; 40; 60; 80). Но это вкратце, тут для большей ясности мне следовало бы подробнее описать что я имею в виду... Если вариант предоставляется перспективным, то можно потом его проработать...

87
26 декабря 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: Ghox
Но для второй версии считаю нужным реализовать возможность игры вслепую.


Не совсем понял - зачем? Странным представляется сценарий: бросал, бросал кубик и вдруг проиграл. Ну, или выиграл. Ни догоняешь, ни отрываешься. Нет азарта.

Цитата: Ghox
И еще в случае, если игроков будет больше двух (второй этап разработки игры), то можно также придумать разные варианты завершения игры:
1. Как только какой-нибудь игрок наберет 100 очков - игра заканчивается, игрок объявляется победителем, остальные - проигравшими.
2. После того как какой-нибудь игрок наберет 100 очков, но при этом есть два или более игроков, еще не набравших 100 очков, то игра не заканчивается. Не набравшие 100 очков игроки продолжают делать ходы, пока кто-нибудь также 100 очков не наберет. Так до тех пор, пока не останется только один игрок, который не набрал 100 очков, который объявляется проигравшим. Остальные игроки занимают места: кто первым набрал 100 очков - первое, кто вторым - второе и т.д.


Тогда не максимум, а массив результатов.

Но всё это расчеты на будущее. Пока же надо сделать простейший вариант для двух игроков. А кода что-то не видать (если не считать тот класс кости). Наверное, готовится шедевр... Подожду ещё день и если код не появится, буду делать свои наброски. Чтобы другие не теряли интерес - кодить буду на Python :)

297
26 декабря 2009 года
koodeer
1.2K / / 02.05.2009
Цитата: Kogrom
А кода что-то не видать (если не считать тот класс кости). Наверное, готовится шедевр... Подожду ещё день и если код не появится, буду делать свои наброски. Чтобы другие не теряли интерес - кодить буду на Python



Не надо Python! :eek: В таком случае над проектом будет работать всего один человек, и это будет Kogrom.

Шедевр, к сожалению, не готовится. Я увлёкся освоением UML :). Открыв Крэга Лармана, понял, откуда ноги растут у игры в кости ;).
Я тут присмотрел софтинку StarUML для построения диаграмм UML. Как только расчищу место на винте (сцуко, кончилось :(), установлю её и попробую UML на практике.

Теперь насчёт стратегии игры в кости. Я за точность формулировок! При нынешних правилах - все выброшенные очки больше 1 начисляются, при выпадении единицы ход переходит к другому игроку - выигрышная стратегия всего одна: бросать кубик, пока не выпадет единица. При таких правилах возможна лишь стратегия поддаваться противнику - передавать ему ход, даже если не выпала единица.

87
26 декабря 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: koodeer
Не надо Python! :eek: В таком случае над проектом будет работать всего один человек, и это будет Kogrom.


Ок.

Цитата: koodeer
Шедевр, к сожалению, не готовится. Я увлёкся освоением UML :). Открыв Крэга Лармана, понял, откуда ноги растут у игры в кости ;).
Я тут присмотрел софтинку StarUML для построения диаграмм UML. Как только расчищу место на винте (сцуко, кончилось :(), установлю её и попробую UML на практике.


Один продвинутый в проектировании человек рекомендовал Microsoft Visio. Я пытался использовать бесплатную альтернативу - Dia, но уж больно она неудобная. В результате остановился на MS Paint (стандартный редактор Windows). Для черновиков он хорошо подошёл, а большего мне и не надо.

Цитата: koodeer
Теперь насчёт стратегии игры в кости. Я за точность формулировок! При нынешних правилах - все выброшенные очки больше 1 начисляются, при выпадении единицы ход переходит к другому игроку - выигрышная стратегия всего одна: бросать кубик, пока не выпадет единица. При таких правилах возможна лишь стратегия поддаваться противнику - передавать ему ход, даже если не выпала единица.


Ты не понял правил. Если у игрока выпадает единица, то он теряет все очки, набранные за ход. Игроку не выгодно ждать, пока выпадет единица.

В уточняющем ТЗ я это пытался донести в доступной форме.

297
26 декабря 2009 года
koodeer
1.2K / / 02.05.2009
Цитата: Kogrom
Ты не понял правил. Если у игрока выпадает единица, то он теряет все очки, набранные за ход. Игроку не выгодно ждать, пока выпадет единица.

В уточняющем ТЗ я это пытался донести в доступной форме.



Каюсь, действительно прочитал невнимательно.
Ок, стратегия понята. Буду кодить.

12K
27 декабря 2009 года
Ghox
297 / / 26.07.2009
Цитата: Kogrom
А кода что-то не видать (если не считать тот класс кости). Наверное, готовится шедевр... Подожду ещё день и если код не появится, буду делать свои наброски.


Хех, а я-то думал что пока идет этап проектирования решения. А ты, оказывается, уже кода ждешь. :)

Тогда вот мой набросок в соответствии с тем, как я представлял структуру программы. Использовал сделанный ранее koodeer'ом класс Dice. Метод принятия решений ботом пока сделал примитивный, т.к. разработка алгоритма стратегии игры бота - не такая простая вещь как может показаться.

P.S. Проверял в Code::Blocks - вроде работает.

Код:
#include <iostream>
#include <conio.h>
using namespace std;

class Dice
{
private:
    int facets; // количество граней кости

public:
    unsigned int count; // количество бросков за всю игру

    Dice(int facets = 6)
    {
        this->facets = facets;
        srand((unsigned int)time(0));
        count = 0;
    }
    int Roll() // бросить кость
    {
        count++;
        return rand() % facets + 1;
    }
};

class Player
{
protected:
    unsigned int points;
    unsigned int turnsPassed;
    unsigned int throwDice();
    const string name;
public:
    Player(const string&);
    virtual ~Player();
    virtual unsigned int makeTurn(unsigned int) = 0;
    string announce();
};

Player::Player(const string& str) : points(0), turnsPassed(0), name(str) {}

Player::~Player() {}

unsigned int Player::throwDice()
{
    Dice * pDice = new Dice;
    unsigned int result = pDice->Roll();
    delete pDice;
    return result;
}

string Player::announce()
{
    return name;
}

class HumanPlayer : public Player
{
public:
    HumanPlayer();
    virtual unsigned int makeTurn(unsigned int);
};

HumanPlayer::HumanPlayer() : Player("user player") {}

unsigned int HumanPlayer::makeTurn(unsigned int otherPartyPoints)
{
    cout << "\n----------------------\n";
    cout << announce() << ", your turn # " << turnsPassed++ << ", you have " << points << " points\n";
    cout << "your adversary has " << otherPartyPoints << " points\n";
    cout << "start now rolling the dice\n";
    unsigned int totalResult = 0, throws = 0, throwResult;
    bool continueRolls = true;
    while(continueRolls)
    {
        ++throws;
        cout << "Roll # " << throws << ": ";
        throwResult = throwDice();
        cout << "rolled " << throwResult << " points";
        if(throwResult == 1)
        {
            cout << "\nyou rolled 1 and loose all points rolled in this turn\n";
            totalResult = 0;
            continueRolls = false;
        }
        else
        {
            totalResult += throwResult;
            cout << "; total " << totalResult << " points\n";
            cout << "press 'y' if you wish to continue rolls\n";
            char c;
            cin >> c;
            if(c != 'y')
                continueRolls = false;
        }
    }
    cout << "ending turn, you got " << totalResult << " in " << throws << " rolls\n";
    points += totalResult;
    cout << "Press any key to continue\n";
    _getch();
    return totalResult;
}

class RobotPlayer : public Player
{
public:
    RobotPlayer();
    virtual unsigned int makeTurn(unsigned int);
};

RobotPlayer::RobotPlayer() : Player("computer player") {}

unsigned int RobotPlayer::makeTurn(unsigned int otherPartyPoints)
{
    cout << "\n----------------------\n";
    cout << announce() << ", your turn # " << turnsPassed++ << ", you have " << points << " points\n";
    cout << "your adversary has " << otherPartyPoints << " points\n";
    cout << "start now rolling the dice\n";
    unsigned int totalResult = 0, throws = 0, throwResult;
    bool continueRolls = true;
    int diffPoints = (int)otherPartyPoints - (int)points;
    unsigned int wishedTriesCount = 1;
    if(diffPoints > 80)
        wishedTriesCount = 6;
    else if(diffPoints > 60)
        wishedTriesCount = 5;
    else if(diffPoints > 40)
        wishedTriesCount = 4;
    else if(diffPoints > 20)
        wishedTriesCount = 3;
    else if(diffPoints > 0)
        wishedTriesCount = 2;
    while(continueRolls)
    {
        ++throws;
        cout << "Roll # " << throws << ": ";
        throwResult = throwDice();
        cout << "rolled " << throwResult << " points";
        if(throwResult == 1)
        {
            cout << "\nyou rolled 1 and loose all points rolled in this turn\n";
            totalResult = 0;
            continueRolls = false;
        }
        else
        {
            totalResult += throwResult;
            cout << "; total " << totalResult << " points\n";
            if(throws < wishedTriesCount)
                cout << "you decided to continue rolls\n";
            else
            {
                cout << "you decided to end this turn\n";
                continueRolls = false;
            }
        }
    }
    cout << "ending turn, you got " << totalResult << " in " << throws << " rolls\n";
    points += totalResult;
    return totalResult;
}

class Game
{
    static const unsigned int maxPoints = 100;
    static const unsigned int playersQuantity = 2;
    std::pair<Player*, unsigned int> players[playersQuantity];
    unsigned int turnsPassed;
    Game(const Game&);
    Game operator=(const Game&);
public:
    Game();
    ~Game();
    void Play();
};

Game::Game() : turnsPassed(0)
{
    for(unsigned int i = 0; i < playersQuantity; ++i)
    {
        if(i % 2)
            players.first = new RobotPlayer;
        else
            players.first = new HumanPlayer;
        players.second = 0;
    }
}

Game::~Game()
{
    for(unsigned int i = 0; i < playersQuantity; ++i)
        delete players.first;
    cout << "Game over\n";
}

void Game::Play()
{
    unsigned int i1 = playersQuantity - 1, i2 = 0;
    do
    {
        if(i1 == playersQuantity - 1)
        {
            i1 = 0;
            i2 = playersQuantity - 1;
            ++turnsPassed;
        }
        else
        {
            ++i1;
            i2 = 0;
        }
        players[i1].second += players[i1].first->makeTurn(players[i2].second);
    }
    while(players[i1].second < maxPoints);
    cout << "player " << players[i1].first->announce() << " wins, having got " << players[i1].second << " in " << turnsPassed + 1 << " turns\n";
}

int main()
{
    Game* pGame = new Game;
    pGame->Play();
    delete pGame;
}
87
27 декабря 2009 года
Kogrom
2.7K / / 02.02.2008
koodeer, не смотри на код от Ghox - делай своё!
Цитата: Ghox
Хех, а я-то думал что пока идет этап проектирования решения. А ты, оказывается, уже кода ждешь.


Я жду хоть того, хоть другого. Наверное, надо было настоять на диаграммах. Тогда было бы удобнее рассуждать.

Цитата: Ghox
Тогда вот мой набросок в соответствии с тем, как я представлял структуру программы. Использовал сделанный ранее koodeer'ом класс Dice.



Замечания (как и обещал):
1. Свойство count класса Dice не используется.
2. Функции makeTurn громоздкие (слишком много строк), части кода в них дублируются.
3. Игроки знают, как работать с интерфейсом вывода, то есть с Видом в терминологии MVC. С чего бы это? А если я перенесу код в GUI, то мне придется переделывать весь этот класс.
4. Метод Game::Play() я не смог понять с ходу - слишком наворочено, да и имена i1, i2 радуют.

Ну и предложение по броску кости:

Код:
#include <iostream>
#include <vector>
#include <conio.h>

using namespace std;

class Dice
{
private:
    static const size_t FACETS = 6; // количество граней кости
    static const size_t BREAK_FACET = 1;
public:
    static void Roll(const size_t count, vector<int> &result) // бросить кость
    {
        result.clear();
        srand((unsigned int)time(0));
        for(size_t i = count; i > 0;  --i)
        {
            size_t rollResult = rand() % FACETS + 1;
            if (rollResult != BREAK_FACET)
                result.push_back(rollResult);
            else
                break;
        }
    }
};

int main()
{
    vector<int> res;
    Dice::Roll(5, res);

    for(size_t i = 0; i < res.size(); ++i)
        cout << res << endl;
    return 0;
}

Возможно, есть ошибки в этом коде. Он только идею иллюстрирует.
12K
27 декабря 2009 года
Ghox
297 / / 26.07.2009
Цитата: Kogrom
koodeer, не смотри на код от Ghox - делай своё!


Совершенно верно, лучше мой пример не смотреть пока что, хотя бы потому что он быдлокодерский и очень далек от совершенства. Можно потом посмотреть (когда будет свое), для сравнения...

Цитата: Kogrom
1. Свойство count класса Dice не используется.


В моем коде оно не нужно, я просто скопипастил пример класса koodeer'а, не посмотрев хорошенько что из этого класса мне реально нужно, а что нужно удалить за (пока) ненадобностью. Но судя по комментарию, если оно и в самом деле нужно, то оно должно быть, как я понимаю, static unsigned int.

Цитата: Kogrom
2. Функции makeTurn громоздкие (слишком много строк), части кода в них дублируются.


Да, верно. Я сначала хотел сделать 2 совсем разных функции, для человека - чтобы путем диалога с пользователем производились броски кости, а для компьютера - чтобы ничего не выводилось. Но потом подумал - нужно чтобы пользователь видел, как играет компьютер, сколько раз бросил кость и что у него выпадало. Потому функцию для бота создал на основе функции для человека, изменив только алгоритм принятия решения. Думаю что общую часть кода вынести в отдельную функцию базового класса (невиртуальную), а метод принятия решения - сделать виртуальной функцией и для нее уже создать разные версии в классах-наследниках.

Цитата: Kogrom
3. Игроки знают, как работать с интерфейсом вывода, то есть с Видом в терминологии MVC. С чего бы это? А если я перенесу код в GUI, то мне придется переделывать весь этот класс.


Это пока не проработал - создал пока что для случая когда жестко задан интерфейс - консоль. Для доработки у меня пока такая идея - создать абстрактный класс Interface, в котором будут объявлены функции для ввода и вывода значений различных типов. От этого класса создаются наследники - реализации конкретных типов интерфейса. В классе Player добавить переменную - указатель на объект Interface. Что-то вроде такого (пока единственный интерфейс - консоль, если понадобится другой - то тогда нужно будет создать новый класс, унаследованный)

Код:
class Interface
{
public:
    Interface();
    virtual ~Interface();
    virtual void out(const char*) = 0;
    virtual void out(const string&) = 0;
    virtual void out(int) = 0;
    virtual void in(char*) = 0;
};

class consoleIfase : public Interface
{
public:
    virtual void out(const char*);
    virtual void out(const string&);
    virtual void out(int);
    virtual void in(char*);
};

void consoleIfase::out(const char* str)
{
    cout << str;
}

void consoleIfase::out(const string& str)
{
    cout << str;
}

void consoleIfase::out(int n)
{
    cout << n;
}

void consoleIfase::in(char* c)
{
    cin >> *c;
}

class Player
{
    //...
    Interface * pIface;
public:
    Player(const string&, Interface*);
};

Player(const string& str, Interface* iface) : name(str), pIface(iface) {}


И в тех функциях где производится ввод-вывод, заменить cout и cin на pIface->out и pIface->in (тогда, если интерфейс сменится, переписывать код класса не придется):
Код:
// вместо
        {
            totalResult += throwResult;
            cout << "; total " << totalResult << " points\n";
            cout << "press 'y' if you wish to continue rolls\n";
            char c;
            cin >> c;
            if(c != 'y')
                continueRolls = false;
        }
// сделать
        {
            totalResult += throwResult;
            pIface->out("; total ");
            pIface->out(totalResult);
            pIface->out(" points\n");
            pIface->out("press 'y' if you wish to continue rolls\n");
            char c;
            pIface->in(&c);
            if(c != 'y')
                continueRolls = false;
        }

Цитата: Kogrom
4. Метод Game::Play() я не смог понять с ходу - слишком наворочено, да и имена i1, i2 радуют.


i1 - это номер текущего игрока (того чья очередь хода), i2 - номер его противника. Вообще я делал пример с ориентиром на то что будет второй этап - когда игроков может быть больше двух - для этого и сделал переменную playersQuantity. Но чтобы было сделано толково - пока не сделал. Надо будет эту функцию дорабатывать.

87
27 декабря 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: Ghox
Да, верно. Я сначала хотел сделать 2 совсем разных функции, для человека - чтобы путем диалога с пользователем производились броски кости, а для компьютера - чтобы ничего не выводилось. Но потом подумал - нужно чтобы пользователь видел, как играет компьютер, сколько раз бросил кость и что у него выпадало.


Конечно, пользователь должен видеть, как играет бот. Надо подумать, как это правильнее реализовать.

Цитата: Ghox
Это пока не проработал - создал пока что для случая когда жестко задан интерфейс - консоль. Для доработки у меня пока такая идея - создать абстрактный класс Interface, в котором будут объявлены функции для ввода и вывода значений различных типов. От этого класса создаются наследники - реализации конкретных типов интерфейса.


Думаю, что не стоит делать универсальную обёртку для потоков ввода-вывода. Надо заточить класс интерфейса под конкретную задачу.

Далее. Не вижу смысла знать об этом классе объектам-игрокам. Игрок-бот должен вычислять стратегию и в соответствии с ней управлять костью. Человеческому игроку нужно от внешнего мира только число бросков кубика за ход. На этом их функции заканчиваются. Не думаю, что надо их нагружать функциями общения с пользователем.

И ещё вопрос. Как лучше сделать: чтобы игрок сразу задавал число бросков за ход, и далее броски совершались бы автоматом, или чтобы он подтверждал каждый бросок?

12K
27 декабря 2009 года
Ghox
297 / / 26.07.2009
Цитата: Kogrom
Думаю, что не стоит делать универсальную обёртку для потоков ввода-вывода. Надо заточить класс интерфейса под конкретную задачу.

Далее. Не вижу смысла знать об этом классе объектам-игрокам. Игрок-бот должен вычислять стратегию и в соответствии с ней управлять костью. Человеческому игроку нужно от внешнего мира только число бросков кубика за ход. На этом их функции заканчиваются. Не думаю, что надо их нагружать функциями общения с пользователем.


Не понял - что значит "не знать об этом классе объектам-игрокам"? Чтобы объекты игроки не имели в своем составе переменной класса Interface - чтобы она была в составе объекта "ведущий" (который у меня представлен классом Game), а объекты-игроки обменивались бы входящими/исходыщими сообщениями с объектом "ведущий", который бы перенаправлял эти сообщения в интерфейс?

Цитата: Kogrom
И ещё вопрос. Как лучше сделать: чтобы игрок сразу задавал число бросков за ход, и далее броски совершались бы автоматом, или чтобы он подтверждал каждый бросок?


Думаю правильнее сделать подтверждение после каждого броска. Например, такая ситуация. Ты играешь с ботом, четыре раза бросил кость. Если у тебя четыре раза выпала двойка, то ты, возможно, не захочешь останавливаться. А вот если четыре раза выпала шестерка, то остановиться вполне можешь захотеть, чтобы сохранить приличный результат. :) Думаю пример дает понять зачем может быть нужно подтверждение после каждого хода. Прекратить ли броски после того как за ход суммарно выпало некоторое количество очков - тоже может быть моментом стратегии игры.

Но для простоты можно внести ограничение в правила игры. Игрок перед совершением хода должен назвать число >=1 бросков, которые он будет пытаться совершить, и возможности остановиться после такого-то броска (по факту достаточности, по его мнению, выпавших за данный ход очков) у него быть не должно.

87
27 декабря 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: Ghox
Думаю правильнее сделать подтверждение после каждого броска. Например, такая ситуация. Ты играешь с ботом, четыре раза бросил кость. Если у тебя четыре раза выпала двойка, то ты, возможно, не захочешь останавливаться. А вот если четыре раза выпала шестерка, то остановиться вполне можешь захотеть, чтобы сохранить приличный результат.


Согласен. Значит будем запрашивать подтверждение на каждый бросок.

Цитата: Ghox
Не понял - что значит "не знать об этом классе объектам-игрокам"?


Пояснение на рисунке.

Добавлено позже. Примерно так оно должно быть: игрок получает команду на ход, бросает кость, результат передает ведущему и запрашивает у него разрешение сделать ещё ход, если выпала не единица. При этом обмен идёт не строками, а числами и переменными логического типа.

12K
28 декабря 2009 года
Ghox
297 / / 26.07.2009
Цитата: Kogrom
Пояснение на рисунке.

Добавлено позже. Примерно так оно должно быть: игрок получает команду на ход, бросает кость, результат передает ведущему и запрашивает у него разрешение сделать ещё ход, если выпала не единица. При этом обмен идёт не строками, а числами и переменными логического типа.


Насчет выходной информации, которая для обоих типов игроков (человек и бот) выводится в интерфейс - да, можно сделать, чтобы она передавалась объекту "ведущий", и тот уже через интерфейс выводит информацию в консоль / GUI.
Но вот как быть насчет информации о том, собирается ли игрок продолжать броски или решил завершить свой ход? Для объектов игрок-человек и игрок-бот эта информация формируется по разному, в первом случае - поступает в объект извне, через интерфейс, от пользователя, во втором случае - формируется внутри объекта с помощью заложенного в боте алгоритма. И если сделать чтобы любой объект-игрок мог взаимодействовать с интерфейсом только через объект "ведущий игры", то тогда получится, что ведущий должен по разному обслуживать ход игрока-человека и игрока-бота. Т.е. ведущий должен знать, какого типа текущий игрок. И в таком случае уже не работает полиморфизм который я планировал использовать (чтобы для ведущего не было разницы между объектом игрок-человек и игрок-бот).

Поэтому думаю что интерфейс для ввода запроса к пользователю нужно оставить внутри класса игрок. Как вариант - можно не хранить объект интерфейс как переменную класса игрок, а передавать ссылку / указатель на интерфейс объектом "ведущий" в качестве аргумента функции принятия решений объекта-игрок, и в случае объекта игрок-человек - объект будет через этот интерфейс обращаться к пользователю. Вывод же результатов хода на экран - он однороден для обоих типов игроков, и его можно реализовать путем передачи информации через ведущего.

Еще вижу такое замечание по своему варианту. Кажется неправильным, что ведущий никак не контролирует, может ли игрок продолжать ход, контроль сейчас заложен внутри самого объекта-игрок. Думаю надо контроль вынести на уровень ведущего, а на стороне игрока оставить только хранение текущего баланса выпавших очков, и принятие решения (и сообщение о них ведущему) после каждого броска насчет того, продолжать ли ход или закончить, в случае когда очередной бросок возможен по правилам игры. Ведущий после каждого броска игрока должен проверять, выпала ли единица или нет, если нет - то сообщать игроку сколько очков выпало, и запрашивать от игрока хочет ли он бросать дальше. Если выпала единица - то сообщить игроку что у него все очки за ход сгорели и что ход передается противнику.

41K
28 декабря 2009 года
Alex57
44 / / 22.02.2009
Некоторые соображения по поводу реализации игры.

Код:
#include "Igrok.h"
#include "Krupje.h"
int main()
{
    // создаём ведущего
    Krupje krup;

    // игроки
    Igrok igk1(1);
    Igrok igk2(2);
    Igrok igk3(3);

    // подключаем игроков
    krup.AddPlayer( &igk1);
    krup.AddPlayer( &igk2);
    krup.AddPlayer( &igk3);

    // начинаем игру
    krup.Start();
    /* Другой вариант: создать отдельный поток
       _beginthreadex  ( .. Start() ...)
       А в родительском потоке контролировать,
       когда приостановить игру, когда завершить.
    */

    krup.SaveLog(); // сохраняем результаты

    cout << "Press enter ... " << endl;
    cin.get();

    return 0;
}


Функция Start() в классе Krupje.

Код:
int Start()
    {
        while ( Continue() )
        {
            // игрок делает ход
            currentIgrok->SdelatKhod();

            // определяем следующего игрока
            DetermineNextPlayer();

            // отображаем процесс игры
            ShowInformation();
        }
        return 0;
    }
87
28 декабря 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: Ghox
Поэтому думаю что интерфейс для ввода запроса к пользователю нужно оставить внутри класса игрок. Как вариант - можно не хранить объект интерфейс как переменную класса игрок, а передавать ссылку / указатель на интерфейс объектом "ведущий" в качестве аргумента функции принятия решений объекта-игрок, и в случае объекта игрок-человек - объект будет через этот интерфейс обращаться к пользователю. Вывод же результатов хода на экран - он однороден для обоих типов игроков, и его можно реализовать путем передачи информации через ведущего.



Наверное, так и хорошо. Можно вообще сделать так, чтобы игрок не знал, что из себя представляет интерфейс. Например, так:

Код:
struct Interface
{
public:
// Возвращает true, если требуется ещё ход
    static bool GetConfirmation()
    {
        char answer;
        cout << "Do you want to continue? y/n" << endl;
        cin >> answer;
        return answer == 'y';
    }
};

struct HumanPlayer
{
    int MakeTurn(int data, bool (*confirmFunc)())
    {
        while(confirmFunc());
        return 0;
    }
};


int main()
{
    HumanPlayer hPlayer;

    hPlayer.MakeTurn(0, Interface::GetConfirmation);

    return 0;
}


Тут передаваемая функция является статической, но вроде бы у класса интерфейса все функции должны быть такими. Хотя, возможно, в случае с GUI будет желание сделать такую функцию нестатической...

Добавлено позже: возможно, указатель на такую функцию "человеческому" игроку лучше передать при его создании. Всё равно, методы создания разных игроков будут отличаться.
87
28 декабря 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: Alex57
Некоторые соображения по поводу реализации игры.



Замечания:
1. Думаю, потоки не нужны пока в этой игре.
2. Не показано то, что за одного игрока будет отвечать пользователь.
3. Не ясно, почему игроки не спрятаны в ведущем (или объекте Игра) - они же вне его нигде не используются.
4. Немного нейминг корявый - мешанина транслита с английским. Лучше всё на английский попытаться перевести.

Подход к функциям Ведущего (крупье) мне нравится.

12K
28 декабря 2009 года
Ghox
297 / / 26.07.2009
Цитата: Kogrom
Наверное, так и хорошо. Можно вообще сделать так, чтобы игрок не знал, что из себя представляет интерфейс. Например, так:

Тут передаваемая функция является статической, но вроде бы у класса интерфейса все функции должны быть такими. Хотя, возможно, в случае с GUI будет желание сделать такую функцию нестатической...

Добавлено позже: возможно, указатель на такую функцию "человеческому" игроку лучше передать при его создании. Всё равно, методы создания разных игроков будут отличаться.


Вот, ИМХО отличный вариант. Как говорится, и волки сыты, и овцы целы: объект игрок теперь ничего не знает про интерфейс - имеет дело с объектом-ведущим и указателем на некую функцию подтверждения хода, о устройстве которой ничего не знает; и полиморфизм сохраняется. Я за.

И тогда для класса игрок-человек можно просто добавить переменную - указатель на эту функцию, который будет специфичной переменной для данного класса, и которой не будет в базовом абстрактном классе и классе игрок-бот. И в конструкторе класса "игрок-человек" будет входным аргументом указатель на эту функцию. Как-то так:

Код:
class HumanPlayer : public Player
{
    bool (*confirmFunc)();
public:
    HumanPlayer(bool (*func)());
    // ...
};

HumanPlayer::HumanPlayer(bool (*func)()) : Player("user player"), confirmFunc(func) {}

// ...

Game::Game() : turnsPassed(0)
{
        players[0].first = new RobotPlayer;
        players[0].second = 0;
        players[1].first = new HumanPlayer(Interface::GetConfirmation);
        players[1].second = 0;
}
12K
09 января 2010 года
Ghox
297 / / 26.07.2009
Что-то в теме никто давно не отписывался... Попробую что-нибудь еще написать.

Решил немного пересмотреть схему реализации кости.
Думаю, класс кость должен иметь переменную, которая будет хранить, сколько очков выпало после последнего броска (если бросков еще не было, то какое-то специальное значение). И должен быть, помимо функции - броска кости, также и метод получения предыдущего выпавшего значения.
Код:
class Dice
{
    static const unsigned int nullValue = 1000;
    const unsigned int facets;
    unsigned int lastPoints;
public:
    Dice(unsigned int = 6);
    unsigned int Roll();
    unsigned int GetLastPoints() const;
};

Dice::Dice(unsigned int f) : facets(f), lastPoints(nullValue)
{
    if(facets < 2 || facets > 20)
    {
        cerr << "Dice facets quantity out of range\n";
        exit(1);
    }
}

unsigned int Dice::Roll()
{
    srand((unsigned int)time(0));
    lastPoints = rand() % facets + 1;
    return lastPoints;
}

unsigned int Dice::GetLastPoints() const
{
    if(lastPoints == nullValue)
    {
        cerr << "Attempt to get value from dice without rolling\n";
        exit(1);
    }
    return lastPoints;
}

Также решил пересмотреть реализацию игроков. Метод бросания кости (makeTurn) решил разделить на функции начала хода, продолжения хода, и завершения хода. Пример реализации:
Код:
class Player
{
    const string name;
protected:
    unsigned int totalPoints;
    unsigned int currentPoints;
    unsigned int turnsPassed;
public:
    Player(const string&);
    virtual ~Player();
    virtual void beginTurn(Dice*, unsigned int);
    virtual bool continueTurn(Dice*) = 0;
    void endTurn(bool);
    string announce();
};

Player::Player(const string& str) :
                name(str), totalPoints(0), currentPoints(0), otherPartyPoints(0), turnsPassed(0) {}

Player::~Player() {}

void Player::beginTurn(Dice* pDice, unsigned int)
{
    currentPoints = pDice->Roll();
}

void Player::endTurn(bool isSuccess)
{
    if(isSuccess)
        totalPoints += currentPoints;
    ++turnsPassed;
}

class HumanPlayer : public Player
{
    bool (*confirmFunc)();
public:
    HumanPlayer(bool (*func)());
    virtual bool continueTurn(Dice*);
}

HumanPlayer::HumanPlayer(bool (*func)()) : Player("user player"), confirmFunc(func) {}

bool HumanPlayer::continueTurn(Dice* pDice)
{
    bool result = confirmFunc();
    if(result)
        currentPoints += pDice->Roll();
    return result;
}

class RobotPlayer : public Player
{
    unsigned int otherPartyPoints;
    unsigned int rollsCount;
    unsigned int upRollsCount;
    unsigned int upPoints;
public:
    RobotPlayer();
    virtual void beginTurn(Dice*, unsigned int);
    virtual bool continueTurn(Dice*);
};

RobotPlayer::RobotPlayer() : Player("computer player") {}

void RobotPlayer::beginTurn(Dice* pDice, unsigned int oPPoints)
{
    otherPartyPoints = oPPoints;
    currentPoints = pDice->Roll();
    rollsCount = 1;
    int diffPoints = (int)otherPartyPoints - (int)totalPoints;
    upPoints = diffPoints > 0 ? (unsigned int)diffPoints : 0;
    if(diffPoints > 80)
        upRollsCount = 12;
    else if(diffPoints > 60)
        upRollsCount = 10;
    else if(diffPoints > 40)
        upRollsCount = 8;
    else if(diffPoints > 20)
        upRollsCount = 6;
    else if(diffPoints > 0)
        upRollsCount = 4;
    else
        upRollsCount = 2;
}

bool RobotPlayer::continueTurn(Dice* pDice)
{
    bool result = !(rollsCount >= upRollsCount || currentPoints >= upPoints);
    if(result)
        currentPoints += pDice->Roll();
    return result;
}


Итого предлагаю следующую схема реализации объектов-игроков и их взаимодействия с объектом-ведущий.

Абстрактный класс Player, содержит:
- переменные:
количество очков, накопленное до начала хода;
суммарное количество очков, накопленных за текущий ход;
- функции (помимо конструктора и деструктора):
функция начала хода, принимает аргумент - указатель на объект-кость, выполняет один бросок;
функция принятия решения о том, следует ли продолжать броски дальше - чисто виртуальная функция (будет определена своя для каждой реализации игрока);
функция окончания хода, принимает булевскую переменную (от ведущего) - сгорели ли очки или нет, если не сгорели, то суммирует набранные за ход очки к накопленным.

Класс игрок-человек наследуется от Player, имеет в своем составе переменную - указатель на функцию для подтверждения извне о том что нужно совершить ход, значение указателя передается объектом-ведущим при инициализации объекта игрок-человек.

Класс игрок-бот также наследуется от Player, имеет переменные: количество очков противника, и специальные переменные, которые используются в функции - принятие решения, стоит ли сделать, по предложению ведущего, еще один бросок, или стоит остановиться. В приведенном мной выше примере - это переменные upRollsCount и upPoints.

Взаимодействие ведущего с игроками:
Перед игрой ведущий создает (с помощью new например) объект-кость.
Порядок совершения хода:
Ведущий выбирает объект - игрок который совершает ход.
Выводит в интерфейс информацию о том, что ходит такой-то игрок
Вызывает для этого объекта функцию начала хода. В функции происходит бросок кости.
Далее в цикле:
Ведущий проверяет, сколько выпало очков:
- Если выпала единица, то сообщает игроку что у него все очки сгорели и что ход передается другому игроку, выход из цикла.
- Если выпало > 1, то ведущий предлагает игроку еще раз бросить кость:
Если игрок бросает еще раз, то возврат на начало цикла;
Если игрок решил остановиться, то ведущий суммирует к очкам данного игрока, которые он (ведущий) хранит у себя, выпавшие за ход очки.
Выход из цикла.
После совершения хода проверяется, набрал ли игрок 100 очков. Если набрал, то игрок объявляется победителем. Если не набрал, то ход передается другому игроку.

Вопрос того, как должен быть реализован ведущий (какая должна быть структура, какие функции у него должны быть), пока не затрагиваю (за исключением описанного алгоритма взаимодействия ведущего с игроками). Также пока не касаюсь других поставленных в ТЗ задач (например, вывода в лог).
87
09 января 2010 года
Kogrom
2.7K / / 02.02.2008
Цитата: Ghox
Что-то в теме никто давно не отписывался... Попробую что-нибудь еще написать.



Спасибо, что восстановил тему. Я сам её думал восстановить после 10-го когда каникулы закончатся. Но раз интерес появился раньше, то и я приму участие.

Посмотрев на предложения, понял, что немного сбил с толку людей неясностью требований к коду. А они должны быть примерно такие:

1. Ясность, читаемость.
2. Отсутствие дублирования. Или хотя бы стремление к нему.
3. Обоснование решений с помощью шаблонов GRASP.
4. Дополнительное, но не обязательное условие - использование правил рефакторинга.

Так вот, я критиковал код за использование числа 6 - так как это было использованием магического числа. То есть, нарушало читаемость.

Но зачем же поименовав константу мы пытаемся сразу навесить на неё кучу функций (присвоение числа граней в конструкторе)? А нужны ли они пользователю? Навесить функции и сможем и позже. Сейчас надо собрать просто что-то рабочее.

Далее. Ведущий у нас получается очень жадным. Он вмешивается в игру, он знает о существовании кости и даже создаёт её. Более того, из-за его жадности приходится в кость добавить неочевидную функцию, которая отдаляет её от предметной области.

Если бы он не "жадничал", то его роль была бы примерно такая:
1. Заставляем игрока бросить кость, заодно считывая его желание бросить ещё раз.
2. Считываем данные игрока и выводим на экран.
3. Если было желание сделать ещё ход, то переходим к пункту 1, иначе выдаем соответствующее сообщение на экран и переходим к другому игроку.

Игроки же являются программными классами - можно сделать их такими, чтобы они не обманывали ведущего. Возможно, игрок может даже сообщить, что выиграл. Хотя тут я не уверен.

12K
13 февраля 2010 года
Ghox
297 / / 26.07.2009
Привычка доводить начатое дело до конца побуждает меня вернуться к обсуждению данной темы, хотя возможно про нее все ее участники (Kogrom, kooder) уже забыли. Поэтому хочу попытаться хотя бы выяснить, возможно ли продолжение данного проекта. И возможно ли мое в нем участие. Это я говорю потому, что теоретическими знаниями в области проектирования программ (в частности, насчет использования шаблонов Grasp) почти не обладаю, и подробно изучать данную теорию в мои планы пока не входит. Так что если Kogrom ожидает, что от всех участников требуется наличие приличных знаний теории проектирования, то буду вынужден сказать, что я пас. :)
Цитата: Kogrom
Посмотрев на предложения, понял, что немного сбил с толку людей неясностью требований к коду. А они должны быть примерно такие:

1. Ясность, читаемость.
2. Отсутствие дублирования. Или хотя бы стремление к нему.
3. Обоснование решений с помощью шаблонов GRASP.
4. Дополнительное, но не обязательное условие - использование правил рефакторинга.


Против требований не возражаю, но думаю что рассматривать их надо будет на этапе кодинга, до которого дело еще не дошло. Хочу заметить, что тот код что я приводил в предыдущих сообщениях - это лишь примеры, поясняющие предлагаемую мной схему взаимодействия объектов. Сейчас пока у нас пока этап проектирования, я так понимаю...

Цитата: Kogrom
Так вот, я критиковал код за использование числа 6 - так как это было использованием магического числа. То есть, нарушало читаемость.

Но зачем же поименовав константу мы пытаемся сразу навесить на неё кучу функций (присвоение числа граней в конструкторе)? А нужны ли они пользователю? Навесить функции и сможем и позже. Сейчас надо собрать просто что-то рабочее.


На мой взгляд, это уже на этапе самого кодирования надо будет обсуждать. Сейчас пока достаточно описать в общих чертах объект "кость" (наряду с другими объетами), а будут ли в нем магические числа или нет - оставить на потом.

Цитата: Kogrom
Далее. Ведущий у нас получается очень жадным. Он вмешивается в игру, он знает о существовании кости и даже создаёт её. Более того, из-за его жадности приходится в кость добавить неочевидную функцию, которая отдаляет её от предметной области.

Если бы он не "жадничал", то его роль была бы примерно такая:
1. Заставляем игрока бросить кость, заодно считывая его желание бросить ещё раз.
2. Считываем данные игрока и выводим на экран.
3. Если было желание сделать ещё ход, то переходим к пункту 1, иначе выдаем соответствующее сообщение на экран и переходим к другому игроку.

Игроки же являются программными классами - можно сделать их такими, чтобы они не обманывали ведущего. Возможно, игрок может даже сообщить, что выиграл. Хотя тут я не уверен.


Итого, вырисовываются два разных варианта - в плане того, в каких объектах будет контролироваться выполнение игроками правил игры:
1. Вариант Kogrom'а: контроль выполнения правил игры возлагается на объекты, представляющие игроков.
2. Мой вариант: контроль выполнения правил игры возлагается на ведущего. Этот вариант описан в моем предыдущем сообщении, и вызвал замечания Kogrom'а по отдельным моментам предложенной схемы, которые являются следствием того, что контроль осуществляет ведущий - отсюда его "жадность" и т.д..

Честно говоря, не нашел серъезных аргументов в пользу своего варианта. Поэтому согласен на вариант Kogrom'а, соответственно то что я писал выше (предложенная мной схема объектов) - отменяется (в силу того что было завязано на контроль правил в ведущем), надо прорабатывать другую схему.

87
14 февраля 2010 года
Kogrom
2.7K / / 02.02.2008
Цитата: Ghox
Привычка доводить начатое дело до конца побуждает меня вернуться к обсуждению данной темы, хотя возможно про нее все ее участники (Kogrom, kooder) уже забыли.


Очень рад. Этот проект затевался как групповая работа, как проект для общения, в котором главное процесс разработки. Поэтому я его не стал в одиночку продолжать.

Цитата: Ghox
Поэтому хочу попытаться хотя бы выяснить, возможно ли продолжение данного проекта. И возможно ли мое в нем участие.


Конечно возможно.

Цитата: Ghox
Это я говорю потому, что теоретическими знаниями в области проектирования программ (в частности, насчет использования шаблонов Grasp) почти не обладаю, и подробно изучать данную теорию в мои планы пока не входит.


Ну, Grasp - это не GoF, в них всё примитивно и понятно каждому программисту, знакомому с ООП, но немного систематизировано.

Например, если у нас есть объекты: игральная доска, клетка (элемент игральной доски) и собака, то использование собаки для создания клеток - не лучшая идея, так как порождает ненужные связи. Лучше, чтобы клетки создавала сама доска, так как она будет их использовать. Вот приблизительный смысл шаблона Creator (Производитель).

Примерно такие же сложные и все остальные шаблоны. Однако, проще понять друг друга, если использовать какую-то известную терминологию.

Цитата: Ghox
Против требований не возражаю, но думаю что рассматривать их надо будет на этапе кодинга...



Ну, сейчас принято не делить на такие этапы. Например, в RUP используется такая схема:
http://upload.wikimedia.org/wikipedia/ru/d/da/RUP_process.png
то есть, проектирование и кодинг идут параллельно.

Тем более ясность, перестройка и отсутствие дублирования и в проектировании используется.

К делу. Если берёмся делать что-то, то надо внести хоть какой-то ритм. Например, очерёдность сообщений от участников, лимит времени между сообщениями и т.д. То есть участники должны как минимум подавать признаки того, что они в проекте, делиться мыслями, черновиками, намерениями.

Ок. Ваш ход. Ожидаю какие-то предложения по очередности ходов, по лимиту времени и т.д.

12K
14 февраля 2010 года
Ghox
297 / / 26.07.2009
Цитата: Kogrom
Ну, Grasp - это не GoF, в них всё примитивно и понятно каждому программисту, знакомому с ООП, но немного систематизировано.


Почитал про GRASP в Википедии. На первый взгляд - да, то что написано - вроде просто и понятно... Но непонятно (за исключением совсем уже простых примеров, аналогично приведенному тобой ниже), например, как эти шаблоны правильно использовать в реальных проектах. Нужно изучение способов применения этих шаблонов, а также разбор одного или нескольких примеров их использования, а это уже есть составляющие той самой теории проектирования, на изучение которой требуется время.

Конечно можно пытаться использовать эти шаблоны при обосновании своих решений и без полного понимания как их правильно использовать, но такие обоснования рискуют оказаться всего лишь какой-то софистикой...

Цитата: Kogrom
Например, если у нас есть объекты: игральная доска, клетка (элемент игральной доски) и собака, то использование собаки для создания клеток - не лучшая идея, так как порождает ненужные связи. Лучше, чтобы клетки создавала сама доска, так как она будет их использовать. Вот приблизительный смысл шаблона Creator (Производитель).


Пример надуманный, в реальном проекте все не так просто. Как я понял, лежащий в основе шаблона Creator тезис таков: "Создателем каждого конкретного объекта должен выступать тот объект, который его будет потом использовать". Тогда возникают вопросы, например, такие. А что, если создаваемый объект будут использовать несколько объектов - какой из них тогда назначать создателем? И что понимать под "использованием объекта A другим объектом B" - только ли обращение внутри функций объекта B к объекту A напрямую, или также и другие виды взаимодействия объектов (например объект B хранит переменную - ссылку на какую-то переменную объекта A; опосредованное использование - объект B использует объект C, который использует объект A)? Это лишь навскидку, при желании можно и много других вопросов задать, для нахождения ответов на которые нужно изучать теорию.

Цитата: Kogrom
Примерно такие же сложные и все остальные шаблоны. Однако, проще понять друг друга, если использовать какую-то известную терминологию.


Насчет кажущейся простоты я сказал выше. Насчет использования известной терминологии: то что при ее использовании собеседникам проще понять друг друга справедливо, ИМХО, только лишь в случае, когда все собеседники эту самую терминологию в полной мере понимают. А я в данном случае понимаю далеко не все, часть того что не понимаю - описал выше.

Цитата: Kogrom
Ну, сейчас принято не делить на такие этапы. Например, в RUP используется такая схема:
http://upload.wikimedia.org/wikipedia/ru/d/da/RUP_process.png
то есть, проектирование и кодинг идут параллельно.


Как я понял, не совсем так. Этапы могут пересекаться по времени (и обычно пересекаются), но основная часть разных этапов проходит в разное время и не пересекается. В случае этапов проектирования и кодинга. Сначала проходит основной этап проектирования, на котором вырабатывается основа архитектуры программы, которая должна быть реализована проектом, структура объектов и их взаимоотношений. В итоге получается некоторая принципиальная схема, в соответствии с которой должна вестись разработка проекта, и которая (схема) уже не будет как-то значитально меняться, меняться могут только детали, но в основе своей она должна оставаться неизменной (за исключением случая, когда при дальнейшей разработке выясняется, что реализация невозможна без значительной переделки основной схемы, что говорит о том, что проектирование проведено неправильно). Далее начинается этап кодинга, на котором проектирование также продолжается, но теперь оно заключается только в незначительных доработках и внесении уточнений в спроектированную до этого схему.

У нас же сейчас получается, что проектирование и кодинг идут одновременно, что я считаю неправильно. Считаю что нужно сначала выработать основную схему, потом уже переходить к кодингу, попутно с которым уточнять и детализировать, и в незначительной степени менять схему.

Но в сказанном выше я лишь изложил свое понимание того, что там написано, может быть, на самом деле что-то и не так, конечно...

Цитата: Kogrom
К делу. Если берёмся делать что-то, то надо внести хоть какой-то ритм. Например, очерёдность сообщений от участников, лимит времени между сообщениями и т.д. То есть участники должны как минимум подавать признаки того, что они в проекте, делиться мыслями, черновиками, намерениями.


На этот счет у меня такие мысли...

Думаю, на каждый момент работы над проектом должен быть некоторый план работ на ближайшее время - список элементарных задач, каждая из которых может быть выполнена, без затрат значительного времени и усилий, одним участником. В каждой из задач, перед тем как она может быть кому-то поручена, должна быть четко сформулированная постановка, и требования к результату выполнения задачи.

После формулировки задачи один или несколько участников проекта заявляют о своем желании выполнить эту задачу, называя сроки, сроков предлагаю называть два: один - ориентировочный средний срок, т.е. за какое количество дней участник, как он сам думает, скорее всего сделает задачу, второй - максимальный срок (на случай когда все нет времени, или время есть да что-то не тянет, и т.д.). Если желающих выполнить одну и ту же задачу - несколько, то руководитель проекта (в данном случае - Kogrom) выбирает одного из них, впрочем наверно можно дать возможность сделать одну и ту же задачу нескольким исполнителям, после чего сравнить результаты и в результате обсуждения, выбрать вариант который представляется лучшим.

После того как исполнитель выполняет задачу, он предоставляет полученные результаты на обсуждение (сделать он это должен в заявленные им сроки), по результатам обсуждения задача либо считается как выполненная, либо, при наличии замечаний, отправляется на доработку (которая может быть поручена другому исполнителю).

Примеры таких элементарных задач:

  • Кодирование классов, представляющих "игроков". Постановка: <описание что должен делать класс>, результат: готовый код классов.
  • Кодирование класса "Ведущий", постановка и результат - аналогично.

Еще насчет ритма. Как я предложил выше, каждый участник сам должен выбирать срок за который он сделает задачу, за которую берется, но при этом все-таки думаю надо назначить максимальный допустимый срок. В качестве этого срока предлагаю взять неделю. Если при какой-то элементарной задаче выяснится, что ни один из участников не готов ее сделать за указанное максимальное время, то это может означать или то, что это время нужно увеличить, или то что элементарная задача должна быть разделена на более элементарные задачи.

Так же думаю, что было бы полезно всем реальным и потенциальным (тот кто готов сказать "я бы может и присоединился но пока точно не знаю") участникам проекта сообщить, в какой роли / ролях они желают (хотели бы) / имеют возможность участвовать в проекте. Это помогло бы руководителю проекта и другим участникам понять, какого участия можно ожидать от каждого участника, и ориентироваться на это при составлении планов, выделении элементарных задач и т.д. Со своей стороны скажу, что ожидаю свое участие в качестве: проектировщика (в ограниченном объеме, т.к. далеко не все знаю), кодера, ну и тестировщика.
Цитата: Kogrom
Ок. Ваш ход. Ожидаю какие-то предложения по очередности ходов, по лимиту времени и т.д.


Итак, свои мысли высказал. Если мое предложение насчет планирования и выделения элементарных задач принимается, то собственно нужно выделить на ближайшее время элементарную задачу (задачи), и выбрать исполнителей. Напрашивается задача "Создание базовой схемы классов программы и их взаимодействия" (или как-то так), но возможно что задача не совсем элементарная и надо ее декомпозировать...

P.S. Но это еще не все, хотелось бы еще кое-что добавить, но это уже не раньше чем завтра. Пока предлагаю к обсуждению написанное в данном посте, может потом что-то еще дополню.

87
14 февраля 2010 года
Kogrom
2.7K / / 02.02.2008
Цитата: Ghox
Как я предложил выше, каждый участник сам должен выбирать срок за который он сделает задачу, за которую берется, но при этом все-таки думаю надо назначить максимальный допустимый срок. В качестве этого срока предлагаю взять неделю.


Ок. Вводим срок итерации - неделя. Хотя, подозреваю, что верный срок - две недели. В конце каждой итерации я буду подводить итоги (если будет доступ в Интернет, конечно). Если две итерации подряд в теме будут только мои сообщения, то проект будет заморожен.

Ещё можно попробовать использовать такие правила:
http://forum.codenet.ru/showpost.php?p=298331&postcount=50

Цитата: Ghox
Напрашивается задача "Создание базовой схемы классов программы и их взаимодействия" (или как-то так), но возможно что задача не совсем элементарная и надо ее декомпозировать...



Ок. Делаем черновик базовой схемы классов программы. Желательно, чтобы сопровождалось хоть какой-то графической схемой.

12K
15 февраля 2010 года
Ghox
297 / / 26.07.2009
Цитата: Kogrom
Ок. Вводим срок итерации - неделя. Хотя, подозреваю, что верный срок - две недели. В конце каждой итерации я буду подводить итоги (если будет доступ в Интернет, конечно). Если две итерации подряд в теме будут только мои сообщения, то проект будет заморожен.


Вполне согласен, нормальное требование чтобы избежать нахождения проекта в подвисшем состоянии.

Цитата: Kogrom
Ещё можно попробовать использовать такие правила:
http://forum.codenet.ru/showpost.php?p=298331&postcount=50


Хм... мне кажется что не получится их здесь использовать в том виде, в каком они там описаны... В тех правилах в каждой итерации присутствует проектирование, у нас же проектирование будет только вначале... Впрочем, для некоторых классов тоже можно выделить отдельный этап проектирования...

Цитата: Kogrom
Ок. Делаем черновик базовой схемы классов программы. Желательно, чтобы сопровождалось хоть какой-то графической схемой.


Итак, первая задача: черновик базовой схемы классов программы. Предлагаю немного детализировать описание задачи, описав требуемый результат. В итоге должно получиться:

  • Перечень классов, которые должны присутствовать в программе.
  • Описание взаимодействия классов между собою в процессе выполняемой при работе программы имитации игры в кости (кто выступает создателем объектов каждого класса, какой информацией обмениваются объекты в ходе работы программы и т.д.).
  • Внутреннее устройство классов пока разрабатывать не требуется. Например, для класса "кость" (если такой будет) пока не требуется определять, как именно внутри объекта кость будет получаться выдаваемое костью значение. Также как и для класса "игрок-бот" - пока не требуется разрабатывать алгоритм стратегии игры бота, достаточно указать что такой алгоритм должен быть.

Попытаюсь выполнить данную задачу, примерный срок называю - 4 дня (начиная с сегодняшнего), максимальный - 6 дней. Т.е. ориентировочно - в четверг вечером, в крайнем случае - до наступления воскресенья, от меня можно ожидать результата. При выполнении задачи попытаюсь использовать шаблоны GRASP, но не знаю насколько хорошо это у меня получится...

Если найду время - нарисую и схему.

Есть кстати предложение Kogrom'у самому также попытаться выполнить эту задачу, чтобы продемонстрировать, как можно испоьзовать шаблоны GRASP для данного проекта. Но предоставлять свои результаты лучше только после того, как я предоставлю свои. Потом сравнить, у кого что получилось.
87
15 февраля 2010 года
Kogrom
2.7K / / 02.02.2008
Ок.

Цитата: Ghox
Есть кстати предложение Kogrom'у самому также попытаться выполнить эту задачу, чтобы продемонстрировать, как можно использовать шаблоны GRASP для данного проекта.


Попытаюсь. Возможно, для себя проверю не только полезность GRASP, но и других эээ... технологий.

Небольшая просьба: Ghox, постарайся писать сообщения чуть более лаконично.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог