首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将FEN字符串解码为6个类别的独立变量。

将FEN字符串解码为6个类别的独立变量。
EN

Code Review用户
提问于 2020-08-03 03:48:14
回答 1查看 359关注 0票数 5

分弦是国际象棋棋盘位置的紧凑表示,它允许你从棋盘位置获得必要的信息来开始下棋。这包括像棋盘上的碎片,城堡的状态等。更多信息在这里:https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_符号表示法

我已经用go编写了一个简单的函数,将一个FEN字符串解码为单独的变量,并为FEN字符串所代表的每一个信息片段提供合适的类型,我想看看是否以一种合理的方式解析FEN字符串。

代码语言:javascript
复制
import (
    "strings"
)

type pair struct {
    x, y int8
}

func decodeFen(fen string) ([8][8]int8, int8, [4]bool, pair, int8, int) {
    split := strings.Split(fen, " ")
    var board [8][8]int8
    board_split := strings.Split(split[0], "/")
    for r, row := range board_split {
        var col_ind int8
        for _, char := range row {
            if char >= 49 && char <= 57 {
                for i := int8(0); i < int8(char) - 48; i++ {
                    board[r][col_ind] = '-'
                    col_ind++
                }
            } else {
                board[r][col_ind] = int8(char)
                col_ind++
            }
        }
    }
    var color int8
    if split[1] == "w" {
        color = 1
    } else {color = 2}
    var castle_status [4]bool
    var status_map = map[rune]int8 {
        'K' : 0, 'Q' : 1, 'k' : 2, 'q' : 3}
    if split[2] != "-" {
        for _, char := range split[2] {
            castle_status[status_map[char]] = true
        }
    }
    var ep_pos pair = pair{-1, -1}
    if split[3] != "-" {
        x_label := split[3][0]
        y_label := split[3][1]
        y_label -= 48
        ep_pos = pair{int8(x_label - 97), int8(y_label - ((y_label - 1) - (8 - y_label)) - 1)}
    }
    var halfmove_clock int8 = int8(split[4][0]) - 48
    var fullmove_number int = int(split[5][0]) - 48
    return board, color, castle_status, ep_pos, halfmove_clock, fullmove_number
}

这实际上只是一个解析问题,为了拆分字符串,我决定使用strings go库中的拆分()函数,而不是编写自己的函数。对这段代码的任何改进和反馈都将是很棒的,如果我没有正确地问这个问题,我很抱歉,因为这是我在这个社区中的第一篇文章。

EN

回答 1

Code Review用户

回答已采纳

发布于 2020-08-03 21:55:23

代码应该是正确的、可维护的、健壮的、合理有效的,而且最重要的是是可读的。

要确保代码是正确的,请仔细阅读规范和相关文档。

福赛斯-爱德华兹表示法

PGN-规格

便携游戏符号

代数符号(国际象棋)

国际象棋

对于代码评审,请比较规范和并行实现它的代码.

在国际象棋中,棋子被放置在正方形上,这些棋子被组织成不同的排列和文件,形成一个棋盘。在decodeFen中,除了板外,似乎没有任何对这些基本概念的引用。因此,将代码与规范进行比较是很困难的。

PGN是“便携游戏表示法”,这是为使用ASCII文本文件表示国际象棋游戏数据而设计的标准。PGN数据使用8位ISO 8859/1 (拉丁文1)字符集的子集表示。因此,

代码语言:javascript
复制
var board [8][8]int8

是不正确的。字符不是int8类型(8位有符号整数).字符类型为byte (8位)。

代码语言:javascript
复制
var board [8][8]byte

密码

代码语言:javascript
复制
for _, char := range row { ... }

期望一个UTF-8编码字符串。UTF-8编码与ISO 8859/1编码不同。

Go是一种安全的静态类型化语言。密码

代码语言:javascript
复制
board[r][col_ind] = int8(char)

当ISO 8859/1编码被解码为UTF-8编码时,纠正错误的尝试失败。

decodeFen代码是一种“意识流”代码,很难阅读并证明是正确的。代码缺少基本概念,比如封装复杂性和实现细节的函数。例如,将decodeFen组织成一系列调用来解析每个FEN字段的函数。

作为一个例子,考虑分件放置字段。以下是初稿:

pieces.go

代码语言:javascript
复制
package main

import (
    "errors"
    "fmt"
    "strings"
)

type Board [8][8]byte

const (
    whitePieceLetters = "PNBRQK"
    blackPieceLetters = "pnbrqk"
    pieceLetters      = whitePieceLetters + blackPieceLetters
)

func isPiece(p byte) bool {
    for i := 0; i < len(pieceLetters); i++ {
        if p == pieceLetters[i] {
            return true
        }
    }
    return false
}

var (
    ErrRankOutOfRange = errors.New("rank out of range")
    ErrFileOutOfRange = errors.New("file out of range")
    ErrPieceInvalid   = errors.New("piece invalid")
)

func parseFENPieces(board *Board, pieces string) error {
    ranks := strings.Split(pieces, "/")
    if len(ranks) != len(board) {
        return ErrRankOutOfRange
    }
    for r, rank := range ranks {
        f := 0
        for i := 0; i < len(rank); i++ {
            piece := rank[i]
            if piece >= '0' && piece <= '9' {
                for j := byte(0); j < piece-'0'; j++ {
                    if f >= len(board[0]) {
                        return ErrFileOutOfRange
                    }
                    board[r][f] = '-'
                    f++
                }
            } else {
                if f >= len(board[0]) {
                    return ErrFileOutOfRange
                }
                if !isPiece(piece) {
                    return ErrPieceInvalid
                }
                board[r][f] = piece
                f++
            }
        }
        if f != len(board[0]) {
            return ErrFileOutOfRange
        }
    }
    return nil
}

func main() {
    fens := []string{
        // https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation
        "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
        "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1",
        "rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq c6 0 2",
        "rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq - 1 2",
    }
    var board Board
    for _, fen := range fens {
        fields := strings.Split(fen, " ")
        if len(fields) > 0 {
            pieces := strings.Split(fen, " ")[0]
            fmt.Println(pieces)
            err := parseFENPieces(&board, pieces)
            fmt.Println(err)
            for i := range board {
                fmt.Printf("%c\n", board[i])
            }
        }
    }
}

操场:https://play.golang.org/p/-pPnCs2GMao

输出:

代码语言:javascript
复制
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR
<nil>
[r n b q k b n r]
[p p p p p p p p]
[- - - - - - - -]
[- - - - - - - -]
[- - - - - - - -]
[- - - - - - - -]
[P P P P P P P P]
[R N B Q K B N R]

使用国际象棋术语,以符合规格。

棋盘数据结构无处不在。给它一种类型:

代码语言:javascript
复制
type Board [8][8]byte

在Go中,参数通过值传递。对于数组,值是整个数组。因此,为了提高效率,我们使用指针(8字节或4字节)而不是数组(64字节)。

输入必须有效。不要对外部输入做出任何假设。报告错误。

不要使用魔法值: 49是'0',57是'9‘。

以此类推。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/247415

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档