#include "stdafx.h"
#include <iostream>
using std::cin;
using std::cout;
using std::ios;
#include <fstream>
using std::ifstream;
#include <string>
using std::string;
#include <list>
using std::list;
using std::iterator;
#include <cstring>


// funkcja pomocnicza, pozwalajca na poprawne wywietlanie
// polskich znakw w konsoli
string ToPl(string str) {          
   for (unsigned int i = 0; i < str.length(); i++)
   {
      switch(str[i])
      {
         case '':
            str[i] = static_cast<unsigned char>(165);
            break;
 
         case '':
            str[i] = static_cast<unsigned char>(134);
            break;
 
         case '':
            str[i] = static_cast<unsigned char>(169);
            break;
 
         case '':
            str[i] = static_cast<unsigned char>(136);
            break;
 
         case '':
            str[i] = static_cast<unsigned char>(228);
            break;
 
         case '':
            str[i] = static_cast<unsigned char>(162);
            break;
 
         case '':
            str[i] = static_cast<unsigned char>(152);
            break;
 
         case '':
            str[i] = static_cast<unsigned char>(171);
            break;
 
         case '':
            str[i] = static_cast<unsigned char>(190);
            break;
 
         case '':
            str[i] = static_cast<unsigned char>(164);
            break;
 
         case '':
            str[i] = static_cast<unsigned char>(143);
            break;
 
         case '':
            str[i] = static_cast<unsigned char>(168);
            break;
 
         case '':
            str[i] = static_cast<unsigned char>(157);
            break;
 
         case '':
            str[i] = static_cast<unsigned char>(227);
            break;
 
         case '':
            str[i] = static_cast<unsigned char>(224);
            break;
 
         case '':
            str[i] = static_cast<unsigned char>(151);
            break;
 
         case '':
            str[i] = static_cast<unsigned char>(141);
            break;
 
         case '':
            str[i] = static_cast<unsigned char>(189);
            break;
       }
   }
   return str;
}

void removeWordsWithLetter(list<string> & wordList, char forbiddenLetter) {
   list<string>::const_iterator iter;
   iter = wordList.begin();
   while (iter != wordList.end()) {
      if (iter->find(forbiddenLetter) != string::npos) {
         iter = wordList.erase(iter);
      } else {
         iter++;
      }
   }
}

void removeWordsWithoutLetter(list<string> & wordList, char requiredLetter) {
   list<string>::const_iterator iter;
   iter = wordList.begin();
   while (iter != wordList.end()) {
      if (iter->find(requiredLetter) == string::npos) {
         iter = wordList.erase(iter);
      } else {
         iter++;
      }
   }
}

int countWordsWithoutLetter(const list<string> & wordList, char letter) {
   list<string>::const_iterator iter;
   int count = 0;
   iter = wordList.begin();
   while (iter != wordList.end()) {
      if (iter->find(letter) == string::npos) {
         count++;
      }
      iter++;
   }
   return count;
}

bool numberInPattern(const list<int> & pattern, int number) {
   list<int>::const_iterator iter;
   iter = pattern.begin();
   while (iter != pattern.end()) {
      if (*iter == number) {
         return true;
      }
      iter++;
   }
   return false;
}

bool matchesPattern(string word, char letter, list<int> pattern) {
   for (unsigned int i = 0; i < word.length(); i++) {
      if (word[i] == letter) {
         if (!numberInPattern(pattern, i)) {
            return false;
         }
      } else {
         if (numberInPattern(pattern, i)) {
            return false;
         }
      }
   }
   return true;
}

list<string> reduceByPattern(const list<string> & wordList, char letter, list<int> pattern) {
   list<string> newList;
   list<string>::const_iterator iter;
   iter = wordList.begin();
   while (iter != wordList.end()) {
      if (matchesPattern(*iter, letter, pattern)) {
         newList.push_back(*iter);
      }
      iter++;
   }
   return newList;
}

void mostFreqPatternByLetter(list<string> wordList, char letter, list<int> & maxPattern, int & maxPatternCount) {
   removeWordsWithoutLetter(wordList, letter);
   list<string>::iterator iter;
   maxPatternCount = 0;
   while (wordList.size() > 0) {
      iter = wordList.begin();
      list<int> currentPattern;
      for (unsigned int i = 0; i < iter->length(); i++) {
         if ((*iter)[i] == letter) {
            currentPattern.push_back(i);
         }
      }
      int currentPatternCount = 1;
      iter = wordList.erase(iter);
      while (iter != wordList.end()) {
         if (matchesPattern(*iter, letter, currentPattern)) {
            currentPatternCount++;
            iter = wordList.erase(iter);
         } else {
            iter++;
         }
      }
      if (currentPatternCount > maxPatternCount) {
         maxPatternCount = currentPatternCount;
         maxPattern = currentPattern;
      }
      currentPattern.clear();
   }
}

void removeWordsOfWrongLength(list<string> & wordList, int acceptableLength) {
   list<string>::iterator iter;
   iter = wordList.begin();
   while (iter != wordList.end()) {
      if (iter->length() != acceptableLength) {
         iter = wordList.erase(iter);
      } else {
         iter++;
      }
   }
}

void displayList(const list<string> & wordList) {
   list<string>::const_iterator iter;
   iter = wordList.begin();
   while (iter != wordList.end()) {
      cout << iter->c_str() << "\n";
      iter++;
   }
}

int letterCount(string word, char letter) {
   int count = 0;
   for (unsigned int i = 0; i < word.length(); i++) {
      if (word[i] == letter) count++;
   }
   return count;
}

void displayGuessedLetters(bool letters[26]) {
   cout << ToPl("Uyte litery: ");
   for (int i = 0; i < 26; i++) {
      if (letters[i]) cout << (char)('a' + i) << " ";
   }
   cout << "\n";
}

list<string> readWordFile(char * filename) {
   list<string> wordList;
   ifstream wordFile(filename, ios::in);
   if (!wordFile) {
      cout << "Problem z otwarciem pliku\n";
      return wordList;
	}
   char currentWord[30];
   char diacriticPL[] = "󜟿ʣӌ";
   int size = strlen(diacriticPL);
   int i;
   while (wordFile >> currentWord) {
         for (i = 0; i < size; i++)
            if (strchr(currentWord, diacriticPL[i]) != 0)
               break;
               
         if (i < size)
            continue;
            
         string temp(currentWord);
         wordList.push_back(temp);
   }
   return wordList;
}




int main()
{
   // plik lista.txt ze sowami znajduje si w pakiecie zip
   // moesz take samemu wyszuka taki plik, posugujc si stron Google
   list<string> wordList = readWordFile("lista.txt");


   const int wordLength = 5;
   const int maxMisses = 9;
   int misses = 0;
   int discoveredLetterCount = 0;
   removeWordsOfWrongLength(wordList, wordLength);

   char revealedWord[wordLength + 1] = "*****";

   bool guessedLetters[26];
   for (int i = 0; i < 26; i++) guessedLetters[i] = false;

   char nextLetter;
   cout << ToPl("Zgadywane sowo: ") << revealedWord << "\n";
   while (discoveredLetterCount < wordLength && misses < maxMisses) {
      cout << ToPl("Podaj liter: ");
      cin >> nextLetter;
      guessedLetters[nextLetter - 'a'] = true;
      int missingCount = countWordsWithoutLetter(wordList, nextLetter);
      list<int> nextPattern;
      int nextPatternCount;
      mostFreqPatternByLetter(wordList, nextLetter, nextPattern, nextPatternCount);
      if (missingCount > nextPatternCount) 
      {
         removeWordsWithLetter(wordList, nextLetter);
         misses++;
      } 
      else 
      {
         list<int>::iterator iter = nextPattern.begin();
         while (iter != nextPattern.end()) 
         {
            discoveredLetterCount++;
            revealedWord[*iter] = nextLetter;
            iter++;
         }
         wordList = reduceByPattern(wordList, nextLetter, nextPattern);
      }
      // Jeli usuniesz znak komentarza przy wierszu z wywoaniem funkcji displayList,
      // zobaczysz sowa, ktre s dostpne na "licie kandydatw" po kadej prbie odgadnicia.
      // Jest to bardzo przydatne do testowania
      // displayList(wordList);
      cout << ToPl("Zgadywane sowo: ") << revealedWord << "\n";
      displayGuessedLetters(guessedLetters);
   }

   if (misses == maxMisses) {
      cout << ToPl("Niestety przegrae. Sowo, o ktrym mylaem, brzmi: '");
      cout << (wordList.cbegin())->c_str() << "'.\n";
   } else {
      cout << ToPl("Gratulacje - wygrae! Mylaem o sowie '") << revealedWord << "'.\n";
   }
	
   
   cout << ToPl("Nacinij Enter, by wyj");
   std::cin.ignore(std::cin.rdbuf()->in_avail() + 1);
   
   return 0;
}

