From 69e09797c5b4f14f63bc9a6bf4ef3dc7abc8d8f3 Mon Sep 17 00:00:00 2001 From: Philipp Hagemeister Date: Tue, 5 Nov 2024 09:37:28 +0100 Subject: [PATCH] Automatic orientation for puzzles in studies When a coach is solving studies with a student, or a training group is solving puzzles from a book / course in lichess studies, this is done by enabling Conceal mode. The PGN for that is usually exported from Chessbase, or from the [ChessVision AI reader](https://ebook.chessvision.ai/). The existing cases don't help: Often, the PGN goes all the way to game end, so the game would be seen as completed, and thus rendered from white's side. So if a chapter is created in Conceal mode, set the orientation to the side that makes the next move that will be un-concealed if correct. [My coach](https://lichess.org/@/josefineheinemann) shared this example PGN, where the student is supposed to find black's moves: ``` [Event "Frauenbundesliga 2023/24"] [Site "lichess.org"] [Date "2024.06.08"] [Round "10"] [White "Gheng, Simona"] [Black "Heinemann, Josefine"] [Result "0-1"] [ECO "A36"] [WhiteElo "1982"] [BlackElo "2259"] [SetUp "1"] [FEN "1rbqk1nr/4ppb1/3p2p1/1p5p/3pPP2/3P2P1/PP2N1BP/R1BQ1R1K b k - 0 13"] [PlyCount "47"] [EventDate "2024.??.??"] [WhiteTeam "Schachfreunde Deizisau"] [BlackTeam "OSG Baden-Baden"] {[%evp 0,72,18,42,46,20,18,20,12,-35,-17,-17,0,0,31,31,19,17,0,15,26,1,13,10, 15,10,16,-7,-3,-12,18,-16,0,-94,-82,-79,-73,-68,-28,-67,-73,-100,-77,-185,-151, -224,-151,-172,-83,-137,-72,-72,-92,-153,-142,-234,-224,-191,-100,-194,-233, -301,-109,-277,-356,-452,-266,-428,-340,-349,-393,-1165,-1305,-1355,-1572] [#] } 13... h4 {[%emt 0:06:00][%cal Rg3g4]} (13... Bg4 14. h3 $14) (13... e6) 14. f5 {[%emt 0:10:00][%csl Rc8][%cal Gf5g6]} (14. gxh4 {[%cal Gh8h4,Gd8h4]} e5 $15 {[%cal Gd8h4]}) 14... hxg3 {[%emt 0:07:00]} (14... e6 15. fxg6 fxg6) 15. Nxg3 e5 {[%emt 0:03:00][%csl Gd4,Rg2][%cal Gd8h4]} 16. fxg6 {[%emt 0:08:00]} fxg6 17. Qf3 {[%emt 0:16:00][%csl Rf7]} (17. Qb3 Rb7) 17... Rb7 {[%emt 0:06:00] [%csl Gc8][%cal Gd8h4,Rh2h3]} 18. Ne2 {[%emt 0:04:00][%cal Gf3g3]} Bf6 { [%emt 0:02:00][%cal Gb7h7]} (18... Qh4 19. Qg3 Qxg3 (19... Qh5 20. Bf3) 20. Nxg3 Nf6 $17 {[%csl Rg2,Rg3][%cal Gc8e6,Gf6d7,Gd7c5,Gf6g4]}) (18... Nf6) 19. Qg3 {[%emt 0:08:00]} g5 {[%emt 0:02:00][%cal Gg5g4]} 20. Bd2 {[%emt 0:02:00]} g4 {[%emt 0:05:00][%cal Gf6h4]} 21. Rxf6 $2 {[%emt 0:07:00]} (21. Qf2 {[%csl Rf8]} Rbh7 (21... Qe7 22. Ng3 Qh7 23. h3 {[%cal Rg4h3,Gg2f3]} Rf7 $15) 22. Ng3 Rxh2+ 23. Kg1 $14 {[%csl Gg2][%cal Gg3f5,Ga1c1,Gd2b4,Gb4a5]}) (21. Kg1 Bh4) ( 21. Qe1) 21... Qxf6 {[%emt 0:03:00]} 22. Rf1 Qg6 {[%emt 0:03:00]} 23. Rc1 { [%emt 0:01:00][%csl Rc8]} Be6 {[%emt 0:01:00]} 24. Bb4 {[%emt 0:05:00]} Kd7 { [%emt 0:05:00] [#]} 25. Nxd4 {[%cal Re5d4]} (25. Bxd6 Kxd6 26. Nxd4 Rxh2+ { [%cal Rg3h2,Gb7h7]} 27. Kxh2 Qh6+ $19 {[%cal Gh6c1]}) 25... Ne7 {[%emt 0:02:00] [%csl Rc6]} (25... exd4 26. Qxd6+ Ke8 27. Qf8+ (27. Rc7 Rxc7) (27. Qc6+) 27... Kd7 28. Qc8#) 26. Nf5 (26. Nxe6 Qxe6) 26... Qg5 {[%emt 0:12:00]} (26... Bxf5 27. exf5 Nxf5 28. Qf2 Rxh2+ {[%csl Rc1][%cal Rh1h2,Gg6h6]} 29. Kg1 Nd4 { [%csl Rg2][%cal Rg1h2,Gg6h6]} 30. Bc6+ Nxc6 31. Qxh2 Nxb4 $19) 27. Rf1 { [%emt 0:01:00]} Bxf5 28. exf5 Rc7 29. f6 {[%emt 0:02:00]} (29. Bxd6 Kxd6 30. d4 Kd7 31. dxe5 Rc1 $19 {[%csl Re5,Rf5,Rh1]}) 29... Nf5 {[%emt 0:02:00]} 30. Qf2 Rc1 {[%emt 0:03:00]} 31. Qa7+ {[%emt 0:03:00]} (31. Rxc1 Qxc1+ 32. Bf1 Ng3+ $19 {[%cal Gc1f1]} 33. Qxg3 Qxf1+ 34. Qg1 Rxh2+ 35. Kxh2 Qh3#) (31. Be1 g3 32. Qxf5+ Qxf5 33. Rxf5 Rxh2+ 34. Kg1 Rxe1+ 35. Bf1 g2 $19 {[%cal Ge1f1]}) 31... Ke6 {[%csl Gf5]} 32. Be1 {[%emt 0:02:00]} (32. Bd5+ Kxd5 {[%csl Rb7,Rf7]} 33. Qf7+ (33. Qb7+ Ke6 $19) 33... Kc6 $19) 32... Rxe1 {[%emt 0:03:00]} 33. Rxe1 { [%emt 0:01:00]} Qh4 {[%csl Rh2][%cal Gh4e1]} (33... Rxh2+ 34. Kxh2 (34. Kg1 $19 ) 34... Qh4+ 35. Kg1 Qxe1+ $19 {[%csl Ge1,Gf5,Rf6]}) 34. Bd5+ (34. Rxe5+ Kxe5 $19 {[%cal Gf5e3,Gf5e7]}) 34... Kxf6 (34... Kxd5 35. Qf7+ Kd4 36. Qa7+ Kxd3 $19 ) 35. Qf7+ (35. Qg1 {[%csl Ge1,Gh2]} Ng3+ 36. Kg2 Qh3+ 37. Kf2 Nf5 $19 { [%cal Gh3h2,Gh3d3]}) 35... Kg5 {[%csl Gf5][%cal Gf5e7,Gf5g7,Gh4h2]} 36. Re2 Ng3+ (36... Ng3+ {[%cal Rh1g2,Gh4h2]} 37. Kg1 Nxe2+ 38. Kf1 Qxh2 $19 {[%cal Gg5f4,Gf4e3,Gf4g3]}) 0-1 ``` --- modules/study/src/main/ChapterMaker.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/study/src/main/ChapterMaker.scala b/modules/study/src/main/ChapterMaker.scala index f9b9c82d0d19c..f36cf27ae2122 100644 --- a/modules/study/src/main/ChapterMaker.scala +++ b/modules/study/src/main/ChapterMaker.scala @@ -82,6 +82,8 @@ final private class ChapterMaker( case Orientation.Fixed(color) => color case _ if isMe(tags.names.white) => Color.white case _ if isMe(tags.names.black) => Color.black + // If it is a concealed chapter (puzzles from a coach/book/course), start from side which moves first + case _ if data.isConceal && !data.fen.isDefined => root.color // if an outcome is known, then it's a finished game, which we show from white perspective by convention case _ if tags.outcome.isDefined => Color.white // in gamebooks (interactive chapter), we guess the orientation based on the last node