我在LAN(长代数符号)中有一系列的Fen字符串和伴随的动作,看起来如下所示.在我的问题的末尾粘贴了一个数据帧示例.

FEN Moves GameUrl
r3k2r/1b1pbppp/p7/1pp5/3q4/P1NPBp1P/1PP1B1P1/R4Q1K w kq - 0 19 e3d4 f3g2 f1g2 b7g2 h1g2 c5d4 Link
3rr1k1/5ppp/6q1/pp6/1bppPn2/5P2/PPP2QPP/2NRBRK1 w - - 8 25 e1b4 f4h3 g1h1 h3f2 Link
r1bq1rk1/ppp2ppp/2np1b1n/3Q2N1/2B1PP2/4B3/PP2N1PP/R4RK1 b - - 0 13 h6g4 g5f7 f8f7 d5f7 Link

这个数据框中的每一行都是一个国际象棋谜题.我想要生成一个拼图的PGN,基于初始的fen,然后应用组成拼图的移动序列,目前存储在Moves中的长代数记法.

因此,我对上述嵌套框架的第一行的理想结果是:

FEN Moves GameUrl PGN
r3k2r/1b1pbppp/p7/1pp5/3q4/P1NPBp1P/1PP1B1P1/R4Q1K w kq - 0 19 e3d4 f3g2 f1g2 b7g2 h1g2 c5d4 Link [Variant "From Position"][FEN "r3k2r/1b1pbppp/p7/1pp5/3q4/P1NPBp1P/1PP1B1P1/R4Q1K w kq - 0 19"]19. Bxd4 fxg2+ 20. Qxg2 Bxg2+ 21. Kxg2 cxd4

要实现这一点,我们需要将局域网移动转换为SAN(短代数记法).

使用R的bigchess包,我try 将移动转向SAN,如下所示:

library(tidyverse)
library(bigchess)

df2 <- df %>% 
  mutate(Moves_SAN = sapply(Moves, lan2san))

但我认为它是从棋盘的起始位置读取Moves,所以翻译后的Moves_SAN是不正确的.

Does anyone know a way to convert the LAN to SAN based on the FEN and using an available package in R?

我设想的解决方案包括向FEN加载bigchessstockfishchess,然后应用局域网,并在这种情况下以某种方式将它们转换为SAN,但我一直无法弄清楚如何实现.

structure(list(FEN = c("r3k2r/1b1pbppp/p7/1pp5/3q4/P1NPBp1P/1PP1B1P1/R4Q1K w kq - 0 19", 
"3rr1k1/5ppp/6q1/pp6/1bppPn2/5P2/PPP2QPP/2NRBRK1 w - - 8 25", 
"r1bq1rk1/ppp2ppp/2np1b1n/3Q2N1/2B1PP2/4B3/PP2N1PP/R4RK1 b - - 0 13"
), Moves = c("e3d4 f3g2 f1g2 b7g2 h1g2 c5d4", "e1b4 f4h3 g1h1 h3f2", 
"h6g4 g5f7 f8f7 d5f7"), GameUrl = c("https://lichess.org/6OEDg4W3#Some(36)", 
"https://lichess.org/W9LaAFV1#Some(48)", "https://lichess.org/BxbS4jtt/black#Some(25)"
)), row.names = c(NA, -3L), class = c("data.table", "data.frame"
), .internal.selfref = <pointer: 0x0000026e39ef2e30>)

推荐答案

R确实应该有一个更完整的包,独立于引擎实现国际象棋的东西.我怀疑,在这里,Python的表现要好得多.好的,这里有一些bigchess左右的包装器,它应该可以为valid分和局域网移动文本做你想要的事情…

read.pos <- function(pos) {
    map <- list("P" =  1L, "B" =  2L, "N" =  3L, "R" =  4L, "Q" =  5L, "K" =  6L,
                "p" = -1L, "b" = -2L, "n" = -3L, "r" = -4L, "q" = -5L, "k" = -6L)
    map <- c(map, setNames(lapply(0:8, integer), c("/", 1:8)))
    matrix(unlist(map[strsplit(pos, "")[[1L]]], FALSE, FALSE),
           nrow = 8L, ncol = 8L, byrow = TRUE,
           dimnames = list(8:1, letters[1:8]))
}

fenlan2san <- function(fen, lan) {
    lan <- strsplit(lan, " ")[[1L]]
    nhm <- length(lan)
    if (nhm == 0L)
        return("")
    fen <- strsplit(fen, " ")[[1L]]
    pos <- read.pos(fen[1L])
    san <- character(nhm)
    for (i in seq_along(lan)) {
        move <- bigchess:::string.lan.move2move(lan[i])
        m1 <- move[1L]; m2 <- move[2L]; m3 <- move[3L]; m4 <- move[4L]; m5 <- move[5L]

        wb <- sign(pos[m1, m2])
        san[i] <- bigchess:::move2san(pos, m1, m2, m3, m4, m5)
        pos <- bigchess:::position.move(pos, m1, m2, m3, m4, m5)
        if (bigchess:::is.check(pos, wb))
            san[i] <- paste0(san[i], if (bigchess:::is.mate(pos, wb)) "#" else "+")
    }
    wtm <- fen[2L] == "w"
    nfm <- (nhm + (if (wtm) 1L else 2L)) %/% 2L
    i1 <- as.integer(fen[6L])
    i2 <- i1 - 1L + nfm
    if (wtm)
        san[c(TRUE, FALSE)] <- paste0( i1      :i2, ". ", san[c(TRUE, FALSE)])
    else {
        san[1L] <- paste0(i1, "... ", san[1L])
        if (i1 < i2)
        san[c(FALSE, TRUE)] <- paste0((i1 + 1L):i2, ". ", san[c(FALSE, TRUE)])
    }
    paste0(san, collapse = " ")
}

fenlan2pgn <- function(fen, lan)
    paste0("[Variant \"From Position\"] [FEN \"", fen, "\"] ", mapply(fenlan2san, fen, lan))

然后:

fen <- c("r3k2r/1b1pbppp/p7/1pp5/3q4/P1NPBp1P/1PP1B1P1/R4Q1K w kq - 0 19",
         "3rr1k1/5ppp/6q1/pp6/1bppPn2/5P2/PPP2QPP/2NRBRK1 w - - 8 25",
         "r1bq1rk1/ppp2ppp/2np1b1n/3Q2N1/2B1PP2/4B3/PP2N1PP/R4RK1 b - - 0 13")
lan <- c("e3d4 f3g2 f1g2 b7g2 h1g2 c5d4",
         "e1b4 f4h3 g1h1 h3f2",
         "h6g4 g5f7 f8f7 d5f7")
writeLines(fenlan2pgn(fen, lan))
[Variant "From Position"] [FEN "r3k2r/1b1pbppp/p7/1pp5/3q4/P1NPBp1P/1PP1B1P1/R4Q1K w kq - 0 19"] 19. Bxd4 fxg2+ 20. Qxg2 Bxg2+ 21. Kxg2 cxd4
[Variant "From Position"] [FEN "3rr1k1/5ppp/6q1/pp6/1bppPn2/5P2/PPP2QPP/2NRBRK1 w - - 8 25"] 25. Bxb4 Nh3+ 26. Kh1 Nxf2+
[Variant "From Position"] [FEN "r1bq1rk1/ppp2ppp/2np1b1n/3Q2N1/2B1PP2/4B3/PP2N1PP/R4RK1 b - - 0 13"] 13... Ng4 14. Nxf7 Rxf7 15. Qxf7+

将每个PGN导入Lichess分析板,表明它工作正常:https://lichess.org/analysis

但我的感觉是,熟悉stockfish和UCI协议的人可以以一种更好的方式获得同样的结果……

R相关问答推荐

找出疾病消失的受试者

gganimate在使用shadow_mark选项时不保留所有过go 的标记

未识别时区

R—将各种CSV数字列转换为日期

以更少间隔的较小表中的聚合离散频率表

在使用bslb和bootstrap5时,有没有办法更改特定dt行的 colored颜色 ?

从圆到R中的多边形的标绘雷达图

使用RSelenium在R中抓取Reddit时捕获多个标签

将全局环境变量的名称分配给列表中的所有元素

将数据集旋转到长格式,用于遵循特定名称模式的所有变量对

为什么在写入CSV文件时Purrr::Pwalk不起作用

仅当后续值与特定值匹配时,才在列中回填Nas

使用gt_summary是否有一种方法来限制每个变量集进行配对比较?

为什么函数toTitleCase不能处理english(1),而toupper可以?

如何为混合模型输出绘制不同的线型?

在使用SliderInput In Shiny(R)设置输入数据的子集时,保留一些情节痕迹

按镜像列值自定义行顺序

替换在以前工作的代码中有x行&q;错误(geom_sf/gganimate/dow_mark)

禁用时,SelecizeInput将变得不透明

Broom.Mixed::Augment不适用于Sample::分析