Судоку сетки специального назначения итераторы


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

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

Некоторые технические детали:

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

Сетки класса добавляет несколько статических функций для вычисления смещений в массиве на основе строки, col или блок посты.

class Grid {
public:
    Grid();
    Grid(std::string s);

    class Iterator {
    public:
        Iterator(Grid* g) : grid(g), it(0){}
        Field* operator*(){return field;}
        void operator++(){
            ++it;
            if(it < 9) field = calc_field();
            else field = NULL;
        }
    protected:
        virtual Field* calc_field() = 0;
        Field* field;
        Grid* grid;
        int it;
    };

    class RowIterator : public Iterator {
    public:
        RowIterator(Grid* g, int row) : Iterator(g){
            row_offset = row * size; //Grid::block_offset(block);
            field = calc_field();
        }
        Field* calc_field(){
            int field_index = row_offset + it;
            return grid->field[field_index];
        }
    protected:
        int row_offset;
    };

    class ColIterator : public Iterator {
    public:
        ColIterator(Grid* g, int col) : Iterator(g){
            col_offset = col;
            field = calc_field();
        }
        Field* calc_field(){
            int field_index = it * size + col_offset;
            return grid->field[field_index];
        }
    protected:
        int col_offset;
    };

    class BlockIterator : public Iterator {
    public:
        BlockIterator(Grid* g, int block) : Iterator(g){
            block_offset = Grid::block_offset(block);
            field = calc_field();
        }
        Field* calc_field(){
            int field_index = block_offset + ((it / 3) * size) + (it % 3);
            return grid->field[field_index];
        }
    protected:
        int block_offset;
    };

    RowIterator& row_iter(int row){return *(new RowIterator(this, row));}
    ColIterator& col_iter(int col){return *(new ColIterator(this, col));}
    BlockIterator& block_iter(int block){return *(new BlockIterator(this, block));}

(...)

    static int block_offset(int block){return ((block / 3) * size * 3) + ((block % 3) * 3);}

protected:
        Field* field[grid_size];

Пример использования:

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

void Field::do_exclusions(){
    // row
    for(Grid::RowIterator it = grid->row_iter(row); *it; ++it)
        (*it)->set_excluded(value);
    // col
    for(Grid::ColIterator it = grid->col_iter(col); *it; ++it)
        (*it)->set_excluded(value);
    // block
    for(Grid::BlockIterator it = grid->block_iter(block); *it; ++it)
        (*it)->set_excluded(value);
}

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

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

PS: Я пытался добавить тег "итератор", но я не позволил слишком мало репутации.



677
14
задан 2 февраля 2011 в 05:02 Источник Поделиться
Комментарии
2 ответа

В мой первый быстрое сканирование, вот некоторые вещи, которые я хочу донести:


  • Если вы собираетесь перегрузки операторов, сделать это так, как пользователи языка, ожидают, или не делать его вообще. Я ожидаю, что оператор++ , чтобы вернуть что-то, не пустота.

  • Разве block_offset действительно должна быть публичной?

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

8
ответ дан 2 февраля 2011 в 05:02 Источник Поделиться

Есть утечка памяти в сетку::row_iter(), соавт. Зачем использовать новый в этом деле? Я бы предпочел

RowIterator row_iter(int row){return RowIterator(this, row);}

4
ответ дан 2 марта 2011 в 08:03 Источник Поделиться