// FetchWebSudoku scrapes a sudoku puzzle from websudoku.com. // A Sudoku is returned on success, nil otherwise. func FetchWebSudoku(level, id int) *common.Sudoku { resp, err := http.PostForm(webSudokuEndpoint, url.Values{"level": {strconv.Itoa(level)}, "set_id": {strconv.Itoa(id)}}) if err != nil { return nil } defer resp.Body.Close() parsed, perr := html.Parse(resp.Body) if perr != nil { return nil } cheat, editMask := scrapeCheatAndEditMask(parsed) if cheat == nil || editMask == nil { return nil } if len(*cheat) != 81 || len(*editMask) != 81 { return nil } sudoku := common.NewSudoku(3) for i := 0; i < 81; i++ { if (*editMask)[i] == '0' { sudoku.Values[i/9][i%9] = int((*cheat)[i]) - int('0') } } return sudoku }
// Next deserializes and returns the next puzzle in the stream. // On success, a Sudoku is returned without an error. On failure, // an error is returned without a Sudoku and all subsequent calls // return the same error. If the Reader has reached the end of the // stream, Next returns nil, nil. func (r *Reader) Next() (*common.Sudoku, error) { // once a terminal state is reached, subsequent calls return the terminal state if r.termOk { return nil, nil } if r.termErr != nil { return nil, r.termErr } // attempt to read the next puzzle r.curSudoku = nil r.curSudokuRow = 0 eof, size, err := r.scanSize() if eof { r.termOk = true return nil, nil } if err != nil { r.termErr = err return nil, err } r.curSudoku = common.NewSudoku(uint8(size)) for s := r.curSudoku.Size * r.curSudoku.Size; s > 0; s-- { eof, err := r.scanRow() if eof { r.termOk = true return nil, nil } if err != nil { r.termErr = err return nil, err } } return r.curSudoku, nil }