1+ /*
2+ * Igel - a UCI chess playing engine derived from GreKo 2018.01
3+ *
4+ * Copyright (C) 2018-2023 Volodymyr Shcherbyna <volodymyr@shcherbyna.com>
5+ *
6+ * Igel is free software: you can redistribute it and/or modify
7+ * it under the terms of the GNU General Public License as published by
8+ * the Free Software Foundation, either version 3 of the License, or
9+ * (at your option) any later version.
10+ *
11+ * Igel is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with Igel. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+ #include " gen.h"
21+
22+ #include < chrono>
23+ #include < thread>
24+
25+ using namespace std ::chrono_literals;
26+ std::vector<std::list<Move>> g_movesBook;
27+
28+ Generator::Generator (int depth, int threads, int fFash ):
29+ m_maxDepth(depth),
30+ m_maxThreads(threads),
31+ m_maxfHash(fFash )
32+ {
33+ std::cout << " Igel training data generator" << std::endl;
34+ std::cout << " Training depth:" << m_maxDepth << std::endl;
35+ std::cout << " Training threads:" << m_maxThreads << std::endl;
36+ std::cout << " Training fens hash:" << m_maxfHash << std::endl;
37+
38+ std::cout << " Allocating fen hash table (" << fFash << " GB) .." ;
39+ FenHashTT::instance (fFash );
40+ std::cout << " . Done" << std::endl;
41+ }
42+
43+ void Generator::onGenerate ()
44+ {
45+ std::ifstream t (" 8moves_v3.pgn" );
46+ std::string str ((std::istreambuf_iterator<char >(t)), std::istreambuf_iterator<char >());
47+ std::replace (str.begin (), str.end (), ' \n ' , ' ' );
48+
49+ size_t offset = 0 ;
50+ std::vector<std::string> book;
51+
52+ // read book into a vector
53+ while (true ) {
54+ auto pos_1 = str.find (" 1. " , offset);
55+ if (pos_1 == std::string::npos)
56+ break ;
57+ auto pos_2 = str.find (" 1/2-1/2" , pos_1);
58+ if (pos_2 == std::string::npos)
59+ break ;
60+ book.emplace_back (str.substr (pos_1, pos_2 - pos_1));
61+ offset = pos_2 + 1 ;
62+ }
63+
64+ std::cout << " Read: " << book.size () << " positions. Generating the book ..." << std::endl;
65+
66+ std::unique_ptr<Position> position (new Position);
67+
68+ for (const auto & i : book) {
69+ position->SetInitial ();
70+ size_t moveIndex = 0 ;
71+ auto & movesList = g_movesBook.emplace_back ();
72+
73+ while (true ) {
74+ auto separator = i.find (" . " , moveIndex);
75+
76+ if (separator == std::string::npos)
77+ break ;
78+
79+ separator += 2 ;
80+ auto move_end = i.find (" " , separator);
81+
82+ if (move_end == std::string::npos)
83+ break ;
84+
85+ auto m_1 = i.substr (separator, move_end - separator);
86+ auto m = StrToMove (m_1, *position);
87+
88+ if (position->MakeMove (m)) {
89+ movesList.emplace_back (m);
90+ auto m2 = i.find (" " , move_end);
91+
92+ if (m2 == std::string::npos)
93+ break ;
94+
95+ m2++;
96+ move_end = i.find (" " , m2);
97+ auto m_2 = i.substr (m2, move_end - m2);
98+ m = StrToMove (m_2, *position);
99+ moveIndex = move_end;
100+
101+ if (position->MakeMove (m))
102+ movesList.emplace_back (m);
103+ else {
104+ std::cout << " BookGen: m2 failed (" << m_2 << " , " << m << " )" << std::endl;
105+ std::cout << i << std::endl;
106+ abort ();
107+ }
108+ }
109+ else {
110+ std::cout << " BookGen: m1 failed (" << m_1 << " )" << std::endl;
111+ abort ();
112+ }
113+ }
114+ }
115+
116+ book.clear ();
117+ std::cout << " The book is generated: " << g_movesBook.size () << std::endl;
118+
119+ m_workerThreads.reset (new std::thread[m_maxThreads]);
120+ m_workers.reset (new GenWorker[m_maxThreads]);
121+
122+ unsigned int fileIndex = 0 ;
123+
124+ std::ofstream myfile;
125+ myfile.open (std::string (" data_" ) + std::to_string (fileIndex) + " .plain" );
126+ std::mutex mutex;
127+ uint64_t fileResetFenCounter = 0 ;
128+
129+ for (auto i = 0 ; i < m_maxThreads; ++i) {
130+ m_workers[i].m_pFile = &myfile;
131+ m_workers[i].m_pMutex = &mutex;
132+ m_workers[i].m_maxDepth = m_maxDepth;
133+ m_workerThreads[i] = std::thread (&GenWorker::workerRoutine, &m_workers[i]);
134+ }
135+
136+ while (true ) {
137+
138+ uint64_t before_processed = 0 ;
139+ uint64_t before_skipped = 0 ;
140+
141+ for (auto i = 0 ; i < m_maxThreads; ++i) {
142+ before_processed += m_workers[i].m_counter ;
143+ before_skipped += m_workers[i].m_skipped ;
144+ }
145+
146+ std::this_thread::sleep_for (60s);
147+
148+ uint64_t after_processed = 0 ;
149+ uint64_t after_skipped = 0 ;
150+
151+ for (auto i = 0 ; i < m_maxThreads; ++i) {
152+ after_processed += m_workers[i].m_counter ;
153+ after_skipped += m_workers[i].m_skipped ;
154+ }
155+
156+ std::cout << " [Processed " << after_processed << " FENs, " << ((after_processed - before_processed) / 60 ) << " per sec] [" ;
157+ std::cout << " Skipped " << after_skipped << " FENs, " << ((after_skipped - before_skipped) / 60 ) << " per sec]" << std::endl;
158+
159+ //
160+ // every epoch create a new data file
161+ //
162+
163+ if ((after_processed - fileResetFenCounter) >= 100000000 ) {
164+ std::cout << " Switch data file" << std::endl;
165+ mutex.lock ();
166+ myfile.close ();
167+ myfile.open (std::string (" data_" ) + std::to_string (++fileIndex) + " .plain" );
168+ mutex.unlock ();
169+ fileResetFenCounter = after_processed;
170+ }
171+ }
172+
173+ for (auto i = 0 ; i < m_maxThreads; ++i) {
174+ if (m_workerThreads[i].joinable ())
175+ m_workerThreads[i].join ();
176+ }
177+ }
0 commit comments