Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> написать приложение похожее на Windows Miner, новичок нид хелп! 
:(
    Опции темы
aMiGo!
  Дата 7.9.2003, 09:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 124
Регистрация: 6.4.2003
Где: Тула

Репутация: нет
Всего: нет



Привет всем!
Есть задача: написать приложение похожее на Windows Miner
Вот кусок задания, в который я никак не вьеду, если не трудно, то разъясните плиз ху есть ху! (основной причиной моего непонимания является последний абзац)
Цитата
Поле игры должно быть отдельным классом, компонентой, контролом. Этот компонент должен содержать события (Delhi, C++ Builder, C#), function pointer (Visual C++) или Listeners (Java) или Visual C++. Иными словами, отделить объект, реализующий минное  поле, от кода основной программы, чтобы получить возможность многократного использования данного класса без изменения его кода.
    Не используйте стандартные классы, такие как Grid или Button для реализации поля игры. Все приведенные языки имеют в своих стандартных библиотеках классы, от которых удобно наследоваться и самим отработать все действия пользователя.

?? Какие еще стандартные классы от которых удобно наследоваться и самим отработать все действия пользователя!
--------------------
With the best regards, Anton
PM MAIL   Вверх
mr.DUDA
Дата 7.9.2003, 10:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 25
Всего: 232



Вроде заказчик хочет компонент COM/ActiveX, с "событиями" и "свойствами", определяющими работу именно самого минного поля, в отрыве от GUI-компонента (Grid, Button и пр.).

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


--------------------
user posted image
PM MAIL WWW   Вверх
RAN
Дата 7.9.2003, 10:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Экс. модератор
Сообщений: 709
Регистрация: 14.3.2003
Где: Щёлково Моск.обл.

Репутация: 5
Всего: 6



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

Можно же было, на окно кнопок набросать и обрабатывать нажатия на них. Я не считаю, что это хорошо. Ресурсов будет жрать неоправдано.
PM MAIL ICQ   Вверх
aMiGo!
Дата 7.9.2003, 11:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 124
Регистрация: 6.4.2003
Где: Тула

Репутация: нет
Всего: нет



Можно плиз по подробнее, как это все реализовать на С++ Builder.

Вот даю полное задание, для дальнейших соображений

Цитата
Создайте приложение похожее на Windows Miner.
Задание может быть выполнено на любом из следующих языков:
Delphi, C++ Builder, Visual C++, Java, C#.

В случае Visual C++ разрешается использование MFC. Запрещается использовать Grid или любой другой подобный класс. В этом задании мы оцениваем качество Вашего кода, поэтому одна из главных Ваших задач – правильно построить внутренний дизайн программы, и сделать код как можно более читабельным  и красивым.
(Читабельный код -  это необязательно код, в котором много комментариев. Хороший код - это грамотно написанный код, где правильно построены классы, продумано взаимодействие между ними. Код, который не содержит повторяющегося текста. Код, из которого понятно, что делают методы Вашей программы. Код, который средний программист, который не писал Ваш код, может понять в течение 20-30 секунд. Хороший код можно легко изменить, чтобы добавить новые возможности, и он останется и т.д).
Разработайте структуру классов, опишите, для чего нужен каждый из них и как классы будут взаимодействовать между собой. Ваш код должен быть таким, чтобы  его можно было легко модифицировать и расширять.

Например, представьте себе, что в будущем Вам потребуется рисовать изображение мин по-другому (например, сделать мины нескольких типов), или изменить логику игры так, чтобы взрыв происходил лишь после 3 ошибки, или так, чтобы при попадании на мину взрыв происходил с вероятностью 1/3. Или, возможно, потребуется изменить способ ввода информации в программу (использовать клавиатуру вместо мыши или, не дай бог, управление голосом  ). 
Не надо реализовывать все эти возможности, просто подумайте заранее о возможности расширения функциональности и заложите её в программу изначально.
Подумайте о том, чтобы сразу обеспечить возможность изменения логики игры, путем наследования нового класса от Вашего класса, отвечающего за логику. Подумайте и о том, чтобы сразу обеспечить возможность внешнего вида игрового поля, путем наследования нового класса от Вашего класса, отвечающего за рисование.
Если Ваша программа спроектирована хорошо, то сделать указанные изменения будет легко.

Рекомендации:

Поле игры должно быть отдельным классом, компонентой, контролом. Этот компонент должен содержать события (Delhi, C++ Builder, C#), function pointer (Visual C++) или Listeners (Java) или Visual C++. Иными словами, отделить объект, реализующий минное  поле, от кода основной программы, чтобы получить возможность многократного использования данного класса без изменения его кода.

Не используйте стандартные классы, такие как Grid или Button для реализации поля игры. Все приведенные языки имеют в своих стандартных библиотеках классы, от которых удобно наследоваться и самим отработать все действия пользователя.

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



--------------------
With the best regards, Anton
PM MAIL   Вверх
RAN
Дата 7.9.2003, 11:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Экс. модератор
Сообщений: 709
Регистрация: 14.3.2003
Где: Щёлково Моск.обл.

Репутация: 5
Всего: 6



Цитата
Не спешите сразу кодировать. Вначале все продумайте и нарисуйте классы и их взаимодействие на бумаге
Золотые слова. Тоже самое тебе хотел сказать.
Думаю, надо создать класс ячейки и класс поля, содержащего эти ячейки.
class TCell;
class TField : TPicture {
CCell* cells;
struct {
unsigned col;
unsigned row;
} size;
.................................
};

И пиши методы для работы с полем и обработчики событий. Но не надо реализовывать в событие OnClick реакцию на нажатие кнопки полность. Надо вызвать метод ячейки, на которой кликнули (TCell::Select). И т.д.
PM MAIL ICQ   Вверх
aMiGo!
Дата 7.9.2003, 12:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 124
Регистрация: 6.4.2003
Где: Тула

Репутация: нет
Всего: нет



Я уже начал писать.. вот зацени плиз RAN чо у меня вышло..

Код
#ifndef TCELL_HPP
#define TCELL_HPP
enum TCellStatus    { csEmpty   = 0x002,   //в клетке пусто
                     csMine    = 0x004}; //в клетке мина!

enum TVisibleStatus { vsClosed  = 0x006,  //клетка Закрыта
                     vsOpen    = 0x008,  //клетка Открыта
                     vsMarked  = 0x00A,  //клетка Помечена
                     vsUnknown = 0x00C,  //клетка Вопрос
                     vsMine    = 0x00E,  //клетка Мина
                     vsMissed  = 0x010,  //клетка Взорванная мина
                     vsDigit1  = 0x012,
                     vsDigit2  = 0x014,
                     vsDigit3  = 0x016,
                     vsDigit4  = 0x018,
                     vsDigit5  = 0x01A,
                     vsDigit6  = 0x01B,
                     vsDigit7  = 0x01C,
                     vsDigit8  = 0x01D };


class TCell;  //TCell

class TField      //Класс поля
{
  public:
     void Init(void);
    ~TField(void);   //деструктор  поля
     TField(int Height, int Width); //конструктор поля игры

     void TField::ClearField();
     TCell** Cells;              //Клетки поля игры
     int uCellsCount;   //Общие количество клеток
     int uMinesCount;   //Количество мин
     int uRowCount;     //Количество Rows
     int uColCount;     //Количество Columns

  private:




};
class TCell //класс клетки
{
  public:                
     int Click( int uX, int uY,bool isMbLeft);
     ~TCell();

      int X;       //координата клетки X
      int Y;       //координата клетки Y
      int cell_Id; //иденфикатор клетки
      int cellDigit;
      TCellStatus CellStatus;
      TVisibleStatus VisibleStatus;

  private:




};
TCell::~TCell()      //деструктор клетки
{
  CellStatus = (TCellStatus)0;
  VisibleStatus = (TVisibleStatus)0;
  X = 0;
  Y = 0;
  cell_Id = 0;
  cellDigit = 0;
 
}
TField::~TField()  //деструктор  поля
{
 
 uCellsCount = 0;
 uMinesCount= 0;
 uRowCount = 0;
 uColCount = 0;
 
 for (int i = 0; i < uColCount;  i++)    //Очищаем COLUMNS
      delete  Cells[i];

  delete [] Cells;        //Очищаем ROWS

           
}
TField::TField( int Height,int Width)  //конструктор  поля игры
{

 

  uColCount = Height;
  uRowCount =  Width;
  uCellsCount = (uColCount)*(uRowCount); //общие количество клеток


  Cells = new TCell*[uColCount];       //выделяем пямять для клеток
     for (int j = 0; j < uColCount; j++)
       Cells[j] = new TCell [uRowCount];


}
                                     
////////////////////////////////////////////////////////////////////////////////
void TField::ClearField()
{
  for (int i = 0; i<uColCount; i++)    //очищаем поле
  {

     for (int j = 0;j<uRowCount; j++)
     {
         delete  &Cells[i][j];
     }

  }
}
void TField::Init(void)
{
 long lpCell_Id;
 int randCol;   //Случайная клетка поля
 int randRow;
 int i,j;

 
  ClearField();

  for (i = 0; i<uMinesCount; i++) //цикл минирования поля
  {
     
      randCol = random(uColCount);       //выбираем случайную клетку
 
       randRow = random(uRowCount);

        if (Cells[randCol][randRow].CellStatus != csMine) //если клетка не заминирована,
        {                                                 //то минируем её
         
           Cells[randCol][randRow].CellStatus = csMine;

        }
          else   //клетка уже заминирована, возвращаемся на одну клетку
                 //назад и пробуем её заминировать
          {
              i--;
              continue;
          }

  }

  lpCell_Id = 0;
  for (i = 0; i<uColCount; i++)    //создаем чистое поле и присваиваем клетке свой идентифекатор
  {

     for (j = 0;j<uRowCount; j++)
     {
       

         lpCell_Id++;
         
         Cells[i][j].X = i;
         Cells[i][j].Y = j;

     if (Cells[i][j].CellStatus != csMine)
     {
         Cells[i][j].CellStatus = csEmpty;
     }

         Cells[i][j].VisibleStatus =  vsClosed;
         Cells[i][j].cell_Id = lpCell_Id << 4;  //16 32 48 64 80 96 112 128


     }
  }
}

--------------------
With the best regards, Anton
PM MAIL   Вверх
RAN
Дата 7.9.2003, 13:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Экс. модератор
Сообщений: 709
Регистрация: 14.3.2003
Где: Щёлково Моск.обл.

Репутация: 5
Всего: 6



Пока рано что-то серьёзное говорить, напиши побольше. Точно не понятно следующее:
Цитата
void TField::ClearField()
{
  for (int i = 0; i<uColCount; i++)    //очищаем поле
  {

    for (int j = 0;j<uRowCount; j++)
    {
        delete  &Cells[i][j];
    }

  }
}

Что этот delete должен делать?
Теперь, закрой лучше все переменные классов и напиши методы для работы с ними. В твоём случае это просто необходимо. Во-первых, изменение uRowCount должно вызывать изменение uCellsCount, а во-вторых, это вообще недопустимо по логике твоего класса (у тебя память выделена уже под uCellsCount ячеек). Кстати вместо uCellsCount можно использовать метод getCellsCount() { return uRowCount * uColCount; }.
В деструкторах не надо обнулять поля, всё равно объект удаляется. И ещё, не надо писать CellStatus = (TCellStatus)0;, используй только значения из enum (обязательно придерутся).
Не совсем понимаю смысл id ячейки, также думаю можно обойтись и без X, Y. Что будет в cellDigit, цифры? Тогда зачем в TVisibleStatus vsDigit'ы? Короче, пиши дальше. Не забудь показать конструктор ячейки, его здесь нет.
Я думаю направление правильное. Цикл минирования поля понравился.
PM MAIL ICQ   Вверх
aMiGo!
  Дата 7.9.2003, 22:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 124
Регистрация: 6.4.2003
Где: Тула

Репутация: нет
Всего: нет



Цитата
Что этот delete должен делать?

Да, это лишнее - уже убрал.

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

Я знаю, замучил я тебя RAN, но все же можно разъяснить какие именно методы? tounge.gif

Цитата
В деструкторах не надо обнулять поля, всё равно объект удаляется

Эту фичу я спутал с "блуждающими указателями" hehe.gif

Цитата
не надо писать CellStatus = (TCellStatus)0;, используй только значения из enum (обязательно придерутся)

Огромное спасибо за совет, буду знать

Цитата
Не забудь показать конструктор ячейки, его здесь нет

А я собственно не понял, чо может быть в конструкторе клетки..,рисование самого объекта?

Цитата
Не совсем понимаю смысл id ячейки, также думаю можно обойтись и без X, Y

Да, я тут подумал, это нафиг не нужно.. (идея была такова: по идешнику можно найти любую клетку)

Цитата
Что будет в cellDigit, цифры? Тогда зачем в TVisibleStatus vsDigit'ы?

Пока в разработке, это всеволишь наброски




--------------------
With the best regards, Anton
PM MAIL   Вверх
RAN
Дата 8.9.2003, 01:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Экс. модератор
Сообщений: 709
Регистрация: 14.3.2003
Где: Щёлково Моск.обл.

Репутация: 5
Всего: 6



Код

//==============================================================
// Как я вижу TCell
class TCell
{
friend class TField; //Позволим TField изменять поля этого класса.
//Вообще друзей надо использовать как можно реже, они нарушают принципы ООП, но здесь, по-моему, уместно дать возможность TField
//изменять поле Value. Потому что никто другой, кроме TFiled не должен этого делать и писать метод нет смысла.
private:
   enum TCellStatus    { csEmpty, csMine }; //Ячейка может содержать мину и не содержать
   enum TVisibleStatus { vsClosed, vsOpen, vsMarked, vsUnknown }; //Она может быть закрыта, открыта, помечена и вопрос
   TCellStatus CellStatus;
   TVisibleStatus VisibleStatus;
   unsigned char Value; //Здесь будем хранить цифру для всех полей. Даже там где не надо. Мне кажется так проще.
public:
   TCell();
};

TCell::TCell()
{
   CellStatus = csEmpty;
   VisibleStatus = vsClosed;
   Value = 0; //Обнулим цифру
}


//==============================================================
// А это TField
class TField      //Класс поля
{
private: //Эта секция недоступна за пределами класса
//Это гарантирует, что переменные никто не изменит
unsigned uMinesCount;   //Количество мин
unsigned uRowCount;     //Количество Rows
unsigned uColCount;     //Количество Columns
TCell** Cells;              //Клетки поля игры
void DeleteCells();      //Функция для удаления всех Cells. Тоже закрыта, чтоб извне никто не удалил

public: //Эта секция видна ото всюду
    TField(); //конструктор поля игры
 ~TField() { DeleteCells(); } //Деструктор
    void Init(unsigned Columns, unsigned Rows, unsigned Mines); //Инициализируем игровое поле
// Вот методы для доступа к закрытым полям
    inline unsigned getMinesCount() { return uMinesCount; }
    inline unsigned getRowCount() { return uRowCount; }
    inline unsigned getColCount() { return uColCount; }
    TCell& getCell(unsigned column, unsigned row) { return Cells[row][column]; }
};

TField::TField()
{
//Обнулим переменные для порядку
uMinesCount = uRowCount = uColCount = 0;
Cells = 0; //а это надо сделать обязательно, что delete в Init ошибку не дал
}

void TField::Init(unsigned Columns, unsigned Rows, unsigned Mines)
{
uMinesCount = Mines;   //Количество мин
uRowCount = Rows;     //Количество Rows
uColCount = Columns;     //Количество Columns
DeleteCells();
Cells = new TCell*[uRowCount];
unsigned i; //Не люблю в for определять. Потому что Builder и Visual по разному к этому относятся.
for(i = 0; i != uRowCount; i++)
   Cells[i] = new TCell[uColCount];

/* Цикл заполнения ячеек минами. Я заменил на while, чтоб i туда сюда не изменять */
i = 0;
while(i != uMinesCount) //цикл минирования поля
{
  unsigned randCol = random(uColCount); // VC почему-то выдаёт ошибку. Чтоб работало определите этот макрос
  unsigned randRow = random(uRowCount); // random это макрос #define random(max) ( rand() % (max) )
  if (Cells[randRow][randCol].CellStatus != TCell::csMine) //если клетка не заминирована,
  {                                                 //то минируем её
      Cells[randRow][randCol].CellStatus = TCell::csMine;
      //Теперь надо пройтись по периметру и увеличить Value в соседних ячейках
      //Может не совсем красиво, но, по-моему, оптимально
      if(randRow > 0)
   {
    Cells[randRow - 1][randCol].Value++;
    if(randCol > 0) Cells[randRow - 1][randCol - 1].Value++;
    if(randCol < uColCount - 1) Cells[randRow - 1][randCol + 1].Value++;
   }
      if(randCol > 0) Cells[randRow][randCol - 1].Value++;
      if(randCol < uColCount - 1) Cells[randRow][randCol + 1].Value++;
      if(randRow < uRowCount - 1)
   {
    Cells[randRow + 1][randCol].Value++;
    if(randCol > 0) Cells[randRow + 1][randCol - 1].Value++;
    if(randCol < uColCount - 1) Cells[randRow + 1][randCol + 1].Value++;
   }
      i++;
  }
}
}

void TField::DeleteCells()
{
   if(Cells == 0) return;
   for(unsigned i = 0; i != uRowCount; i++)
       delete[] Cells[i];
   delete[] Cells;
   Cells = 0;
}


Тут правда, неоправдано используется unsigned для хранения кол-ва бомб в соседних ячейках, хотя число это от 0 до 8. И алгоритм определения этого числа можно поискать. Вот другой способ подсчёта бомб в соседних ячейках:
Код

unsigned row, col;
for(col = ( (randCol == 0) ? 0 : randCol - 1 ); col <= ( (randCol == uColCount - 1) ? uColCount - 1 : randCol + 1 ); col++)
       for(row = ( (randRow == 0) ? 0 : randRow - 1 ); row <= ( (randRow == uRowCount - 1) ? uRowCount - 1 : randRow + 1 ); row++)
                  Cells[row][col].Value++; //Увеличится счётчик и самой бомбы, но это не важно. Всё равно он не повазывается.


А так, всё проверено. Работает правильно. Продолжай.

P.S. Обрати внимание на хранение данных в TCell** Cell; Я хранил так: Cell[ряд][столбец], но метод getCell(столбец, ряд).

Блин, я там сам напутал с рядами и столбцами при использовании Cell. Вот исправил. Надеюсь ты увидишь это сообщение раньше, чем столкнёшся с этим жучком. Уставший уже был.

Это сообщение отредактировал(а) RAN - 8.9.2003, 18:17
PM MAIL ICQ   Вверх
aMiGo!
Дата 8.9.2003, 17:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 124
Регистрация: 6.4.2003
Где: Тула

Репутация: нет
Всего: нет



Вау! smile.gif)

Огромнейшее спасибо тебе RAN!
пока буду разбираться, если будут вопросы, обязательно к тебе обращусь.
--------------------
With the best regards, Anton
PM MAIL   Вверх
aMiGo!
Дата 10.9.2003, 12:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 124
Регистрация: 6.4.2003
Где: Тула

Репутация: нет
Всего: нет



Цитата
Надеюсь ты увидишь это сообщение раньше, чем столкнёшся с этим жучком. Уставший уже был.


Твои надежды не оправдались, я уже сам исправил. Спасибо.
--------------------
With the best regards, Anton
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0553 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.