1import os
2
3from pychess.compat import create_task
4from pychess.System.prefix import addDataPrefix
5from pychess.Utils.const import WHITE, BLACK, LOCAL, WAITING_TO_START, HINT, LESSON
6from pychess.Utils.LearnModel import LearnModel
7from pychess.Utils.TimeModel import TimeModel
8from pychess.Players.Human import Human
9from pychess.System import conf
10from pychess.perspectives import perspective_manager
11from pychess.perspectives.learn.generateLessonsSidepanel import generateLessonsSidepanel
12from pychess.perspectives.learn import lessons_solving_progress
13from pychess.perspectives.learn.PuzzlesPanel import start_puzzle_game
14from pychess.Savers.pgn import PGNFile
15from pychess.System.protoopen import protoopen
16from pychess.Players.engineNest import discoverer
17
18__title__ = _("Lessons")
19
20__icon__ = addDataPrefix("glade/panel_book.svg")
21
22__desc__ = _('Guided interactive lessons in "guess the move" style')
23
24
25LESSONS = []
26for elem in sorted(os.listdir(path=addDataPrefix("learn/lessons/"))):
27    if elem.startswith("lichess_study") and elem.endswith(".pgn"):
28        title = elem.replace("beta-lichess-practice-", "")
29        title = title[14:title.find("_by_")].replace("-", " ").capitalize()
30        LESSONS.append((elem, title, "lichess.org"))
31    elif elem.endswith(".pgn"):
32        LESSONS.append((elem, elem.replace("-", " ").capitalize(), "pychess.org"))
33
34# Note: Find the declaration of the class Sidepanel at the end of the file
35
36
37def start_lesson_from(filename, index=None):
38    chessfile = PGNFile(protoopen(addDataPrefix("learn/lessons/%s" % filename)))
39    chessfile.limit = 1000
40    chessfile.init_tag_database()
41    records, plys = chessfile.get_records()
42
43    progress = lessons_solving_progress.get(filename, [0] * chessfile.count)
44
45    if index is None:
46        try:
47            index = progress.index(0)
48        except ValueError:
49            index = 0
50
51    rec = records[index]
52
53    timemodel = TimeModel(0, 0)
54    gamemodel = LearnModel(timemodel)
55
56    chessfile.loadToModel(rec, -1, gamemodel)
57
58    if len(gamemodel.moves) > 0:
59        start_lesson_game(gamemodel, filename, chessfile, records, index, rec)
60    else:
61        start_puzzle_game(gamemodel, filename, records, index, rec, from_lesson=True)
62
63
64def start_lesson_game(gamemodel, filename, chessfile, records, index, rec):
65    gamemodel.set_learn_data(LESSON, filename, index, len(records))
66
67    # Lichess doesn't export some study data to .pgn like
68    # Orientation, Analysis mode, Chapter pinned comment, move hint comments, general fail comment
69    if filename.startswith("lichess_study_beta-lichess-practice-checkmating-with-a-knight-and-bishop"):
70        if index in (4, 6, 8, 9):
71            gamemodel.tags["Orientation"] = "White"
72            print(index, '[Orientation "White"]')
73
74    color = gamemodel.boards[0].color
75    player_name = conf.get("firstName")
76
77    w_name = player_name if color == WHITE else "PyChess"
78    b_name = "PyChess" if color == WHITE else player_name
79
80    p0 = (LOCAL, Human, (WHITE, w_name), w_name)
81    p1 = (LOCAL, Human, (BLACK, b_name), b_name)
82
83    def learn_success(gamemodel):
84        gamemodel.scores = {}
85        chessfile.loadToModel(rec, -1, gamemodel)
86        progress = lessons_solving_progress[gamemodel.source]
87        progress[gamemodel.current_index] = 1
88        lessons_solving_progress[gamemodel.source] = progress
89        if "FEN" in gamemodel.tags:
90            create_task(gamemodel.restart_analyzer(HINT))
91    gamemodel.connect("learn_success", learn_success)
92
93    def on_game_started(gamemodel):
94        perspective.activate_panel("annotationPanel")
95        if "FEN" in gamemodel.tags:
96            create_task(gamemodel.start_analyzer(HINT, force_engine=discoverer.getEngineLearn()))
97    gamemodel.connect("game_started", on_game_started)
98
99    gamemodel.status = WAITING_TO_START
100    perspective = perspective_manager.get_perspective("games")
101    create_task(perspective.generalStart(gamemodel, p0, p1))
102
103
104# Sidepanel is a class
105Sidepanel = generateLessonsSidepanel(
106    solving_progress=lessons_solving_progress,
107    learn_category_id=LESSON,
108    entries=LESSONS,
109    start_from=start_lesson_from,
110)
111