#include #include #include #include #include #include #include #include #include #include #include #include const int MAX_SIIRTO = 6; class Pelilauta { private: Nappula pelilauta[LAUDAN_KOKO][LAUDAN_KOKO]; int siirtono; public: Pelilauta() { siirtono = 0; } Pelilauta(const Pelilauta &lahde) { lahde.hae(pelilauta, siirtono); } int hae_siirtono() { return siirtono; } void aseta(const Nappula lahde[LAUDAN_KOKO][LAUDAN_KOKO], int nsno) { siirtono = nsno; memcpy(pelilauta, lahde, sizeof(Nappula) * LAUDAN_KOKO * LAUDAN_KOKO); } void hae(Nappula kohde[LAUDAN_KOKO][LAUDAN_KOKO], int &sno) const { sno = siirtono; memcpy(kohde, pelilauta, sizeof(Nappula) * LAUDAN_KOKO * LAUDAN_KOKO); } }; struct Node { unsigned int tyhja; unsigned int oma; unsigned int toinen; }; class PrecalcManager { private: boost::recursive_mutex mutex; std::deque tilanteet; std::vector tree; int toinensyvyys; int tilanteita; bool nayta; public: PrecalcManager() { const Node tyhja = {0,0,0}; tree.push_back(tyhja); toinensyvyys = 3; tilanteita = 0; nayta = false; } void vaihdanayta() { nayta = !nayta; } void aseta_tsyvyys(int syvyys) { toinensyvyys = syvyys; } bool hae_tilanne(Nappula tulos[LAUDAN_KOKO][LAUDAN_KOKO], int &siirtono) { boost::recursive_mutex::scoped_lock lock(mutex); if (tilanteet.empty()) { std::cout << "Queue empty!" << std::endl; return false; } tilanteet.front().hae(tulos, siirtono); tilanteet.pop_front(); return true; } void vie_tilanne(const Nappula pelilauta[LAUDAN_KOKO][LAUDAN_KOKO], int siirtono) { boost::recursive_mutex::scoped_lock lock(mutex); if (siirtono >= MAX_SIIRTO) { return; } Pelilauta p; p.aseta(pelilauta, siirtono); tilanteet.push_back(p); tilanteita++; } bool hae_ratkaisu(Siirto &tulos, const Nappula pelilauta[LAUDAN_KOKO][LAUDAN_KOKO]) { boost::recursive_mutex::scoped_lock lock(mutex); int depth = 0; unsigned int pos = 0; Nappula arvo = TYHJA; do { arvo = pelilauta[depth % LAUDAN_KOKO][depth / LAUDAN_KOKO]; if (arvo == TYHJA) { pos = tree.at(pos).tyhja; } else if (arvo == OMA) { pos = tree.at(pos).oma; } else { pos = tree.at(pos).toinen; } if (pos == 0) return false; depth++; } while (depth < LAUDAN_KOKO * LAUDAN_KOKO); tulos.alkuX = (pos & 0xFF000000) >> 24; tulos.alkuY = (pos & 0x00FF0000) >> 16; tulos.loppuX = (pos & 0x0000FF00) >> 8; tulos.loppuY = pos & 0x000000FF; return true; } void vie_ratkaisu(const Siirto &siirto, const Nappula pelilauta[LAUDAN_KOKO][LAUDAN_KOKO]) { boost::recursive_mutex::scoped_lock lock(mutex); int depth = 0; unsigned int pos = 0; unsigned int nextpos = 0; Nappula arvo = TYHJA; const Node tyhja = {0,0,0}; Nappula lauta2[LAUDAN_KOKO][LAUDAN_KOKO] = {{TYHJA}}; if (nayta) { std::cout << "----OMA----" << std::endl; tulostalauta(pelilauta); std::cout << "v v v v v v" << std::endl; memcpy(lauta2, pelilauta, sizeof(Nappula) * LAUDAN_KOKO * LAUDAN_KOKO); toteutasiirto(lauta2, siirto); tulostalauta(lauta2); Siirto temp; std::cout << "HYVYYS: " << ai_rekursio(temp, OMA, lauta2, 0, -99, 99) << std::endl; std::cout << "----OMA----" << std::endl; } while(1) { arvo = pelilauta[depth % LAUDAN_KOKO][depth / LAUDAN_KOKO]; if (arvo == TYHJA) { nextpos = tree.at(pos).tyhja; } else if (arvo == OMA) { nextpos = tree.at(pos).oma; } else { nextpos = tree.at(pos).toinen; } depth++; if (depth == LAUDAN_KOKO * LAUDAN_KOKO) break; if (nextpos == 0) { nextpos = tree.size(); tree.push_back(tyhja); if (arvo == TYHJA) { tree.at(pos).tyhja = nextpos; } else if (arvo == OMA) { tree.at(pos).oma = nextpos; } else { tree.at(pos).toinen = nextpos; } } pos = nextpos; } nextpos = siirto.alkuX << 24; nextpos |= siirto.alkuY << 16; nextpos |= siirto.loppuX << 8; nextpos |= siirto.loppuY; if (arvo == TYHJA) { tree.at(pos).tyhja = nextpos; } else if (arvo == OMA) { tree.at(pos).oma = nextpos; } else { tree.at(pos).toinen = nextpos; } } void lasketilanne(int max) { Siirto tulos = {0}; Nappula pelilauta[LAUDAN_KOKO][LAUDAN_KOKO] = {{TYHJA}}; int count = 0; int siirtono = 0; while ((count < max || max == -1) && hae_tilanne(pelilauta, siirtono) && siirtono < MAX_SIIRTO) { // tulostalauta(pelilauta); if (peliloppu(OMA, pelilauta)) continue; if (!hae_ratkaisu(tulos, pelilauta)) { ai_etsisiirto(tulos, OMA, pelilauta); // Oma laskentasyvyys = automaattinen vie_ratkaisu(tulos, pelilauta); } toteutasiirto(pelilauta, tulos); if (peliloppu(TOINEN, pelilauta)) continue; std::vector tulokset; std::vector::const_iterator iter; ai_multirekursio(tulokset, TOINEN, pelilauta, toinensyvyys); // Toisen laskentasyvyys Nappula lauta2[LAUDAN_KOKO][LAUDAN_KOKO]; for (iter = tulokset.begin(); iter < tulokset.end(); iter++) { memcpy(lauta2, pelilauta, sizeof(Nappula) * LAUDAN_KOKO * LAUDAN_KOKO); toteutasiirto(lauta2, *iter); vie_tilanne(lauta2, siirtono + 1); } count++; } } int status_tilanteet() { boost::recursive_mutex::scoped_lock lock(mutex); return tilanteita; } int status_treesize() { boost::recursive_mutex::scoped_lock lock(mutex); return tree.size(); } int status_queuesize() { boost::recursive_mutex::scoped_lock lock(mutex); return tilanteet.size(); } int status_siirtono() { boost::recursive_mutex::scoped_lock lock(mutex); return tilanteet.front().hae_siirtono(); } int status_boardstate() { boost::recursive_mutex::scoped_lock lock(mutex); int oma, toinen, temp; Nappula pelilauta[LAUDAN_KOKO][LAUDAN_KOKO]; tilanteet.front().hae(pelilauta, temp); laskepisteet(oma, toinen, pelilauta); return oma + toinen; } void tallenna(std::ostream &kohde) { boost::recursive_mutex::scoped_lock lock(mutex); std::vector::const_iterator iter; Node temp; for (iter = tree.begin(); iter < tree.end(); iter++) { temp = *iter; kohde.write((char *) &temp, sizeof(temp)); } } void lataa(istream &lahde) { boost::recursive_mutex::scoped_lock lock(mutex); std::vector newtree; Node temp = {0,0,0}; lahde.read((char *) &temp, sizeof(Node)); while (lahde.good()) { newtree.push_back(temp); lahde.read((char *) &temp, sizeof(Node)); } Node n = tree.at(0); n.oma = join(newtree, newtree.at(0).oma, tree.at(0).oma, 1); n.toinen = join(newtree, newtree.at(0).toinen, tree.at(0).toinen, 1); n.tyhja = join(newtree, newtree.at(0).tyhja, tree.at(0).tyhja, 1); tree.at(0) = n; } int import(const std::vector &newtree, int pos, int depth) { boost::recursive_mutex::scoped_lock lock(mutex); if (pos == 0) return 0; if (depth == LAUDAN_KOKO * LAUDAN_KOKO) { return pos; } Node n = {0,0,0}; int npos; npos = tree.size(); tree.push_back(n); n.oma = import(newtree, newtree.at(pos).oma, depth + 1); n.toinen = import(newtree, newtree.at(pos).toinen, depth + 1); n.tyhja = import(newtree, newtree.at(pos).tyhja, depth + 1); tree.at(npos) = n; return npos; } int join(const std::vector &newtree, int pos, int ownpos, int depth) { boost::recursive_mutex::scoped_lock lock(mutex); if (depth == LAUDAN_KOKO * LAUDAN_KOKO) { if (pos == 0) { return ownpos; } else if (ownpos == 0) { return pos; } else if (ownpos != pos) { std::cout << "Move mismatch" << std::endl; return ownpos; } else { return ownpos; } } if (pos == 0) { return ownpos; } else if (pos != 0 && ownpos == 0) { return import(newtree, pos, depth); } else if (pos != 0 && ownpos != 0) { Node n = tree.at(ownpos); n.oma = join(newtree, newtree.at(pos).oma, tree.at(ownpos).oma, depth + 1); n.toinen = join(newtree, newtree.at(pos).toinen, tree.at(ownpos).toinen, depth + 1); n.tyhja = join(newtree, newtree.at(pos).tyhja, tree.at(ownpos).tyhja, depth + 1); tree.at(ownpos) = n; return ownpos; } std::cout << "BUG" << std::endl; return 0; } void print(const Nappula pelilauta[LAUDAN_KOKO][LAUDAN_KOKO], Siirto siirto) { int x, y; char oma = '@', toinen = 'O'; if (pelilauta[0][0] != TYHJA) { if (pelilauta[0][0] != OMA) { oma = 'O'; toinen = '@'; } } else if (pelilauta[6][6] != TYHJA) { if (pelilauta[6][6] != OMA) { oma = 'O'; toinen = '@'; } } else { std::cout << "EPIC FAIL!" << std::endl; } std::cout << oma << " "; for (y=0; y < LAUDAN_KOKO; y++) { for (x=0; x < LAUDAN_KOKO; x++) { switch (pelilauta[x][y]) { case OMA: std::cout << oma; break; case TOINEN: std::cout << toinen; break; default: std::cout << '.'; } } } std::cout << " " << siirto.alkuX << " " << siirto.alkuY; std::cout << " " << siirto.loppuX << " " << siirto.loppuY << std::endl; } void traverse(int paikka, Nappula pelilauta[LAUDAN_KOKO][LAUDAN_KOKO], int depth) { if (paikka == 0 && depth != 0) return; if (depth == LAUDAN_KOKO * LAUDAN_KOKO) { Siirto tulos; tulos.alkuX = (paikka & 0xFF000000) >> 24; tulos.alkuY = (paikka & 0x00FF0000) >> 16; tulos.loppuX = (paikka & 0x0000FF00) >> 8; tulos.loppuY = paikka & 0x000000FF; print(pelilauta, tulos); return; } Nappula &n = pelilauta[depth % 7][depth / 7]; n = OMA; traverse(tree.at(paikka).oma, pelilauta, depth + 1); n = TOINEN; traverse(tree.at(paikka).toinen, pelilauta, depth + 1); n = TYHJA; traverse(tree.at(paikka).tyhja, pelilauta, depth + 1); } }; class ThreadWrapper { private: PrecalcManager *pm; public: ThreadWrapper(PrecalcManager &npm) { pm = &npm; } void operator()() { pm->lasketilanne(-1); std::cout << "Thread finished!" << std::endl; } }; void print_time() { std::time_t t = std::time(NULL); std::cout << std::endl << std::ctime(&t); } int main(int argc, char *argv[]) { Nappula pelilauta[LAUDAN_KOKO][LAUDAN_KOKO] = {{TYHJA}}; PrecalcManager pm; if (argc == 2) { std::ifstream lahde(argv[1]); pm.lataa(lahde); lahde.close(); pm.traverse(0, pelilauta, 0); return EXIT_SUCCESS; } if (argc == 3) { std::ifstream lahde1(argv[1]); pm.lataa(lahde1); lahde1.close(); std::ifstream lahde2(argv[2]); pm.lataa(lahde2); lahde2.close(); std::ofstream kohde(argv[1]); pm.tallenna(kohde); kohde.close(); return EXIT_SUCCESS; } if (argc != 4) { std::cout << "Virhe parametreissa" << std::endl; return EXIT_FAILURE; } pm.aseta_tsyvyys(std::atoi(argv[2])); std::ifstream lahde(argv[1]); pm.lataa(lahde); lahde.close(); std::cout << "Ladattu!" << std::endl; if (argv[3][0] == 'o') { alustalauta(pelilauta, OMA); pm.vie_tilanne(pelilauta, 1); pm.lasketilanne(1); } else { alustalauta(pelilauta, TOINEN); std::vector tulokset; std::vector::const_iterator iter; ai_multirekursio(tulokset, TOINEN, pelilauta, std::atoi(argv[2])); Nappula lauta2[LAUDAN_KOKO][LAUDAN_KOKO]; for (iter = tulokset.begin(); iter < tulokset.end(); iter++) { memcpy(lauta2, pelilauta, sizeof(Nappula) * LAUDAN_KOKO * LAUDAN_KOKO); toteutasiirto(lauta2, *iter); pm.vie_tilanne(lauta2, 2); } } std::cout << "Jono: " << pm.status_queuesize() << std::endl; boost::thread_group threads; for (int i = 0; i < 2; i++) { ThreadWrapper thrd(pm); threads.create_thread(thrd); } std::cout << "Threads started!" << std::endl; std::string kasky(""); while (pm.status_siirtono() < MAX_SIIRTO) { std::getline(std::cin, kasky); print_time(); std::cout << "Tilanteita: " << pm.status_tilanteet() << std::endl; std::cout << "Puun koko: " << pm.status_treesize() << std::endl; std::cout << "Jono: " << pm.status_queuesize() << std::endl; std::cout << "Käsitelty: " << pm.status_tilanteet() - pm.status_queuesize() << std::endl; std::cout << "Lauta: " << pm.status_boardstate() << "/49" << std::endl; std::cout << "Siirto no: " << pm.status_siirtono() << std::endl; if (kasky.size() < 1) { continue; } if (kasky.at(0) == 's') { std::ofstream filu(argv[1]); pm.tallenna(filu); filu.close(); std::cout << "Tallennettu!" << std::endl; } else if (kasky.at(0) == 'q') { break; } else if (kasky.at(0) == 'd') { pm.vaihdanayta(); } } std::ofstream filu(argv[1]); pm.tallenna(filu); filu.close(); std::cout << "Lopetetaan!" << std::endl; threads.join_all(); return EXIT_SUCCESS; }