Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.75/8: Рейтинг темы: голосов - 8, средняя оценка - 4.75
4 / 4 / 0
Регистрация: 20.07.2018
Сообщений: 280

Крисс-кросс, этюды для программистов

03.12.2022, 21:24. Показов 2306. Ответов 33
Метки c++ (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте, пытаюсь решить задачу из книги Уэзерелла Чарльза "Этюды для программистов". Задача крисс - кросс. Нужно по заданному списку слов построить сетку. В местах пересечения слова имеют одинаковые буквы. Я написал вот такую программу:

main.cpp:
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
#include <iostream>
#include "crisscross.h"
#include <vector>
using namespace std;
 
int main()
{
 
    vector<Word> mass;
    vector<Word>a not_visited_words;
    mass.push_back(Word("cat"));
    mass.push_back(Word("fbad"));
    mass.push_back(Word("forest"));
    mass.push_back(Word("eagle"));
   // mass.push_back(Word("lose"));
    mass.push_back(Word("siedge"));
    not_visited_words = mass;
    Cell c;
    //for(int i = 0; i < mass.size(); i++) {
        Word w;
        w = mass[0];
        w.set_coord_X(0);
        w.set_coord_Y(c.get_cell_coord_Y()/2);
        w.set_horizontal(1);
        c.add_word(w);
        not_visited_words.erase(not_visited_words.begin());
        c.backtracking(not_visited_words, w, 0);
        c.delete_word(w);
        //cout << not_visited_words[0].get_string() << endl;
 
    //}
 
    //c.backtracking(mass, mass[0], 0);
    c.print_matrix();
   // c.delete_word(w);
    //c.print_matrix();
}
crisscross.h:
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
#ifndef CRISSCROSS_H_INCLUDED
#define CRISSCROSS_H_INCLUDED
 
#include <vector>
#include <string>
#include <tuple>
 
using namespace std;
 
class Word {
private:
    string value;
    int len;
    bool horizontal;
    int coord_X;
    int coord_Y;
public:
    Word();
    Word(string value);
    void set_horizontal(bool horizontal);
    void set_coord_X(int coord);
    void set_coord_Y(int coord);
    bool get_horizontal();
    int get_coord_X();
    int get_coord_Y();
    int get_len();
    string get_string();
};
 
class Cell {
private:
    char** matrix;
    int dx;
    int dy;
    vector<bool> table_with_laters;
    vector<bool> used_words;
    tuple<int,int> check_in_table(Word& word_a, Word& word_b);
    int index_in1word;
public:
    Cell();
    int get_cell_coord_X();
    int get_cell_coord_Y();
    void add_word( Word& word_to_add);
    bool check(int X, int Y, bool horiz);
    void delete_word(Word& word_to_delete);
    int backtracking(vector<Word>& list_of_wirds, Word& current_word, int iteration);
    void print_matrix();
};
#endif // CRISSCROSS_H_INCLUDED
crisscross.cpp:
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
#include <string>
#include <iostream>
#include "crisscross.h"
#include <tuple>
using namespace std;
 
Word::Word() {
 
    this->value = "";
    this->coord_X = 0;
    this->coord_Y = 0;
    this->len = 0;
    this->horizontal = 1;
}
Word::Word(string value) {
    this->value = value;
    this->len = value.length();
    this->coord_X = 0;
    this->coord_Y = 0;
    this->horizontal = 1;
}
void Word::set_coord_X(int coord) {
    this->coord_X = coord;
}
void Word::set_coord_Y(int coord) {
    this->coord_Y = coord;
}
void Word::set_horizontal(bool horizontal) {
    this->horizontal = horizontal;
}
bool Word::get_horizontal() {
    return this->horizontal;
}
int Word::get_coord_X() {
    return this->coord_X;
}
int Word::get_coord_Y() {
    return this->coord_Y;
}
int Word::get_len() {
    return this->len;
}
 
string Word::get_string() {
    return this->value;
}
 
Cell::Cell(){
    this->dx = 50;
    this->dy = 50;
    matrix = new char* [dx];
    for(int i = 0; i < dx; i++) {
        matrix[i] = new char [dy];
    }
    for(int i = 0; i < dx; i++) {
        for(int j = 0; j < dy; j++) {
            matrix[i][j] = ' ';
        }
    }
 
}
 
bool Cell::check(int X, int Y, bool horiz) {
    if(horiz == true) {
        if(matrix[X][Y+1] == ' ' && matrix[X][Y-1] == ' ' && matrix[X][Y] == ' ')
            return true;
        else
            return false;
    }
    else if(horiz == false) {
        if(matrix[X+1][Y] == ' ' && matrix[X][Y] == ' ') {
            if( X > 0 && matrix[X-1][Y] == ' ')
                return true;
            return true;
        }
        else
            return false;
    }
    else
        return false;
}
 
void Cell::add_word( Word& word_to_add) {
    string value = word_to_add.get_string();
    int iter = 0;
    int max_value = 0;
 
    if(word_to_add.get_horizontal() == true)
        max_value = word_to_add.get_coord_X();
    else
        max_value = word_to_add.get_coord_Y();
    while(iter != value.length()) {
        if(word_to_add.get_horizontal() == true && check(max_value, word_to_add.get_coord_Y(), true)) {
            matrix[word_to_add.get_coord_Y()][max_value] = value[iter];
            iter += 1;
            max_value += 1;
        }
        else if(word_to_add.get_horizontal() == false && check(word_to_add.get_coord_X(), max_value, false)){
            matrix[max_value][word_to_add.get_coord_X()] = value[iter];
            iter += 1;
            max_value += 1;
        }
        else {
            cout << "error";
            delete_word(word_to_add);
        }
    }
}
 
 
void Cell::delete_word(Word& word_to_delete) {
    if(word_to_delete.get_horizontal() == true) {
        int iter = 0;
        int i = word_to_delete.get_coord_X();
        while(iter < word_to_delete.get_len()) {
            if(matrix[word_to_delete.get_coord_Y() + 1][i] != ' ' || matrix[word_to_delete.get_coord_Y() - 1][i] != ' ')
                continue;
            else {
                matrix[word_to_delete.get_coord_Y()][i] = ' ';
                iter+=1;
                i+=1;
            }
        }
    }
 
    else if(word_to_delete.get_horizontal() == false) {
        int iter = 0;
        int i = word_to_delete.get_coord_Y();
        while(iter < word_to_delete.get_len()) {
            if(matrix[i][word_to_delete.get_coord_X() - 1] != ' ' || matrix[i][word_to_delete.get_coord_X() + 1] != ' ')
                continue;
            else {
                matrix[i][word_to_delete.get_coord_X()] = ' ';
                iter+=1;
                i+=1;
            }
        }
    }
    else
        cout << "error" << endl;
}
 
void Cell::print_matrix() {
    for(int i = 0; i < dx; i++) {
        for(int j = 0; j < dy; j++) {
            cout << matrix[i][j];
            if(i == dx - 1)
                cout << '-';
        }
        cout << '|' << endl;
    }
}
 
tuple<int,int> Cell::check_in_table(Word& word_a, Word& word_b) {
    table_with_laters.resize(128);
    table_with_laters.clear();
    for (const char *p = word_a.get_string().c_str(); *p != '\0'; ++p)
        table_with_laters[(unsigned char) *p] = true;
 
    for (unsigned int i = 0; i < word_b.get_string().length(); i++) {
        if (table_with_laters[(unsigned char) word_b.get_string()[i]]) {
            for(int j = 0; j < word_a.get_string().length(); j++) {
                if(word_a.get_string()[j] != (unsigned char)word_b.get_string()[i])
                    continue;
                else {
                    table_with_laters.resize(0);
                    table_with_laters.clear();
                    return make_tuple(i, j);
                }
            }
        }
    }
    table_with_laters.resize(0);
    table_with_laters.clear();
    return make_tuple(-1, -1);
}
 
int Cell::get_cell_coord_X() {
    return this->dx;
}
 
int Cell::get_cell_coord_Y() {
    return this->dy;
}
 
int Cell::backtracking(vector<Word>& list_of_words, Word& current_word, int iteration)
{
    print_matrix();
    vector<Word> not_visited_words = list_of_words;
    for(int i = 0; i < list_of_words.size(); i++)
    {
        int tmp = 0;
        int same_latter_1, same_latter_2;
        tie(same_latter_2, same_latter_1) = check_in_table(current_word, list_of_words[i]);
        if(same_latter_1 >= 0 && same_latter_2 >= 0) {
        Word new_word;
        new_word = list_of_words[i];
        bool new_horiz;
        if(current_word.get_horizontal())
            new_horiz = false;
        else
            new_horiz = true;
 
        new_word.set_horizontal(new_horiz);
 
        new_word.set_coord_X(current_word.get_coord_X() + same_latter_1);
        new_word.set_coord_Y(current_word.get_coord_Y() - same_latter_2);
        add_word(new_word);
        for(int j = 0; j < not_visited_words.size()+1; j++) {
            if(not_visited_words[j].get_string() == new_word.get_string()) {
                tmp = j;
                not_visited_words.erase(not_visited_words.begin() + tmp);
                break;
            }
        }
 
        backtracking(not_visited_words, new_word, iteration+1);
        not_visited_words.insert(not_visited_words.begin()+tmp, new_word);
        delete_word(new_word);
        new_word.set_horizontal(true);
        new_word.set_coord_X(0);
        new_word.set_coord_Y(0);
        iteration -= 1;
        }
 
    }
}
Пояснение к коду: отдельный класс Word хранит в себе слово (которое в будущем будет считано из текстового файла), а класс Cell хранит сетку в матрице mass. У каждого слова есть своя координата для отрисовки. Идея такова: взять слово из списка, найти одинаковые буквы в другом слове, нарисовать это новое слово, запустить метод для нового слова, используя список еще не использованных слов. Собственно в чем проблема: я совсем не понимаю почему иногда слова вписываются СОВСЕМ не туда, куда надо, например как на скришотах. Также программа почему то не завершается (нет сообщения, что программа завершилась с каким либо кодом), даже если я добавляю условие выхода (if(list...size() == 0){return 1;}). Очень прошу помочь, если будут вопросы по коду - с радостью постараюсь объяснить что я пытался написать
Миниатюры
Крисс-кросс, этюды для программистов   Крисс-кросс, этюды для программистов  
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
03.12.2022, 21:24
Ответы с готовыми решениями:

Кроссворд крисс-кросс в делфи
Помогите создать кроссворд крисс-кросс в дельфи

Задание по книге "Этюды для программистов"
Ссылка на полную статью: http://programming-lang.com/ru/comp_programming/uezerell/0/j6.html

Реализация Игры "Жизнь" из книги Уэзерелл Ч. "Этюды для программистов"
Кто нибудь встречал ее нга с#??? Если у кого-то есть, вы не могли бы выложить исходник?

33
4 / 4 / 0
Регистрация: 20.07.2018
Сообщений: 280
06.12.2022, 21:05  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от SmallEvil Посмотреть сообщение
Это тоже у вас так совпало красиво или же не допускаете прикасание слов при вставке ?
Тоже просто совпало) Но сейчас как раз хочу добавить условие исключения соприкасания
0
4 / 4 / 0
Регистрация: 20.07.2018
Сообщений: 280
06.12.2022, 22:03  [ТС]
Этот результат пока наилучшее, что у меня получилось
Изображения
 
1
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
06.12.2022, 22:49
Так же создал новую версию класса Сетки, добавил в метод проверки фильтр на соприкасание.
Вот так вот получилось. Телескопу толком места не осталось.
Хотя если ограничить поле размерами, то он бы упаковался к слову cosmonaut.
Хотя еще можно изменить порядок выбора мест не по добавлению слов, а по расстоянию к центру кроссворда (его первого слова)
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
       c  p          
       ogalaxy       
       l  a          
       o  n          
      universe       
       i  t p        
 t     s    a        
meteorite   cosmonaut
 l          e        
 e                   
 s                   
 c                   
 o                   
 p                   
 e
Моя песочница.
Последний код, со скудными комментариями, без оптимизаций, и излишними контейнерами.
C++17

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
285
286
287
288
289
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <functional>
#include <memory>
#include <set>
#include <list>
#include <algorithm>
 
using std::string;
using std::pair;
using std::vector;
using std::ref;
template <typename T>
using ref_t = std::reference_wrapper<T>;
template <typename T>
using cref_t = std::reference_wrapper<const T>;
 
// универсальный hash дл¤ pair
struct pair_hash
{
    template <class T1, class T2>
    std::size_t operator() (const std::pair<T1, T2> &pair) const {
        return (std::hash<T1>()(pair.first) + std::hash<T2>()(pair.second)) ^ std::hash<T2>()(pair.second);
    }
};
 
// это просто Data класс, он хранит только данные, и не ¤вл¤етс¤ самосто¤тельной единицей.
// поэтому нет инкапсул¤ции полей.
struct CWord{
    CWord(const string &word):word{word}{
    }
    enum class Dir{Hor, Vert};
    struct CWordLink{
        CWordLink(CWord &cword, int pos):cword{cword}, pos{pos}{
        }
        bool operator==(const CWordLink &rhs){
            return (pos == rhs.pos) && (&cword.get() == &rhs.cword.get());
        }
        ref_t<CWord> cword; // ссыкла на cross - слово
        int pos; // номер буквы пересечени¤ с данным словом
    };
    int x{},y{}; // начало слова
    Dir dir{}; // ориентаци¤
    short pn{}; // ѕ/Ќ - пор¤дковый номер // если нужно
    cref_t<string> word; // слово
    std::map<int, CWordLink> links; // число - позици¤ буквы пересечени¤, с кемой буквой
    // danger !!!
    bool Linked() const{
        return links.size()!=0;
    }
    bool Link(int pos, CWord& to, int pos_to){
        if (pos < word.get().size() && pos_to < to.word.get().size()){
            links.emplace(pos, CWordLink(to, pos_to));
            return true;
        }
        return false;
    }
    void break_links(){
        for(auto& [pos, link] : links)
            link.cword.get().links.erase(pos);
        links.clear();
    }
};
 
// сетка (виртуальна¤), отвечает за расположение в ней слов.
// правила их расстановок, отступы , правила пересечений и т.д
struct Grid{
    using cells_t = std::map<pair<int,int>, vector<CWord::CWordLink>>;
    //using available_cells_t = std::unordered_map<pair<int,int>, CWord::CWordLink, pair_hash>;
    using available_cells_t = std::map<pair<int,int>, CWord::CWordLink>;
    using available_queued_cells_t = std::list<CWord::CWordLink>;   
    // максимальна¤ ширина и высота пол¤.
    // -1 - резинова¤
//      Grid(int max_width=-1, int max_height=-1)
         Grid()
      :width{0}, height{0}{
    }
    // одна из самых важных функций-членов Cетки
    // с отступами между словами
    bool CanBurn(const CWord & cword){
        if (cword.word.get().empty())
            return false;
        int dx = (cword.dir == CWord::Dir::Hor );
        int dy = (cword.dir == CWord::Dir::Vert);
        int x = cword.x, y = cword.y;
        auto cells_end = cells.end();
        for (int i = 0, end = cword.word.get().size(); i != end ; ++i){
            auto search = cells.find({x, y});
 
            if (search != cells_end){
                const auto& links = search->second;
                if (links.size()==2)
                    return false;
                else if ( links.size()==1){
                        if ( links[0].cword.get().word.get()[links[0].pos] != cword.word.get()[i]) 
                            return false;
                }
            }else{
                // проверка прилегаемости
                switch(cword.dir){
                    case CWord::Dir::Hor  : 
                        if (cells.find({x, y-1}) != cells_end || cells.find({x, y+1}) != cells_end)
                            return false;
                        break;
                    case CWord::Dir::Vert : 
                        if (cells.find({x-1, y}) != cells_end || cells.find({x+1, y}) != cells_end)
                            return false;
                        break;
                    default : break;
                }
            }
            x+=dx, y+=dy;
        }
        return true;
    }
    // прожиг слова на —етке
    bool Burn(CWord &cword){
        if (!CanBurn(cword))
            return false;
 
        int dx = (cword.dir == CWord::Dir::Hor );
        int dy = (cword.dir == CWord::Dir::Vert);
        int x = cword.x, y = cword.y;
        top_left_x = std::min(top_left_x, x);
        top_left_y = std::min(top_left_y, y);
        bottom_right_x = std::max(bottom_right_x, x + dx * int(cword.word.get().size()-1));
        bottom_right_y = std::max(bottom_right_y, y + dy * int(cword.word.get().size()-1));
 
        for (int i = 0, end = cword.word.get().size(); i != end ; ++i){
            cells_t::mapped_type & links = cells[{x,y}];
            links.emplace_back(cword, i);
            if (links.size()==1){
                available_cells.emplace(std::make_pair(x,y), CWord::CWordLink(cword, i) );
                available_queued_cells.push_back(CWord::CWordLink(cword, i));
            }
            else{
                available_queued_cells.erase(std::find(available_queued_cells.begin(), available_queued_cells.end(),
                    CWord::CWordLink(links[0].cword,links[0].pos))
                );
                cword.Link(i, links[0].cword, links[0].pos);
                available_cells.erase(std::make_pair(x,y));
                
            }
            x+=dx; y+=dy;
        }
        return true;
    }
    
    bool Excision (const CWord &cword);
    
    vector<string> MakeRows(){
        if (cells.size()!=0){
            int w = GetWidth();
            int h = GetHeight();
            vector<string> rows(h, string(w, ' '));
            for(auto& cell : cells){
                rows[cell.first.second - top_left_y][cell.first.first - top_left_x] = cell.second[0].cword.get().word.get()[cell.second[0].pos];
            }
            return rows;
        }
        return {};
    }
    
    int GetWidth() const{
        return bottom_right_x - top_left_x + 1;
    }
    int GetHeight() const{
        return bottom_right_y - top_left_y + 1;
    }
    const cells_t& Cells() const{
        return cells;
    }
    const available_cells_t& AvailableCells() const{
        return available_cells;
    }
    const available_queued_cells_t& AvailableQueuedCells() const{
        return available_queued_cells;
    }
private:
    // карта клеток, можно определить к какому слову/словам относитс¤ клетка
    cells_t cells;
    available_cells_t available_cells;
    available_queued_cells_t available_queued_cells;
    // bounds
    int top_left_x{0}, top_left_y{0};
    int bottom_right_x{0}, bottom_right_y{0};
    
    int width;  // текуща¤ ширина
    int height; // текуща¤ высота
    int max_width;
    int max_hegiht;
};
 
// главный класс, хран¤щий слова, св¤зи между ними и сетку дл¤ слов.
template <typename TGrid>
class CrossWord{
    //std::unique_ptr<TGrid> grid;  // сетка
    TGrid grid;
    std::set<string> words; // сами слова
    std::list<CWord> cwords; // crossed words
    std::map<pair<int, int>, ref_t<CWord>> table; // таблица cross-слов
    int horizontal_words = 0;
    int vertical_words = 0;
public:
    CrossWord(const CrossWord &) = delete;
    CrossWord(CrossWord&&) = delete;
    CrossWord& operator=(const CrossWord&) = delete;
    CrossWord& operator=(CrossWord&&) = delete;
    CrossWord() = default;
    ~CrossWord() = default;
    
    bool AddWord(const string &word){
        //const auto &cells  = grid.Cells();
        //const auto &acells = grid.AvailableCells();
        if (words.size() == 0){
            auto inserted_word = words.insert(word);
            if (inserted_word.second == false)
                return false;
            cwords.emplace_back(*(inserted_word.first));
            auto& cword = cwords.back();
            cword.dir = CWord::Dir::Hor;
            if (grid.Burn(cword)){
                cword.pn = ++horizontal_words;
                table.emplace(std::make_pair(cword.pn, 0), cword); 
                return true;
            }
            words.erase(inserted_word.first);
            cwords.pop_back();
            return false;
        }
        const auto &acells = grid.AvailableQueuedCells();
        if (acells.size() == 0)
            return false;
        
        auto inserted_word = words.insert(word);
        if (inserted_word.second == false)
            return false;
        cwords.emplace_back(*(inserted_word.first));
        auto& cword = cwords.back();
 
        for(const auto& wordlink : acells){
            for(int i = 0, end = word.size(); i != end; ++i){
                auto dir = wordlink.cword.get().dir;
                auto coord = std::make_pair(wordlink.cword.get().x + (dir == CWord::Dir::Hor)  * wordlink.pos ,
                                            wordlink.cword.get().y + (dir == CWord::Dir::Vert) * wordlink.pos);
                if (word[i] != wordlink.cword.get().word.get()[wordlink.pos])
                    continue;
                cword.x = coord.first  - (dir == CWord::Dir::Vert ? i : 0);
                cword.y = coord.second - (dir == CWord::Dir::Hor  ? i : 0);
                cword.dir = (dir == CWord::Dir::Hor ? CWord::Dir::Vert : CWord::Dir::Hor);
                if (grid.Burn(cword)){
                    if (cword.dir == CWord::Dir::Hor){
                        cword.pn = ++horizontal_words;
                        table.emplace(std::make_pair(cword.pn, 0), cword);
                    }
                    if (cword.dir == CWord::Dir::Vert){
                        cword.pn = ++vertical_words;
                        table.emplace(std::make_pair(0, cword.pn), cword);
                    }
                    return true;
                }
                
            }
        }
        words.erase(inserted_word.first);
        cwords.pop_back();
        return false;
    }
    
    vector<string> MakeCrossField(){
        return grid.MakeRows();
    };
};
 
int main(){
    CrossWord<Grid> cross;
    vector<string> words{
        "universe", "colonist", "planet", "space", "galaxy",
        "meteorite", "cosmonaut", "telescope",
    };
    for (const auto& w : words)
        std::cout << "Add word \"" << w << "\" - " 
                  << (cross.AddWord(w) ? "success" : "fail") << std::endl;
    auto cw_paper{cross.MakeCrossField()};
    for(const auto& line : cw_paper)
       std::cout << line << std::endl;
}


Добавлено через 1 минуту
Точно, в коде нет проверок на размеры сетки.
То есть пока сетка только "резиновая".
0
4 / 4 / 0
Регистрация: 20.07.2018
Сообщений: 280
06.12.2022, 23:18  [ТС]
У меня есть какой то странный момент: если у меня не осталось не использованных слов, то я вывожу полученную сетку. Первая такая сетка - та что выше, а все последующие имеют странную особенность: слово universe стирается. Ладно стирается, так оно убирается не полностью, а счетчик слов указывает, что оно все еще в сетке. Чудеса
Миниатюры
Крисс-кросс, этюды для программистов  
0
4 / 4 / 0
Регистрация: 20.07.2018
Сообщений: 280
06.12.2022, 23:20  [ТС]
А все, проблема решена, я не до конца проверял соприкасание между словами)
Миниатюры
Крисс-кросс, этюды для программистов  
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
06.12.2022, 23:25
_lUserl_, а вы позади слова проверяете соприкасание?
Я вот пропустил, добавил уже, но засорять не хочу своими правками.
В моем посте #23, слово galaxy прилепилось к другому
0
4 / 4 / 0
Регистрация: 20.07.2018
Сообщений: 280
06.12.2022, 23:26  [ТС]
Теперь надо бы решить проблему со связанностью и компактность решетки. Можно ли как то вычислить максимальный размер сетки имея только набор слов?
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
06.12.2022, 23:26
_lUserl_, в общем поздравляю, за упорность вашу, все таки доделали (хоть так)
1
4 / 4 / 0
Регистрация: 20.07.2018
Сообщений: 280
06.12.2022, 23:28  [ТС]
Цитата Сообщение от SmallEvil Посмотреть сообщение
_lUserl_, а вы позади слова проверяете соприкасание?
Я вот пропустил, добавил уже, но засорять не хочу своими правками.
В моем посте #23, слово galaxy прилепилось к другому
Да, и как раз из за этого у меня и стиралась вселенная)

Добавлено через 42 секунды
Цитата Сообщение от SmallEvil Посмотреть сообщение
_lUserl_, в общем поздравляю, за упорность вашу, все таки доделали (хоть так)
Спасибо вам тоже, вы подали много хороших идей!
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
06.12.2022, 23:28
Цитата Сообщение от _lUserl_ Посмотреть сообщение
Теперь надо бы решить проблему со связанностью и компактность решетки. Можно ли как то вычислить максимальный размер сетки имея только набор слов?
Даже не знаю что на это ответить. На глаз, оно такое не нужно.
У меня такой проблемы нет
0
4 / 4 / 0
Регистрация: 20.07.2018
Сообщений: 280
06.12.2022, 23:30  [ТС]
Просто изначально я создаю матрицу фиксированного заведомо большего размера, хотелось бы как нибудь этого избежать
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
06.12.2022, 23:39
Цитата Сообщение от _lUserl_ Посмотреть сообщение
решить проблему со связанностью и компактность решетки
Ну это зависит от набора слов.
И как я уже писал, начинать выбирать буквы для вставки, начиная с выбранного центра кроссворда (например центра первого слова.).
А связность, это особый случай.
То есть при переборе мест вставки, искать все варианты, и выбирать тот, где наибольше пересечений с другими словами.

Цитата Сообщение от _lUserl_ Посмотреть сообщение
Просто изначально я создаю матрицу фиксированного заведомо большего размера, хотелось бы как нибудь этого избежать
Так и делается, создается размер ожидаемого кроссворда, составили сетку.
Не нравится, увеличили/уменьшили размеры поля. И заново составляем сетку.

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

Добавлено через 4 минуты
Edit : добавлено несколько важных правок в пост!
0
4 / 4 / 0
Регистрация: 20.07.2018
Сообщений: 280
06.12.2022, 23:41  [ТС]
Хорошо, я попробую сделать еще что нибудь. Большое спасибо за помощь, это, наверное, одна из самых трудоемких задач из тех, что мне приходилось решать

Добавлено через 1 минуту
В книге написано так:

Качество схем крисс-кросса пропорционально их «связанности», т. е., чем теснее в среднем слова переплетены с соседями, тем интереснее головоломка. Связанность можно измерять по-разному: как отношение площади схемы к площади наименьшего объемлющего прямоугольника; как среднее число пересечений на слово; как среднее число пересечений на букву; как минимальное число пересечений на слово. При генерации головоломок крисс-кросс для массовых изданий использовалась коммерческая программа, но головоломки получались неинтересные — слишком длинные и извилистые. Когда ваша программа заработает, позаботьтесь об увеличении связанности.

Буду пытаться решить эту задачу
1
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
07.12.2022, 00:24
Попытался скомпоновать плотнее, пока только очередностью выбора потенциальных мест вставки (от своего центра, относительного, (0,0)).
Также слова из вектора, берутся до тех пор, пока хотя бы одно слово на каждом проходе, было вставлено.
То-есть, если не получилось вставить, оставляю слово на след. круг.
Если ни одного слова не было вставлено из всего вектора, прерываю цикл.
Более-менее смотрится, но еще есть над чем подумать.
Хотя я пока наигрался

Code
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
Add word "universe" - success
Add word "colonist" - success
Add word "planet" - success
Add word "space" - success
Add word "galaxy" - fail
Add word "meteorite" - success
Add word "cosmonaut" - fail
Add word "telescope" - success
Add word "comet" - success
Add word "eclipse" - success
Add word "gravity" - fail
Add word "observatory" - success
Add word "galaxy" - success
Add word "cosmonaut" - success
Add word "gravity" - success
 
 space               
    o  m  c          
   planet observatory
    o  t  m          
   universe          
    i  o  t          
    s  r g           
    t  i a           
       telescope     
 eclipse a           
  o      x           
  s      y           
  m                  
  o                  
  n                  
gravity              
  u                  
  t
Удачи.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
07.12.2022, 00:24

Ищу программистов Cocos2d-x для разработки игр, Ищу программистов C++
Привет всем. Ищу разработчиков С++ для мобильной игры (iOS, Android и WP в перспективе). Используемый движок - Cocos2d-x. Сейчас в...

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

Макрос для кросс журнала
Всем здравствуйте. Помогите пожалуйста создать маркос для заполнения кроссировочного журнала. сам я к сожалению не умею программировать....

Кросс компиляция для Raspberry Pi 3
Добрый день. Пытаюсь собрать QT, опираюсь на мануал https://wiki.qt.io/Raspberry_Pi_Beginners_Guide. Мануал довольно старый (предлагают...

EntityFramework для кросс-платформенного приложения
Доброго времени суток товарищи! Есть две либы: Model и ViewModel, обе на .NET Standard 2.0. ViewModel служит общим модулем для UWP...


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

Или воспользуйтесь поиском по форуму:
34
Ответ Создать тему
Новые блоги и статьи
Море в объективе
kumehtar 06.07.2026
Хотел написать много проникновенных слов, но передумал. Оно само - говорит. Кто слышит тот слышит.
Оказывается, Unreal Engine позволяет качество на порядки выше, чем было в Lineedge
Etyuhibosecyu 05.07.2026
Жаль, конечно, что я не узнал об этом, пока Lineedge существовала, а то бы Noname2331 написал, что волки превращаются в пиксельную кашу, а я бы его попросил скачать какую-нибудь бриллиантовую или Pro. . .
Doom для терминала без стрельбы и монстров. 3D Raycasting на ascii.
dcc0 05.07.2026
Попросил нейронную сеть deepai. org написать рейкастинг 3D с библиотекой ncurses для Linux. Чтобы можно было ходить на стрелочки. Чтобы стены были отрисованы символами. Справилась. Первый вариант. . .
Установка статуса документа по условию
Maks 05.07.2026
Алгоритм из решения ниже реализован на нетиповом документе "НарядПутевка" разработанного в КА2. Задача: в табличной части "Материалы" документа при записи автоматически устанавливать статус. . .
Сезонность и суточность закисления почв
anaschu 04.07.2026
200 часов это все равно моловато. Есть ситуации, но нестандартные, когда смена происходит за 5 лет. Но обычно это 50 лет и более. Наверное, закисление почвы происходит сезонно в средней. . .
В чем ценность человеческого опыта в глобальном смысле?
kumehtar 03.07.2026
Возможно, ценность человека не в том, что он однажды достигает мудрости, а в том, что он становится носителем карты пути. Он знает не только истину, но и последовательность внутренних изменений,. . .
интеграция AnyLogic с самописным REST API и переход на Odoo
anaschu 03.07.2026
Успешная интеграция AnyLogic с самописным REST API и переход на промышленную Odoo WMS Сегодня проделал огромный путь от простой симуляции физических процессов до построения полноценной. . .
Поиск всех путей на ориентированном графе. Linux
dcc0 02.07.2026
Переработка старого кода из моей статьи. Через несколько переработок от PHP кода к C89 (надеюсь, 89). Но довольно запутанно получилось. Код для Linux. Но если убрать time и то, что с ним. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru