84 / 84 / 42
Регистрация: 25.01.2010
Сообщений: 386
1

Консольный морской бой. Расстановка кораблей

25.10.2012, 23:08. Показов 7681. Ответов 7
Метки нет (Все метки)

Добрый вечер, уважаемые форумчане.
Хочу написать консольный морской бой. Начал с функции автоматической расстановки кораблей.
Весь день не получается найти где спяталась ошибка в моем коде.
Иногда программа зависает в 193-195 строках. Я новичек и не совсем еще разобрался в отладке программ. Использую VS 2010.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#include <iostream>
#include <time.h>
#include <conio.h>
using namespace std;
 
// размер поля 10х10 + 1 поле для индексации
const size_t field_size = 11;
 
const char default_symb = '-';
const char nonwritable_symb = '.';
const char sheep_symb = 'O';
 
 
char **create_field(const size_t, const size_t);
void init_field (char **);
void show_field (char **);
void init_sheep (char **, unsigned short, unsigned short);
// можно ли ставить кораблик в точку X,Y
bool IsEmpty (char**, int, int);
void MarkNear (char **field);
void UnMark (char **field);
 
int main()
{   
    setlocale (LC_ALL,"Rus");
    char ch = '\0';
    char **plr, **cpu;
    
    srand( (unsigned)time(NULL) );
    
    // Player's game space
    plr = create_field(field_size, field_size);
    // CPU's game space
    cpu = create_field(field_size, field_size);
 
    do 
    {
        system("CLS");
        // Заполняем значениями
        init_field(plr);
        // Расставляем корабли
        size_t SHEEP_SIZE = 4;
        size_t SHEEP_COUNT = 1;
        while (SHEEP_SIZE>0)
        {
            init_sheep(plr, SHEEP_SIZE, SHEEP_COUNT);
            SHEEP_SIZE--;
            SHEEP_COUNT++;
        }
            UnMark(plr);
            show_field(plr);
        cout << "\nRepeat? (y/n)\n";
        ch = getch();
    } while ( (ch != 'n') && (ch != 'N') );
 
    return 0;
}
 
char **create_field(const size_t rows, const size_t cols)
{
    char **temp = new char* [rows];
 
    for (size_t i = 0; i < rows; ++i)
         temp[i] = new char [cols];
 
     if (temp == 0)
     {
         cout << "\nНе удалось выделить память под массив\n";
         return 0;
     }
     else 
         return temp;
}
 
void show_field(char **field)
{
    for (size_t i=0; i<field_size; i++)
    {
        for (size_t j=0; j<field_size; j++)
            cout << *(*(field + i) + j) << ' ';
        cout << '\n';
    }
}
 
void init_field(char **field)
{
    field[0] = " РЕСПУБЛИКА";
    for (size_t i=1; i<field_size; i++)
        field[i][0] = 47+i;
 
    for (size_t i=1; i<field_size; i++)
        for (size_t j=1; j<field_size; j++)
            field[j][i] = default_symb;
}
 
bool IsEmpty (char **field, int pointX, int pointY)
{
    if ( field[pointY][pointX] == default_symb )
        return true;
    else
        return false;
}
 
void MarkNear (char **field)
{
    short near[8][2] = { {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1} };
    short add_x, add_y;
 
    for (unsigned short y=1; y<field_size; y++)
        for (unsigned short x=1; x<field_size; x++)
            if (field[y][x] == sheep_symb)
                for (unsigned short i=0; i<8; i++)
                {
                    add_x = x + near[i][0];
                    add_y = y + near[i][1]; 
                    if ( add_x >= 1 && add_x <= field_size-1 && add_y >= 1 && add_y <= field_size-1 && field[add_y][add_x] == default_symb)
                        field[add_y][add_x] = nonwritable_symb; 
                }
}
void UnMark (char **field)
{
    for (unsigned short y=1; y<field_size; y++)
        for (unsigned short x=1; x<field_size; x++)
            if (field[y][x] == nonwritable_symb)
                field[y][x] = default_symb;
}
 
void init_sheep (char **field, unsigned short DECKS, unsigned short COUNT)
{
    int X;
    int Y;
    int add_X;
    int add_Y;
    
    // один из 4-х вариантов пути приращения
    size_t way;
    // количество сгенерированных палуб
    size_t decks_count;
    // направление(X,Y) приращивания координат = вверх, вниз, влево, вправо 
    int direction[4][2] = { {0,1},{0,-1},{-1,0},{1,0} };
    // количество сгенерированных кораблей
    unsigned short sheeps_counter = 0;
 
    while (sheeps_counter < COUNT)
    {
    decks_count = 0;
    while (decks_count < DECKS)
    {
        if (decks_count == 0)
        {
            // большие корабли прижимаем к стенкам :)
            if (DECKS > 1)
            {
                size_t variant = rand()%4;
                switch (variant)
                {
                    case 0:
                        X = 1;
                        Y = rand()%(field_size-1)+1;
                        break;
                    case 1:
                        X = field_size-1;
                        Y = rand()%(field_size-1)+1;
                        break;
                    case 2:
                        X = rand()%(field_size-1)+1;
                        Y = 1;
                        break;
                    case 3:
                        X = rand()%(field_size-1)+1;
                        Y = field_size-1;
                        break;
                }
            }
            
            if (DECKS == 1)
            {
                X = rand()%(field_size-1)+1;
                Y = rand()%(field_size-1)+1;
            }
            if ( IsEmpty(field, X,Y) )
            {
                field[Y][X] = sheep_symb;
                decks_count++;
            }
        } else if (decks_count > 0 )
        {
            way = rand()%4;
            add_X = direction[way][0];
            add_Y = direction[way][1];
 
            if ( ((add_X + X) >= 1) && ((add_X + X) <= (field_size-1)) && ((add_Y + Y) >= 1) && ((add_Y + Y) <= (field_size-1)) ) 
            {
                if ( IsEmpty (field,(add_X + X),(add_Y + Y)) )
                {
                    X += add_X;
                    Y += add_Y;
                    field[Y][X] = sheep_symb;
                    decks_count++;
                }
            }
            
        }
    }
    sheeps_counter++;
    MarkNear(field);
    }
 
}
1
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
25.10.2012, 23:08
Ответы с готовыми решениями:

Расстановка кораблей (морской бой)
Доброго времени суток, при расстановке 2х палубных кораблей возникает проблема... При выборе точки...

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

Морской бой - программа зацикливается на расстановке кораблей
Нужно написать курсовую(игру). Решила написать морской бой(пока что консольно). Написала программу...

Морской бой. Ф-ция автоматической рассатновки кораблей.
Добрый день, ув. форумчане! Есть задание написать консольный морской бой. Есть задача расстановки...

7
0 / 0 / 1
Регистрация: 25.03.2012
Сообщений: 71
28.10.2012, 20:43 2
извините, можно ли спросить у вас, у меня просто задача там с расстановкой объектов тоже, как поставить условие чтоб между одним объектом-существующим и другим - предполагаемым, было расстояние в одну клетку?
0
178 / 161 / 38
Регистрация: 08.10.2012
Сообщений: 423
28.10.2012, 20:56 3
Цитата Сообщение от we2seek Посмотреть сообщение
Добрый вечер, уважаемые форумчане.
Хочу написать консольный морской бой. Начал с функции автоматической расстановки кораблей.
Весь день не получается найти где спяталась ошибка в моем коде.
Иногда программа зависает в 193-195 строках. Я новичек и не совсем еще разобрался в отладке программ. Использую VS 2010.
ВЫ знаете с разбегу не получится найти ошибку в вашем коде, особенно если ошибка не описана как таковая, а просто так перелопачивать столько строк кода...
Укажите пожалуйста что получается сделать и что должно происходить на том месте программы где у вас виснет?
Цитата Сообщение от Лера Чай Посмотреть сообщение
извините, можно ли спросить у вас, у меня просто задача там с расстановкой объектов тоже, как поставить условие чтоб между одним объектом-существующим и другим - предполагаемым, было расстояние в одну клетку?
Довольно просто, перед расстановкой корабля проверить нет ли рядом занятого поля, а после расстановки обставить кораблик занятым полем
0
Эксперт С++
3220 / 1747 / 435
Регистрация: 03.05.2010
Сообщений: 3,867
29.10.2012, 09:53 4
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/////////////////////////////////////////////////////////////////////////////////////////
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
/////////////////////////////////////////////////////////////////////////////////////////
class  T_battleship
{
    static const int    SHIP_SIZE_MIN   =   1;
    static const int    SHIP_SIZE_MAX   =   4;
    static const int    FIELD_ORDER     =   10;
    static const int    DIST_MIN        =   2;
    static const int    WATER_SYMB      =   ' ';
    static const int    SHIP_SYMB       =   'X';
    //-----------------------------------------------------------------------------------
    struct  T_cell
    {
        int     row_;
        int     col_;
        //-------------------------------------------------------------------------------
    public:
        //-------------------------------------------------------------------------------
        T_cell
            (
                int     row,
                int     col
            )
            :
            row_( row ),
            col_( col )
        {}
        //-------------------------------------------------------------------------------
        void  shift_to_right()
        {
            ++col_;
        }
        //-------------------------------------------------------------------------------
        void  shift_down()
        {
            ++row_;
        }
        //-------------------------------------------------------------------------------
        int  dist( const T_cell&  cell )    const
        {
            return  std::max
                        (
                            abs( row_ - cell.row_ ),
                            abs( col_ - cell.col_ )
                        );
        }
        //-------------------------------------------------------------------------------
    };
    //-----------------------------------------------------------------------------------
    typedef std::vector<T_cell>         T_ship;
    typedef std::vector<T_ship>         T_ships;
    typedef std::vector<char>           T_field_row;
    typedef std::vector<T_field_row>    T_field;
    //-----------------------------------------------------------------------------------
    T_ships     ships_;
    T_field     field_;
    //-----------------------------------------------------------------------------------
public:
    //-----------------------------------------------------------------------------------
    T_battleship()
        :
        field_
            (
                T_field
                    (
                        FIELD_ORDER,
                        T_field_row
                            ( 
                                FIELD_ORDER,
                                WATER_SYMB
                            )
                    )
            )
    {}
    //-----------------------------------------------------------------------------------
    void  rand_fill_field()
    {
        rand_fill_ships             ();
        to_display_ships_in_field   ();
    }
    //-----------------------------------------------------------------------------------
    void  print_field()   const
    {
        for(int  i = 0; i < FIELD_ORDER; ++i)
        {
            for(int  j = 0; j < FIELD_ORDER; ++j)
            {
                std::cout << field_[i][j]
                          << ' ';
            }    
            std::cout << std::endl;
        }
    }
    //-----------------------------------------------------------------------------------
private:
    //-----------------------------------------------------------------------------------
    void  to_display_ships_in_field()
    {
        for (
                T_ships::const_iterator
                ship_it     =   ships_.begin    ();
                ship_it     !=  ships_.end      ();
                ++ship_it            
            )
        {
            for (
                    T_ship::const_iterator
                    cell_it     =   ship_it->begin  ();
                    cell_it     !=  ship_it->end    ();
                    ++cell_it
                )
            {
                field_
                    [ cell_it->row_ ]
                    [ cell_it->col_ ]   =   SHIP_SYMB;
            }
        }
    }
    //-----------------------------------------------------------------------------------
    void  rand_fill_ships()
    {
        for( int  ship_size = SHIP_SIZE_MIN; ship_size <= SHIP_SIZE_MAX; ++ship_size )
        {
            int  quantity   =   SHIP_SIZE_MAX + 1 - ship_size;
            for(int  i = 0; i < quantity; ++i)
            {
                add_correct_rand_ship_with_size( ship_size );
            }
        }
    }
    //-----------------------------------------------------------------------------------
    void  add_correct_rand_ship_with_size( int  size )
    {
        T_ship  ship;
        do
        {
            bool    is_horiz        =   rand() % 2 == 0;
            int     horiz_size      =   SHIP_SIZE_MIN;
            int     vert_size       =   SHIP_SIZE_MIN;
            is_horiz
                ?   horiz_size  =   size
                :   vert_size   =   size;
 
            int     pos_row_max     =   FIELD_ORDER - vert_size;
            int     pos_col_max     =   FIELD_ORDER - horiz_size;
 
            T_cell  left_top_pos    =   get_rand_cell
                                            (
                                                pos_row_max,
                                                pos_col_max
                                            );
 
            ship    =   get_ship_in_pos_with_arrangement_and_size
                            (
                                left_top_pos,
                                is_horiz,
                                size
                            );
 
        }while  (
                    !ship_is_correct( ship )
                );
        ships_.push_back( ship );
    }
    //-----------------------------------------------------------------------------------
    T_cell  get_rand_cell
        (
            int     row_max,
            int     col_max
        )
    {
        int  row    =   get_rand_val(0, row_max);
        int  col    =   get_rand_val(0, col_max);
 
        T_cell  res     =   T_cell
                                (
                                    row,
                                    col
                                );
 
        return  res;
    }
    //-----------------------------------------------------------------------------------
    T_ship  get_ship_in_pos_with_arrangement_and_size
        (
            const T_cell&   left_top_pos,
            bool            is_horiz,
            int             size
        )
    {
        T_ship  ship;
        T_cell  cur_cell    =   left_top_pos;
        for(int  i = 0; i < size; ++i)
        {
            ship.push_back( cur_cell );
            is_horiz
                ?   cur_cell.shift_to_right     ()
                :   cur_cell.shift_down         ();
        }
        return  ship;
    }
    //-----------------------------------------------------------------------------------
    bool  ship_is_correct( const T_ship&  ship )
    {
        bool    bool_res    =   true;
 
        for (
                T_ships::const_iterator
                ship_it     =   ships_.begin    ();
                ship_it     !=  ships_.end      ();
                ++ship_it
            )
        {
            if  (
                        dist
                            (
                                *ship_it,
                                ship
                            )
 
                    <   DIST_MIN
                )
            {
                bool_res    =   false;
                break;
            }
        }
        return  bool_res;
    }
    //-----------------------------------------------------------------------------------
    int  dist
        (
            const T_ship&   L,
            const T_ship&   R
        )
    {
        int     res_dist    =   FIELD_ORDER;
        for (
                T_ship::const_iterator
                L_cell_it     =   L.begin     ();
                L_cell_it     !=  L.end       ();
                ++L_cell_it
            )
        {
            for (
                    T_ship::const_iterator
                    R_cell_it     =   R.begin     ();
                    R_cell_it     !=  R.end       ();
                    ++R_cell_it
                )
            {
                int     cur_dist    =   L_cell_it->dist( *R_cell_it );
                if( cur_dist < res_dist )
                {
                    res_dist = cur_dist;
                }
            }//for
        }//for
        return  res_dist;
    }
    //-----------------------------------------------------------------------------------
    int  get_rand_val
        (
            int     val_min,
            int     val_max
        )
    {
        return  rand() % ( val_max - val_min + 1 ) + val_min;
    }
    //-----------------------------------------------------------------------------------
};
/////////////////////////////////////////////////////////////////////////////////////////
int main()
{
    srand(static_cast<unsigned>(time(0)));
    T_battleship    battleship;
    battleship.rand_fill_field  ();
    battleship.print_field      ();
}
0
84 / 84 / 42
Регистрация: 25.01.2010
Сообщений: 386
01.11.2012, 03:25  [ТС] 5
Цитата Сообщение от MrGrig Посмотреть сообщение
Укажите пожалуйста что получается сделать и что должно происходить на том месте программы где у вас виснет?
Сори, что так долго не отвечал - небыло времени из-за работы
Программа зависает, когда пытается разместить корабль в ограниченном пространстве, как, например на рисунке:
Консольный морской бой. Расстановка кораблей


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

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
bool IsEmpty (char **field, int x, int y, int DECKS)
{
    if ( field[y][x] == default_symb )
    {
        // Счетчик пустых клеток вокруг заданной
        size_t counter = 0;
        
        // Look around
        if ( (y+1 <= field_size-1) && (field[y+1][x] == default_symb) )
            counter++;
        if ( (x+1 <= field_size-1) && (field[y][x+1] == default_symb) )
            counter++;
        if ( (y-1 >= 1) && (field[y-1][x] == default_symb) )
            counter++;
        if ( (x-1 >= 1) && (field[y][x-1] == default_symb) )
            counter++;
        
        switch (DECKS)
        {
            case 1:
                return true;
                break;
            case 2:
                if ( counter >= 1 )
                    return true;
                else
                    return false;
            case 3:
                if ( counter >= 2 )
                    return true;
                else
                    return false;
        }
    }
    else 
        return false;
}


Принцип работы следующий:
  1. Если клетка {x;y} занята символом по умолчанию, т.е. в ней нет корабля и она не соприкасается с другим кораблем, тогда проверяем рядомстоящие клетки по 4 направлениям: вверх, вниз, влево и вправо.
  2. если рядомстоящие клетки не заняты - увеличиваем счетчик на 1
  3. сравниваем счетчик с количеством палуб корабля, который хотим разместить и если счетчик меньше или равен количеству палуб, возвращаем TRUE.

Посмотрите, пожалуйста, что я упускаю?
1
178 / 161 / 38
Регистрация: 08.10.2012
Сообщений: 423
02.11.2012, 12:44 6
Цитата Сообщение от we2seek Посмотреть сообщение
Программа зависает, когда пытается разместить корабль в ограниченном пространстве, как, например на рисунке:
Нужно понять почему зависает, видимо получается бесконечный цикл
Цитата Сообщение от we2seek Посмотреть сообщение
Если клетка {x;y} занята символом по умолчанию, т.е. в ней нет корабля и она не соприкасается с другим кораблем, тогда проверяем рядомстоящие клетки по 4 направлениям: вверх, вниз, влево и вправо.
Цитата Сообщение от MrGrig Посмотреть сообщение
перед расстановкой корабля проверить нет ли рядом занятого поля, а после расстановки обставить кораблик занятым полем
Если после установки корабля сразу обвести его точками, то нет необходимости при построении проверять это условие
Цитата Сообщение от we2seek Посмотреть сообщение
не соприкасается с другим кораблем
Добавлено через 3 минуты
Цитата Сообщение от we2seek Посмотреть сообщение
C++
1
bool IsEmpty (char **field, int pointX, int pointY)
Цитата Сообщение от we2seek Посмотреть сообщение
C++
1
bool IsEmpty (char **field, int x, int y, int DECKS)
за что отвечает переменная DECKS?
Цитата Сообщение от we2seek Посмотреть сообщение
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
switch (DECKS)
* * * * {
* * * * * * case 1:
* * * * * * * * return true;
* * * * * * * * break;
* * * * * * case 2:
* * * * * * * * if ( counter >= 1 )
* * * * * * * * * * return true;
* * * * * * * * else
* * * * * * * * * * return false;
* * * * * * case 3:
* * * * * * * * if ( counter >= 2 )
* * * * * * * * * * return true;
* * * * * * * * else
* * * * * * * * * * return false;
* * * * }
возможно она получает цифру >3
от этого и зависоны

Добавлено через 2 минуты
Цитата Сообщение от we2seek Посмотреть сообщение
по 4 направлениям: вверх, вниз, влево и вправо
я бы реализовал немного по другому, смысл вашей функции впихнуть корабль в координату. Хотя бы хоть как нибудь. Я тоже так делал и это вышло у меня довольно объемно. Проще при создании корабля создавать рандомно еще его направление, тогда проверка будет довольно простая.

Добавлено через 11 минут
кстати, я бы вам советовал использовать поле не 10х10, а 12х12 и контур сразу забить точками (выводить поле с 1 по 11). тогда например при описаном выше варианте создания кораблей не выйдет лажи типо вот такого
C++
1
2
3
4
0 1 2 3 4 5 6
1 - - - - - -
2 о - - - - -
3 - - - - - -
например вы хотите кораблик поставить в точку о, с направлением в лево.
вы спокойно проверяете поле [3][0], так как контур у нас обведен точками, то функция дает отказ и вы генерируете следующие возможные координаты и направление корабля
1
84 / 84 / 42
Регистрация: 25.01.2010
Сообщений: 386
04.11.2012, 00:01  [ТС] 7
Спасибо, что вникли в код. Буду следовать вашим советам.
Переменная DECKS - это количество палуб, которые нужно разместить рядом с точкой {x,y}
0
178 / 161 / 38
Регистрация: 08.10.2012
Сообщений: 423
06.11.2012, 10:22 8
Цитата Сообщение от we2seek Посмотреть сообщение
Переменная DECKS - это количество палуб, которые нужно разместить рядом с точкой {x,y}
вот вы и прояснили, скорее всего зависания происходят когда вы пытаетесь вставить однопалубник, соответственно DECKS равно 0
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
06.11.2012, 10:22
Помогаю со студенческими работами здесь

Проверить правильность расстановки кораблей. Морской бой
Есть матрица NxM, где расставлены корабли. Корабли не стоят на краю матрицы, кол-во 4-х клеточных...

Морской бой: расставляется кораблей больше, чем положено
Здравствуйте! Пишу игру &quot;Морской бой&quot; в консоли, и попалась одна неприятная ситуация. Есть функция...

Консольный морской бой
Занялся написанием консольного морского боя на с++, вроде бы уже написал мат модель(хотя и...

Консольный морской бой
Доброй ночи, уважаемые форумчане! Собственно, нашел код на просторах интернета, вроде как рабочий,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru