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

Ваш аккаунт

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

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

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

Игра в кости

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

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

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

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

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

Как идея? Найдутся желающие?
Страницы:
87
12 апреля 2010 года
Kogrom
2.7K / / 02.02.2008
Цитата: Нездешний
Ага, участник Нездешний отклонился от линии партии :D В частности потому, что линию партии в данном треде отыскать весьма тяжело. "Многабукаф", "ниасилил" и все такое :) .


Ну, наверное надо какой-то документик оформить, в котором она была бы отражена. Пока не придумал, как это оформить, где хранить.

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

Цитата: Нездешний
Стремление "и тебя сосчитать" - всех распределить по заказчикам-советникам-программистам-исполнителям-надсмотрщикам-ипрочимтипам тоже несколько пугает :)


Может и пугает. Но бардак пугает больше. Предложи какую-то организацию, если есть идеи.

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

Цитата: Нездешний
А чем он так уж концептуально отличается от вывода в вид?


Если он не отличается, то почему в твоём новом варианте они не являются наследниками одного предка? Ну и потом, "концептуально" - слово которое можно интерпретировать как угодно. Например, в логе желательно сохранять больше данных, чем выводим в консольный вид.

И наконец, немного спорное утверждение. Мы делаем игру, а не систему управления или сервер. Поэтому тут лог должен сохраняться по желанию пользователя, если игра была интересная. То есть он сохраняется в конце игры, а не по ходу её.

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

То же на счет делегатов. Зачем оно тут, в этой игрушке? Нужен конкретный пример, как оно поможет. А лучше несколько примеров (так как читаемость важнее навороченной гибкости, так как, думаю, большую гибкость даёт именно читаемость).

253
12 апреля 2010 года
Proger_XP
1.5K / / 07.08.2004
Многобуков - это слабо сказано. Я попытался просмотреть тему, но в печатном виде это добрые 100 страниц о_О
535
12 апреля 2010 года
Нездешний
537 / / 17.01.2008
[QUOTE=Kogrom]Поэтому тут лог должен сохраняться по желанию пользователя, если игра была интересная. То есть он сохраняется в конце игры, а не по ходу её.[/QUOTE]Промежуточно, перед сохранением лога все равно данные придется где-то хранить. Почему бы тогда не делать это по ходу игры, а в конце удалить лог, если он не нужен.

[QUOTE=Kogrom]Не совсем ясно, зачем нужны контейнеры с видами и логами[/QUOTE]согласен, контейнеры можно убрать

[QUOTE=Kogrom]на счет делегатов. Зачем оно тут[/QUOTE]Указатель на метод абстрактного класса (IView::GetUserDecision) как-то c ходу не удалось объявить ;)
87
12 апреля 2010 года
Kogrom
2.7K / / 02.02.2008
Цитата: Proger_XP
Многобуков - это слабо сказано. Я попытался просмотреть тему, но в печатном виде это добрые 100 страниц о_О


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

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


А почему нельзя хранить данные лога в виде какого-нибудь объекта в ОЗУ?

Цитата: Нездешний
Указатель на метод абстрактного класса (IView::GetUserDecision) как-то c ходу не удалось объявить ;)


Зачем на метод? Можно сделать указатель на объект. Если упрощенно, то как-то так:

Код:
struct IGetResult
{
    virtual bool Get() = 0;
};

class GetResult: public IGetResult
{
public:
    bool Get() {return StaticGet();}

private:
    static bool StaticGet()
    {
        char res = 'n';
        cout << "y/n? ";
        cin >> res;
        return (res == 'y');
    }
};

int main()
{
    IGetResult *getter = new GetResult();
    cout << getter->Get();

    return 0;
}


Ну, можно для красоты оператор () перегрузить.
Извините за корявый нейминг...
535
12 апреля 2010 года
Нездешний
537 / / 17.01.2008
[QUOTE=Kogrom]А почему нельзя хранить данные лога в виде какого-нибудь объекта в ОЗУ?[/QUOTE]Да можно, почему нет. Просто для меня интересны именно взаимосвязи между сущностями. Конкретное устройство того же лога - дело техники

[QUOTE=Kogrom]Зачем на метод? Можно сделать указатель на объект.[/QUOTE]А зачем здесь функтор? Помнится, кто-то критиковал класс ради одной функции (Dice) несколькими постами ранее ;) Да и тем самым разобьем вид. Если уж избавляться от делегатов, то просто передать классу THumanStrategy указатель на весь интерфейс вида IView
87
12 апреля 2010 года
Kogrom
2.7K / / 02.02.2008
Цитата: Нездешний
Да можно, почему нет. Просто для меня интересны именно взаимосвязи между сущностями. Конкретное устройство того же лога - дело техники


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

Эта сущность нужна для того, чтобы игроки (особенно, компьютерные) могли на её основе вырабатывать стратегию.

У тебя она есть в неявном виде, разорванная на куски.

Цитата: Нездешний
А зачем здесь функтор? Помнится, кто-то критиковал класс ради одной функции (Dice) несколькими постами ранее ;) Да и тем самым разобьем вид. Если уж избавляться от делегатов, то просто передать классу THumanStrategy указатель на весь интерфейс вида IView


Это и есть передача указателя на интерфейс, а не функтор. Идея тут в том, что мы отрываемся от статической функции, а не в использовании алгоритмов STL.

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

253
12 апреля 2010 года
Proger_XP
1.5K / / 07.08.2004
Цитата: Kogrom
Значит надо составить какой-то обновляемый документик. По науке нужно что-то типа wiki. Не по науке можно делать какую-нибудь pdf-ку и выкладывать её по определенному адресу (например, можно для этого использовать проект на гугле, который остался от первого Учебного проекта).


Хм, будем считать это намёком. Если будет время, попробую прочитать всё написанное, может сбацаю документ.

87
16 апреля 2010 года
Kogrom
2.7K / / 02.02.2008
Накатал 3 документа на тему "Основная линия партии". В общем, это черновики, и сделаны большей частью методом "скопировать-вставить".

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

2-й документ (DiceTZ) - ТЗ.
3-й документ (DiceNow) - текущее состояние.
253
25 апреля 2010 года
Proger_XP
1.5K / / 07.08.2004
Накидал общую схему по докам (спасибо, Kogrom, так значительно проще :)) + своим соображениям, можно обсудить (коли проект ещё жив, конечно).
87
25 апреля 2010 года
Kogrom
2.7K / / 02.02.2008
Цитата: Proger_XP
можно обсудить (коли проект ещё жив, конечно).



Не очень удобно цитировать из картинки, а программу для чтения карты мне ставить лень. Хотя карта типа xml, но надо ещё текст расшифровывать...

Ладно. Без цитат.

1. На счет выделения главной строки в отдельную переменную. Пока не понял аргументацию. Что мешает объекту, который записывает лог, читать и упорядочивать данные из таблицы как он пожелает?

2. Не вместо страниц ссылки на игроков, а вместо идентификаторов ссылки. Но тоже не совсем тут однозначно. У обоих подходов есть свои плюсы и минусы.

3. Может и правильно, что Ведущий (Игра) контролирует выигрыш. Но, мне думается, что лучше выделить отдельный контроллер правил. У меня он пока что наследуется от таблицы, но не обязательно делать так.

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

253
26 апреля 2010 года
Proger_XP
1.5K / / 07.08.2004
Цитата:
Не очень удобно цитировать из картинки, а программу для чтения карты мне ставить лень.


Это FreeMind, portable-верию можно взять отсюда (рабочая, проверял).

Цитата:
На счет выделения главной строки в отдельную переменную.


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

Строки мне представляются двумерным массивом типа:

 
Код:
array of record  // ход игрока.
  player: TPlayer;
  total: word;  // сумма очков за весь ход, хотя по идее её всегда можно посчитать, когда нужно.
  points: array of byte; // конкретные очки, которые он выбросил.
end;

Плюс к Таблице добавляется поле с количеством очков, набранным каждым Игроком: array of { player: TPlayer; total: dword; }.

Главная строка, как я её понял, получается разнесённой между этими двумя полями.

Цитата:
Не вместо страниц ссылки на игроков, а вместо идентификаторов ссылки.


А, да. Просто где-то в доках проскакивало то, что каждый Игрок имеет свою Таблицу. Моя идея в том, чтоТаблица - одна на один объект Игры, и имеет такие поля:

 
Код:
Turns: array of ..;. // см. описание двумерного массива ходов выше.
  Total: array of ...; // см. сумму очков по игроку.

  CurrentTurn: record  // либо текущее состояние игры, если игра ещё идёт, либо последний ход (= выигрыш кого-то), если игра закончилась.
    TotalTurns: word; // количество ходов за всю игру от всех игроков.
    Player: TPlayer; // тот, кто сейчас ходит или тот, кто выиграл.
    Index: word;  // индекс строки в массиве Turns: [Player] [Index]. можно сделать указателем, дабы удобнее было обращаться сразу к записи.
  end;


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

Цитата:
...Но, мне думается, что лучше выделить отдельный контроллер правил


У меня это тоже отдельный объект ("для этого можно иметь наследуемый private-объект"), правда, он ни от чего не наследуется - его задача в простейшем случае выдать True/False, например:

 
Код:
// NIL - пока нет победителя, иначе объект выигравшего Игрока.
function TRules.WhoHasWon(Table: TTable): TPlayer;
begin
  LastTurn := Table.Turns[ Table.CurrentTurn.Player ][ Table.CurrentTurn.Index ];
  if LastTurn.Total >= 100 then
    Result := LastTurn.Player
    else
      Result := NIL;
end;


Здесь я возвращаю победителя, а не просто T/F, дабы правила могли быть и обратными, например: побеждает тот, кто продержится с наименьшим количеством очков всю игру.
Таким образом, правила можно полностью вынести из объекта Игры.

По поводу самого объекта Игра. Мне он представляется так (упрощённо, конечно):
Код:
TGame = type
  Rules: TRules;  
  Table: TTable;
  Players: array of TPlayer;
end;      
    ...
// пока будем считать, что к вызову Start() массив Игроков синхронизирован с массивом Turns и до. в Таблице.
procedure TGame.Start;
begin
  while True do
  begin
    Winner := Rules.WhoHasWon(Table);
    if Winner = NIL then
    begin
      Table.NewRound;
      // по Правилам, конец хода тогда, когда Игрок выкинул 1
      while True do
      begin
        TurnState := Rules.TurnState(Table.CurrentTurn);
        case TurnState of
          tsPlayerEnd:  Table.EndLastTurn;
          tsLostTurn:   Table.LastTurnLost; // Игрок выкинул 1.
          tsContinue:   Table.RecordTurn( Players[Table.CUrrentTurn.Player].Turn );
        end;
      end;
    end
      else
        // выигрыш
        ...
  end;
end;


Цитата:
На счёт того, жив ли проект. Он странный какой-то. То вспыхнет, то погаснет.


Ну да, я заметил :) Будем оживлять.

87
26 апреля 2010 года
Kogrom
2.7K / / 02.02.2008
Ладно. Надо договориться о каких-то принципах, какой-то терминологии. Я пытаюсь применять это:
http://ru.wikipedia.org/wiki/GRASP

Особенно меня интересуют шаблоны Low Coupling (Слабая связанность) и High Cohesion (Сильное зацепление).

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

Например, мы вытаскиваем таблицу из этой конкретной игры и, не меняя, используем в программе типа упрощенного Excel. Дорого ли нам обойдется такая процедура? А сложно ли использовать класс игрока в другом проекте? А Ведущего (Игру)?

Думаю, в предложенном Proger_XP варианте Таблица слишком много знает об игре. На это указывают имена функций.

Кстати, почему Delphi? Язык, конечно, хороший, я его понимаю (кроме тонкостей), но хочется узнать почему он был выбран для примеров.
253
26 апреля 2010 года
Proger_XP
1.5K / / 07.08.2004
Цитата: Kogrom

Особенно меня интересуют шаблоны Low Coupling (Слабая связанность) и High Cohesion (Сильное зацепление).


Да, я именно про связность и думал в процессе.

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


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

Цитата: Kogrom
Например, мы вытаскиваем таблицу из этой конкретной игры и, не меняя, используем в программе типа упрощенного Excel. Дорого ли нам обойдется такая процедура? А сложно ли использовать класс игрока в другом проекте? А Ведущего (Игру)?


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

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

Цитата: Kogrom
Думаю, в предложенном Proger_XP варианте Таблица слишком много знает об игре. На это указывают имена функций.


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

  • NewRound - просто добавить новый элемент в Turns и Total.
  • EndLastTurn - пока просто увеличивает счётчик ходов на 1.
  • LastTurnLost - просто вычитает ходы и очки в Turns и Total, использую инфу из CurrentTurn.
  • RecordTurn - пока не чётко представляю, что должен возвращать Player.Turn и, соответственно, принимать этот метод, но это может быть просто число выпавших очков. Так что всё, что делает метод - увеличивает счётчик очков и ходов.

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

Цитата: Kogrom
Кстати, почему Delphi? Язык, конечно, хороший, я его понимаю (кроме тонкостей), но хочется узнать почему он был выбран для примеров.


Чисто из субъективных соображений. Я мог бы написать на PHP или Ruby, но по-моему в Delphi ООП видно лучше всего. А Си, даже шарп, мне меньше нравится.

87
26 апреля 2010 года
Kogrom
2.7K / / 02.02.2008
Есть немного недопонимания. Попытаюсь его устранить с помощью картинки. Попытался изобразить, как я представляю себе Таблицу. Возможно, в ней и правда не нужна главная строка - можно обойтись одним числом для общего числа очков одного игрока. Хотя думаю, что главная строка удобнее для восприятия.

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

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