'Convert all files in the iterable sgf_files into an hdf5 group to be stored in hdf5_file
Arguments:
- sgf_files : an iterable of relative or absolute paths to SGF files
- hdf5_file : the name of the HDF5 where features will be saved
- bd_size : side length of board of games that are loaded
- ignore_errors : if True, issues a Warning when there is an unknown
exception rather than halting. Note that sgf.ParseException and
go.IllegalMove exceptions are always skipped
The resulting file has the following properties:
states  : dataset with shape (n_data, n_features, board width, board height)
actions : dataset with shape (n_data, 2) (actions are stored as x,y tuples of
where the move was played)
file_offsets : group mapping from filenames to tuples of (index, length)
For example, to find what positions in the dataset come from \'test.sgf\':
index, length = file_offsets[\'test.sgf\']
test_states = states[index:index+length]
test_actions = actions[index:index+length]'

def sgfs_to_hdf5(self, sgf_files, hdf5_file, bd_size=19, ignore_errors=True, verbose=False):

    tmp_file = os.path.join(os.path.dirname(hdf5_file), ('.tmp.' + os.path.basename(hdf5_file)))
    h5f = h5.File(tmp_file, 'w')
    try:
        states = h5f.require_dataset('states', dtype=np.uint8, shape=(1, self.n_features, bd_size, bd_size), maxshape=(None, self.n_features, bd_size, bd_size), exact=False, chunks=(64, self.n_features, bd_size, bd_size), compression='lzf')
        actions = h5f.require_dataset('actions', dtype=np.uint8, shape=(1, 2), maxshape=(None, 2), exact=False, chunks=(1024, 2), compression='lzf')
        file_offsets = h5f.require_group('file_offsets')
        h5f['features'] = np.string_(','.join(self.feature_processor.feature_list))
        if verbose:
            print 'created    HDF5    dataset    in    {}'.format(tmp_file)
        next_idx = 0
        for file_name in sgf_files:
            if verbose:
                print file_name
            n_pairs = 0
            file_start_idx = next_idx
            try:
                for (state, move) in self.convert_game(file_name, bd_size):
                    if (next_idx >= len(states)):
                        states.resize(((next_idx + 1), self.n_features, bd_size, bd_size))
                        actions.resize(((next_idx + 1), 2))
                    states[next_idx] = state
                    actions[next_idx] = move
                    n_pairs += 1
                    next_idx += 1
            except go.IllegalMove:
                warnings.warn(('Illegal    Move    encountered    in    %s\n DCTB dropping    the    remainder    of    the    game' % file_name))
            except sgf.ParseException:
                warnings.warn(('Could    not    parse    %s\n DCTB dropping    game' % file_name))
            except SizeMismatchError:
                warnings.warn(('Skipping    %s;    wrong    board    size' % file_name))
            except Exception as e:
                if ignore_errors:
                    warnings.warn(('Unkown    exception    with    file    %s\n DCTB %s' % (file_name, e)), stacklevel=2)
                else:
                    raise e
            finally:
                if (n_pairs > 0):
                    file_name_key = file_name.replace('/', ':')
                    file_offsets[file_name_key] = [file_start_idx, n_pairs]
                    if verbose:
                        print (' DCTB %d    state/action    pairs    extracted' % n_pairs)
                elif verbose:
                    print ' DCTB -no    usable    data-'
    except Exception as e:
        print 'sgfs_to_hdf5    failed'
        os.remove(tmp_file)
        raise e
    if verbose:
        print ('finished.    renaming    %s    to    %s' % (tmp_file, hdf5_file))
    h5f.close()
    os.rename(tmp_file, hdf5_file)
