Schach mit ggplot

Quelle: Wiki Commons, MichaelMaggs


Schach!
Verbundene Freibauern sind normal ein Garant für den Sieg, doch manchmal ist die Partie auch nur Remis. Wir wollen uns heute anschauen wie man das in R schön darstellen kann.

Joshua Kunst hat das Paket rchess geschrieben. In Rchess bietet einige Möglichkeiten was Schachpositionen betrifft, ich will hier aber nur auf einige wenige Bezug nehmen:

library rchess laden
library(rchess)

eine neue Schachpartie, erzeugt die Klasse "Chess"
chss <- Chess$new()


die Position die uns interessiert in FEN
fen = "8/1k6/pP1K4/P7/8/8/8/8 w - - 0 40"
wird in die oben erzeugte Klasse Chss eingefügt (wäre nicht notwendig)
chss$load(fen)

mit chessboardjs wird die Position im RStudio Viewer ausgegeben
chessboardjs(fen = fen,width = 500, height=500)
oder einfach:
plot(chss)



Doch jetzt ein Problem. Wie kann man dieses Bild als Datei abspeichern? Natürlich kann man auf den Export Button klicken und dann händisch das Bild abspeichern. Das ist bei ein paar Positionen möglich, aber wie schaut das bei 1000en Positionen aus?

Eine Möglichkeit wäre folgende. Man benutzt das Paket webshot und htmlwidgets.

library(htmlwidgets)
library(webshot)

Mit saveWidget erzeugt man eine html Seite in der das Bild enthalten ist, mit webshot extrahiert man dann das Bild z.B. als png

saveWidget(mychart, "temp.html")
webshot("temp.html", file="schach.png", delay=2, zoom=1)


 

Ideal ist das nicht! Das Diagramm klebt irgendwo im linken oberen Eck des Bildes. Man könnte sich jetzt wahrscheinlich mit den Parametern von webshot spielen und würde wahrscheinlich ein passables Bild hinbekommen, aber wir wollen andere, lohnendere Wege beschreiten.

Rchess kann auch Schachdiagramme mit ggplot zeichnen. Das ist (wäre) cool, weil dadurch kann (könnte) man die Grafiken einfach mit ggsave speichern.
Der Befehl ist:
ggchessboard(fen)
oder
plot(chss, type="ggplot")

Doch das Ergebnis ist wenig zufriedenstellend:

RChess verwendet hier anscheinend die Schachzeichen aus der Unicodetabelle. Und irgendwas passt mit der Größendarstellung nicht.

J. Kunst schreibt selbst dazu:
Shh you can also plot the chesboard with ggplot. I know I need change that unicode style pieces ;)
Abgesehen davon, die x,y Achsen Beschriftung ist unbrauchhbar. Entweder A bis H oder garnichts. Offensichtlich ist hier keine Zeit hineingeflossen, die Achsenbeschriftung hätte man in einer Zeile
+ labs(y="", x="") entfernen können.

Warum nicht ein eigenes Schachbrett für ggplot entwerfen, dass man schön als Bild abspeichern kann?
Gesagt getan.
Zuerst brauchen wir Schachfiguren. Ich verwende die SVG Grafiken der Wikimedia Commons, aber grundsätzlich kann man jede Vorlage verwenden.

Die Figuren sind unter der CC BY-SA 3.0 veröffentlicht und sind tolle Arbeit!

Ich öffne die SVG Dateien in Photoshop und speichere sie als transparente GIFs mit einer Auflösung von 1200x1200.

Das geht so:
Öffnen des Vektorformats .svg und Eingabe der Größe:

    

ergibt:

dann: Datei -> Exportieren -> für Web Speichern (Legacy)...

dann wichtig Transparenz angehakt und Speichern


Das natürlich mit allen 12 Figuren.

Dann zum R Code:

library(tidyverse)
library(ggimage)

unsere Positon (wie oben)
fen = "8/1k6/pP1K4/P7/8/8/8/8 w - - 0 40"
und wir brauchen nur den Figurenteil momentan:
fen = unlist(strsplit(fen,split = " "))[1]

Die Bildnamen für die in der FEN festgelegten Figuren:

pics <- tribble(~f, ~filename,
                "p"    ,"bp1024.gif",
                "n"    ,"bn1024.gif",
                "b"    ,"bb1024.gif",
                "q"    ,"bq1024.gif",
                "k"    ,"bk1024.gif",
                "r"    ,"br1024.gif",
                "P"    ,"wp1024.gif",
                "N"    ,"wn1024.gif",
                "B"    ,"wb1024.gif",
                "Q"    ,"wq1024.gif",
                "K"    ,"wk1024.gif",
                "R"    ,"wr1024.gif")

Eine Funktion um die Zahlen in der FEN zu behandeln:

makespace <- function(x){
  y <- x %>% str_extract("[1-8]") %>% as.integer()
  if (!is.na(y)) {rep(0,y)} else {x}
}
in f ist dann der Aufbau des Schachbrettes von A8 bis H1 in einem Array von 64 Feldern

f <- 
  fen %>% 
  str_split("/") %>% 
  map(~ str_split(.x, "") ) %>% 
  pluck(1) %>%
  map( ~ map(.x, ~ makespace(.x)) ) %>%
  unlist() 
daraus machen wir das ganze Schachbrett mit den Informationen welche Zeile, welche Spalte, welche Farbe das Brett hat (weiß oder schwarz), welche Figur dort steht und welcher Dateinamen der Figur zugeordnet ist.

df_board <- expand.grid(1:8,1:8) %>%  
  select(s=1,z=2) %>% 
  as_tibble() %>% 
  mutate(f=f) %>% 
  left_join(pics,by=c("f"="f")) %>% 
  mutate(c = (z+s+1) %% 2 , c = ifelse(c==1,"s","w"))

das Ganze kann jetzt als ggplot gezeichnet werden:
in geom_tile sind die Felder, in geom_image werden die Schachfiguren geladen

df_board %>% 
  ggplot( aes(x=s,y= z))+
  theme_bw()+
  theme(axis.line = element_blank(),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.border = element_blank(),
        panel.background = element_blank()) +
  scale_x_continuous(limits=c(0,8), breaks=NULL)+
  scale_y_continuous(limits=c(0,8), breaks=NULL) +
  scale_fill_manual(values = c("lightgray", "darkgray"))+
  geom_tile(aes(x=s-0.5,y=9-z-0.5, fill=c)) +
  geom_image(aes(x= s-0.5, y= 9-z-0.5,image=filename, size=.120) +
  labs(y="",
       x="")+
  coord_fixed()+
  theme(legend.position = "none")+
  list() 

Mittels ggsave kann man das speichern und bekommt ein schönes Bild:

ggsave(file=paste0("chess.jpg"), width = 15, height = 15, units = "cm", dpi= 300 )


oder eine andere Positon:

fen = "r1b1k1nr/p2p1pNp/n2B4/1p1NP2P/6P1/3P1Q2/P1P1K3/q5b1"

aus der Unsterblichen Partie Anderssen - Kieseritzky

Das wars! Viel Spaß mit den Schach Diagrammen!






Comments

Popular posts from this blog

Breaking Excel Encryption (Password Recovery) Part 1

Ultima 5 Underworld in R