Huffman Encoding priority queue - c++

I'm working on an assignment where I should write an encoding and decoding application for the Huffman algorithm, based on a priority queue. We have to read a file, count the frequencies of the letters and then start the algorithm. I have the following problem:
My counting function works fine but it stores the frequency of every letter in an array - even if it's zero. But if I want to use that array to build my min heap I get major problems because of the zeros. Therefore I need to find a way to 'eliminate' them. I can't just skip them because then the min heap algorithm doesn't work anymore (wrong neighbours). So I wanted to transfer all non-zero entries in a vector and use the vector instead of the array. But there I always get an error that tells me that there's a problem with the vector size. I don't really know how to deal with that problem. (My min heap still uses the array because I can't even transfer the entries in a vector).
(Please ignore the main I was just trying stuff there!)
using namespace std;
struct huffman_node
{ char data;
int frequency;
bool vector;
huffman_node *left;
huffman_node *right;
};
void swap_huffman_nodes(huffman_node &a, huffman_node &b)
{ char store_data = a.data;
int store_frequency = a.frequency;
a.data = b.data;
a.frequency=b.frequency;
b.data = store_data;
b.frequency = store_frequency;
huffman_node *store_left = a.left;
huffman_node *store_right= a.right;
a.left = b.left;
a.right = b.right;
b.left = store_left;
b.right = store_right;
}
void print_node (huffman_node a)
{ cout << a.data << a.frequency << endl;
}
string line;
huffman_node Table[52];
vector <huffman_node> non_zero;
void build_table()
{ for (int i=1; i<27; i++)
{ Table[i].data = (char) (i+64);
Table[i].left = NULL;
Table[i].right = NULL;
}
for (int i=27; i<53; i++)
{ Table[i].data = (char) (i+70);
Table[i].left = NULL;
Table[i].right = NULL;
}
}
int counter =0;
void count(){
ifstream yourfile ("example.txt");
if (yourfile.is_open())
{
while ( getline (yourfile,line) )
{
/*cout << line << '\n'; */
unsigned long z=line.length();
int i=0;
while ( i < z)
{ /* cout << line[i] << endl; */
for (int j=65; j<91; j++)
{ if ((int) line[i] == j)
{ int k=-64+j;
Table[k].frequency++;
}
}
for (int j=97; j<123; j++)
{ if ((int) line[i] == j)
{ int k=-70+j;
Table[k].frequency++;
}
}
i++;
}
}
for (int i=1; i<53; i++)
{ if (Table[i].frequency!=0)
{ non_zero.push_back(Table[i]);
counter ++;
}
}
yourfile.close();
}
else cout << "Unable to open file";
}
class heap{
public:
void buildheap()
{
for (int i=1; i<53; i++)
{reheap(i);
};
}
void reheap(int new_index)
{ int parent_index = new_index/2;
while (parent_index > 0 && Table[parent_index].frequency > Table[new_index].frequency)
{ swap_huffman_nodes(Table[parent_index], Table[new_index]);
parent_index=parent_index/2;
new_index=new_index/2;
}
};
void delete_root()
{ int non_null_entries=0;
for (int i=1; i<53; i++)
{ if (Table[i].frequency!=-1) {non_null_entries++;};
}
swap_huffman_nodes(Table[1],Table[non_null_entries]);
Table[non_null_entries].frequency=-1;
non_null_entries--;
rebuild_heap_root_deletion(1, non_null_entries);
}
void rebuild_heap_root_deletion(int new_root,int non_null_entries){
int n;
if (2 * new_root > non_null_entries){
return;
}
if (2 * new_root + 1 <= non_null_entries
&& Table[2*new_root+1].frequency < Table[2*new_root].frequency){
n = 2 * new_root + 1;
} else {
n = 2 * new_root;
}
if (Table[new_root].frequency > Table[n].frequency){
swap_huffman_nodes(Table[new_root], Table[n]);
rebuild_heap_root_deletion(n, non_null_entries);
}
}
void add_element(huffman_node new_heap_element)
{ for (int i=52; i>0;i-- )
{ if (Table[i].frequency==-1 && Table[i-1].frequency!=-1)
{ Table[i]=new_heap_element;
reheap(i);
break;
}
}
}
void print_Table()
{
for (int i=1; i<53; i++)
{ /*if (Table[i].frequency != -1) */
cout << Table[i].frequency << " , " << Table[i].data << endl;
}
}
bool empty_heap() // a heap is empty here if there are only "invalid huffman nodes" in it except the first one that contains all information.
{ for (int i=2; i < 53; i++)
{ if (Table[i].frequency!=-1)
{ return false;}
}
return true;
}
};
int main(){
ofstream myfile ("example.txt");
if (myfile.is_open())
{
myfile << "Flori ist ein Koala.";
myfile << "";
myfile.close();
}
else cout << "Unable to open file";
build_table();
count();
heap allan;
cout << "\n";
allan.buildheap();
allan.print_Table();
int i=0;
/*while(i<500)
{
huffman_node base_1 = Table[1];
allan.delete_root();
huffman_node base_2 = Table[1];
allan.delete_root();
huffman_node parent;
parent.data = '/';
parent.frequency = base_1.frequency + base_2.frequency;
parent.left = &base_1;
parent.right = &base_2;
allan.add_element(parent);
i++;
}
return 0;
}

Related

infix to postfix equations using stack

I am trying to make program that get infix to postfix but when I entered +- in the infix equation
the output should be +- but I find that the output is ++ and if infix is -+ the output is --
it have been a week since I started to solve that problem
#include <iostream>
#include <string>
using namespace std;
//classes
class arr
{
private:
char *items;
int size;
int length;
public:
//default constructor
arr()
{
items = new char[100];
size = 100;
length = 0;
}
//constructor with parameters
arr(int arraySize)
{
items = new char[arraySize];
size = arraySize;
length = 0;
}
//check if array is empty
bool is_empty()
{
return length == 0 ? true : false;
}
//check if array full
bool is_full()
{
return length >= size - 1 ? true : false;
}
//returns array length
int getLength()
{
return length;
}
//return array size
int getSize()
{
return size;
}
//get array address
char *getAddress()
{
return &items[0];
}
//fill number of items in array based on elementNum
void fill(int elementNum)
{
char ch;
cout << "Enter characters you want to add\n";
if (elementNum > size - 1)
{
cout << "can't use elements number largger than " << size - 1;
return;
}
for (int i = 0; i < elementNum; i++)
{
cin >> ch;
insert(i, ch);
}
}
//display all elements in the array
void display()
{
if (is_empty())
{
cout << "there are no data /n";
return;
}
cout << "Array items are :\n";
for (int i = 0; i < length; i++)
{
cout << items[i] << "\t";
}
cout << endl;
}
void append(char ch)
{
insert(length, ch);
}
void insert(int index, char newItem)
{
if (is_full() || length<index || length + 1 == size)
{
cout << "\nSorry array is full\ncan't append letter more\n";
return;
}
else {
for (int i = length; i >= index; i--)
{
items[i + 1] = items[i];
}
items[index] = newItem;
length++;
}
}
int search(char ch)
{
if (!is_empty())
for (int i = 1; i <= length; i++)
{
if (items[i] == ch)
return i;
}
return 0;
}
void del(int index)
{
if (is_empty() || length<index) {
cout << "sorry can't delete item which is doesn't exist";
return;
}
for (int i = index; i < length; i++)
{
items[i] = items[i + 1];
}
length--;
}
void changeSize(int newSize)
{
if (newSize <= length - 1)
{
cout << "can't change size because the new size is small";
return;
}
char *tempItems = new char[newSize];
size = newSize;
for (int i = 0; i < length; i++)
{
tempItems[i] = items[i];
}
items = tempItems;
tempItems = NULL;
}
//merge two arrays
void merge(arr a)
{
this->size = this->size + a.getSize();
for (int i = 0; i < a.getLength(); i++)
{
items[i + length] = a.getAddress()[i];
}
length = this->length + a.getLength();
}
};
class stackUsingArray {
private:
int top;
arr a;
public:
stackUsingArray()
{
top = -1;
}
stackUsingArray(int stackSize)
{
a.changeSize(stackSize);
top = -1;
}
bool is_empty()
{
return(top == -1);
}
bool is_full()
{
return(a.is_full());
}
void push(char ch)
{
top++;
a.append(ch);
}
char pop()
{
if (is_empty())
{
cout << "sorry the stack is empty";
}
else
return a.getAddress()[top--];
}
int peekTop() {
return top;
}
void display()
{
//first way of display
for (int i = top; i >= 0; i--)
{
cout << a.getAddress()[i];
}
//second way of display
//stackUsingArray c;
//char ch;
//for (int i = top; i >= 0; i--)
// c.push(this->pop());
//for (int i = c.peekTop(); i >= 0; i--)
//{
// ch=c.pop();
// this->push(ch);
// cout << ch;
//}
}
int search(char ch)
{
for (int i = top; i >= 0; i--)
{
if (a.getAddress()[i] == ch)
return i;
}
return -1;
}
char topDisplay()
{
return a.getAddress()[top];
}
};
class stackUsingLinkedList {};
//functions
string infixToPostfix(string infix);
short prec(char ch);
int main()
{
//infix and postfix
stackUsingArray c;
cout<<infixToPostfix("x+y-z");
system("pause");
return 0;
}
string infixToPostfix(string infix)
{
string postfix = "";
stackUsingArray sta;
char ch;
char test;
for (int i = 0; i < infix.length(); i++)
{
switch (prec(infix[i]))
{
case 0:
postfix.append(1, infix[i]);
break;
case 1:
sta.push(infix[i]);
break;
//case 2:
// ch = sta.pop();
// while (ch != '(')
// {
// postfix.append(1, ch);
// ch = sta.pop();
// }
// break;
case 3:
// if (sta.is_empty())
// {
// goto k270;
// }
// ch = sta.pop();
// while (prec(ch) > 3)
// {
// postfix.append(1, ch);
// if (sta.is_empty()) {
// //sta.push(infix[i]);
// goto k270;
// }
// ch = sta.pop();
// }
// sta.push(ch);
//k270:
// sta.push(infix[i]);
test = sta.topDisplay();
if (sta.is_empty())
{
sta.push(infix[i]);
test = sta.topDisplay();
}
else
{
ch = sta.pop();
test = sta.topDisplay();
if (prec(ch) >= 3)
{
postfix += ch;
}
sta.push(infix[i]);
}
}
}
while (!sta.is_empty())
{
postfix.append(1, sta.pop());
}
return postfix;
}
short prec(char ch)
{
if (ch == '(')
return 1;
if (ch == ')')
return 2;
if (ch == '+')
return 3;
if (ch == '-')
return 3;
if (ch == '*')
return 4;
if (ch == '/')
return 4;
return 0;
}
thanks to #IgorTandetnik I figured out that I should del last item from the array when I pop from stack

C++ property on class seems to be reinitialized

In the class Element, i have a property called size with default value 0.
When I call the insertElement on main() the line that calls size++ works fine but, in the next line when function shiftElementsToRight(i); are called, the size element are restarted to 0.
Why this happens? I'm declaring in wrong way my Element class?
Using g++ 9.2.1 on Ubuntu Linux
#include<iostream>
using namespace std;
int const ARRAY_MAX = 100;
class Element {
public:
int elements[ARRAY_MAX] = {};
int size = 0;
void shiftElementsToRight(int pos) {
int temp = elements[pos+1];
for (int i=ARRAY_MAX-1; i>=pos; i--) {
elements[i+1] = elements[i];
}
elements[pos] = NULL;
}
void shiftElementsToLeft(int pos) {
int temp = elements[pos];
int i = ARRAY_MAX;
for (int i=pos; i<ARRAY_MAX-1; i++) {
elements[i-1] = elements[i];
}
}
void insertElement(int value) {
int i = 0;
size++;
while ((i<ARRAY_MAX) && (elements[i] != NULL)) {
if (elements[i]>value) {
break;
}
i++;
}
shiftElementsToRight(i);
elements[i] = value;
}
int deleteElement(int value) {
int pos = binarySearch(value);
if (pos!=-1) {
shiftElementsToLeft(pos+1);
}
size--;
return pos;
}
int binarySearch(int value) {
int left = 0;
int right = size;
cout << "Begin" << endl;
while (left<right) {
int middle = left + (right -left) / 2;
cout << "L: " << left << " R: " << right << endl;
if (elements[middle] == value) {
return middle;
}
if (elements[middle]>value) {
right = middle-1;
}
if (elements[middle]<value) {
left = middle+1;
}
}
return -1;
}
};
int main() {
Element *element = new Element();
element->insertElement(3);
element->insertElement(2);
element->insertElement(5);
element->insertElement(6);
element->insertElement(4);
element->deleteElement(3);
return 0;
}
In
for (int i=ARRAY_MAX-1; i>=pos; i--) {
elements[i+1] = elements[i];
}
Your first access to elements is at position ARRAY_MAX - 1 + 1. You're accessing elements[ARRAY_MAX], which is outside the bounds of this array and (likely) points to size.

for-loop help getting wrong output

I am writing a code using classes and am getting the wrong output, this is my function definitions:
void PrintCard(int c)
{
int Rank = c%13;
int Suit = c/13;
const char NameSuit[5] = "SCDH";
const char NameRank[14] = "23456789XJQKA";
cout << NameRank[Rank] << NameSuit[Suit];
}
CardSet::CardSet()
{
Card = NULL;
nCards = 0;
}
CardSet::CardSet(int c)
{
Card = new int[c];
for(int i = 0; i > c; i++)
{
Card[i] = (i % 52);
}
}
CardSet::~CardSet()
{
delete[] Card;
}
bool CardSet::IsEmpty() const
{
return nCards == 0;
}
void CardSet::Print() const
{
for(int i=0; i > nCards; i++)
{
PrintCard(i);
}
}
int CardSet::Size() const
{
return nCards;
}
This is my main
cout << "Testing constructors, Print(), Size() & IsEmpty():" << endl;
CardSet CardSet1; // empty cCardSet
CardSet CardSet2(12); // CardSet with 12 cards
if(CardSet1.IsEmpty()) cout<<"CardSet1 is empty"<<endl;
else cout<<"CardSet1 has "<< CardSet1.Size() <<" cards" << endl;
if(CardSet2.IsEmpty()) cout<<"CardSet2 is empty"<<endl;
else cout<<"CardSet2 has "<< CardSet2.Size() <<" cards" << endl;
cout << "Printout of CardSet1: ";
CardSet1.Print();
cout << "Printout of CardSet2: ";
CardSet2.Print();
cout << endl;
when i am compiling i am getting the correct value (0) for cardset1 however for cardset2 instead of outputting a value of 12, which is what should be the output i am getting very high numbers that are changing each time i compile. i think something is wrong with my for loops or memory allocation.
this is also what the class definition looks like:
class CardSet
{
public:
CardSet();
CardSet(int);
~CardSet();
int Size() const;
bool IsEmpty() const;
void Shuffle();
int Deal();
void Deal(int,CardSet&,CardSet&);
void Deal(int,CardSet&,CardSet&,CardSet&,CardSet&);
void AddCard(int);
void MergeShuffle(CardSet&);
void Print() const;
private:
int* Card;
int nCards;
};
any help would be greatly appreciated !!
Cheers
In CardSet::CardSet change this
for(int i = 0; i > c; i++)
to this
for (int i = 0; i < c; i++)
Also in CardSet::Print change this
for(int i=0; i > nCards; i++)
To this:
for (int i = 0; i < nCards; i++)
Finally, add nCards = c; to CardSet::CardSet.
void CardSet::Print() const
{
for(int i=0; i > nCards; i++)
{
PrintCard(i);
}
}
must be
void CardSet::Print() const
{
for(int i=0; i < nCards; i++)
{
PrintCard(i);
}
}
to correct the end test, and you have the same problem in CardSet::CardSet(int c) which must be
CardSet::CardSet(int c)
{
nCards = c;
Card = new int[c];
for(int i = 0; i < c; i++)
{
Card[i] = (i % 52);
}
}
where nCards must also be set.
In a for the test indicates if the loop continues, not if it ends
for (inits; test; changes) ...
is equivalent to
init;
while (test) {
...
changes;
}
Out of that there is no separator in PrintCard doing cout << NameRank[Rank] << NameSuit[Suit]; so may be you also need to add something like a space in Print :
void CardSet::Print() const
{
for(int i=0; i < nCards; i++)
{
PrintCard(i);
cout << ' ';
}
}
or in PrintCard to also separate the two fields like
cout << NameRank[Rank] << ' ' << NameSuit[Suit] << endl;
Note you can simplify
const char NameSuit[5] = "SCDH";
const char NameRank[14] = "23456789XJQKA";
cout << NameRank[Rank] << NameSuit[Suit];
to be
cout << "23456789XJQKA"[Rank] << "SCDH"[Suit];
Or if you really want to have the arrays I encourage you to not give a size, that avoid problems if you change the literal string and forget to also change the size, so
const char NameSuit[] = "SCDH";
const char NameRank[] = "23456789XJQKA";
For instance having :
#include <iostream>
using namespace std;
class CardSet
{
public:
CardSet();
CardSet(int);
~CardSet();
int Size() const;
bool IsEmpty() const;
void Shuffle();
int Deal();
void Deal(int,CardSet&,CardSet&);
void Deal(int,CardSet&,CardSet&,CardSet&,CardSet&);
void AddCard(int);
void MergeShuffle(CardSet&);
void Print() const;
private:
int* Card;
int nCards;
};
void PrintCard(int c)
{
int Rank = c%13;
int Suit = c/13;
cout << "23456789XJQKA"[Rank] << ' ' << "SCDH"[Suit] << endl;
}
CardSet::CardSet()
{
Card = NULL;
nCards = 0;
}
CardSet::CardSet(int c)
{
nCards = c;
Card = new int[c];
for(int i = 0; i < c; i++)
{
Card[i] = (i % 52);
}
}
CardSet::~CardSet()
{
delete[] Card;
}
bool CardSet::IsEmpty() const
{
return nCards == 0;
}
void CardSet::Print() const
{
for(int i=0; i < nCards; i++)
{
PrintCard(i);
}
}
int CardSet::Size() const
{
return nCards;
}
int main(void)
{
CardSet cs(5);
cs.Print();
}
Compilation and execution :
pi#raspberrypi:/tmp $ g++ -pedantic -Wall -Wextra c.cc
pi#raspberrypi:/tmp $ ./a.out
2 S
3 S
4 S
5 S
6 S
pi#raspberrypi:/tmp $
You should review it (the loop)
void CardSet::Print() const
{
for(int i=0; i > nCards; i++)//## reconsider it
{
PrintCard(i);
}
}

Minimax algorithm for Specker Game

I am creating an minimax player for a game called Specker in c++.
The rules are simple:
There are p players (0 to p - 1) and n heaps (0 to n - 1)
Starting with player 0 each player takes k > 0 coins from a heap x and places m coins (0 <= m < k) on heap y
The winning player is the one which plays last when all coins from all heaps are removed
So I have created the game and some player classes (GreedyPlayer, SpartanPlayer etc.) but they all are a little bit predictable on what they will do. They aren't clever.
so i am creating a player who plays according to minimax (pt18a038)code compiles fine but the program stops responding on execution.
the clever player class:
class pt18a038 : public Player {
private:
string player_type;
public:
pt18a038(const string &n) : Player(n) {
player_type = "Asder aka theRunner";
}
virtual const string &getType() const override {
return player_type;
}
virtual Move play(const State &s) override {
int source_heap = 0;
int target_heap = 0;
int source_coins = 0;
int target_coins = 0;
int sum = 0;
for (source_heap = 0; source_heap < s.getHeaps(); source_heap++) {
for (source_coins = 1; source_coins <= s.getCoins(source_heap); source_coins++) {
for (target_heap = 0; target_heap < s.getHeaps(); target_heap++) {
for (target_coins = 0; target_coins <= source_coins; target_coins++) {
Move m(source_heap, source_coins, target_heap, target_coins);
sum = minimax(s, 3, 0, m);
cout << "Play:" << source_heap << "," << source_coins << "," << target_heap << ","
<< target_coins << ":" << sum << endl;
}
}
}
}
cout << sum << endl;
// ///////////// for debbuging only until minimax is working...
source_heap = 0;
source_coins = 0;
for (int i = 0; i < s.getHeaps(); i++) {
if (s.getCoins(i) > source_coins) {
source_heap = i;
source_coins = s.getCoins(i);
}
}
Move SpartanObject(source_heap, 1, 0, 0);
return SpartanObject;
// /////////////
}
static int minimax(State s, const int &players, int depth, const Move move) {
if (s.winning()) {
cout << "game end!" << endl;
return 1000;
if (depth % players == 0) return 1000; //Maximazing player
else return -1000; //Minimazing player
}
if (depth > 4) {
//cout<<"optimazing"<<endl;
return 0;
}
//cout << s << endl;
s.next(move);
int source_heap = 0;
int target_heap = 0;
int source_coins = 0;
int target_coins = 0;
int max = -100000;
int min = 100000;
int result;
for (source_heap = 0; source_heap < s.getHeaps(); source_heap++) {
for (source_coins = 1; source_coins <= s.getCoins(source_heap); source_coins++) {
for (target_heap = 0; target_heap < s.getHeaps(); target_heap++) {
for (target_coins = 0; target_coins <= source_coins; target_coins++) {
//cout << "Move:" << source_heap << "," << source_coins << "," << target_heap << ","<< target_coins << endl;
Move m(source_heap, source_coins, target_heap, target_coins);
result = minimax(s, players, depth + 1, m);
if (depth % players == 0) {
max = result ? (result > max) : result;
} else {
min = result ? (result < min) : result;
}
}
}
}
}
return max ? (depth % players == 0) : min;
}
};
Here is my code for the rest of the game(it's tested and works fine)
#include <iostream>
#include <stdexcept>
using namespace std;
class Move {
private:
int source_heap, source_coins, target_heap, target_coins;
public:
Move(int sh, int sc, int th, int tc) {
source_heap = sh;
source_coins = sc;
target_heap = th;
target_coins = tc;
}
int getSource() const {
return source_heap;
}
int getSourceCoins() const {
return source_coins;
}
int getTarget() const {
return target_heap;
}
int getTargetCoins() const {
return target_coins;
}
// Let's do some operator overloading
friend ostream &operator<<(ostream &out, const Move &move) {
if (move.getTargetCoins()) {
out << "takes " << move.getSourceCoins() << " coins from heap "
<< move.getSource() << " and puts " << move.getTargetCoins()
<< " coins to heap " << move.getTarget();
} else {
out << "takes " << move.getSourceCoins() << " coins from heap "
<< move.getSource() << " and puts nothing";
}
}
};
class State {
// State with h heaps, where the i-th heap starts with c[i] coins.
private:
int heaps, *heap_coins;
public:
State(int h, const int c[]) {
heaps = h;
heap_coins = new int[heaps];
for (int i = 0; i < heaps; i++)
heap_coins[i] = c[i];
}
~State() {
delete[] heap_coins;
return;
}
int getCoins(int h) const throw(logic_error) {
if (h < 0 || h > heaps) {
throw logic_error(
"Invalid heap number, enter a number between 1 and heaps!");
return 1;
} else {
return heap_coins[h];
}
}
void next(const Move &move) throw(logic_error) {
if ((move.getSource() < 0) || (move.getSource() > heaps) ||
(move.getTarget() < 0) || (move.getTarget() > heaps)) {
throw logic_error("Invalid Heap!");
return;
} else if (
(move.getSourceCoins() < 1) || (move.getTargetCoins() < 0) ||
(move.getSourceCoins() <= move.getTargetCoins()) ||
(move.getSourceCoins() > getCoins(move.getSource()))) {
throw logic_error("Invalid Coin number!");
} else {
heap_coins[move.getSource()] -= move.getSourceCoins();
heap_coins[move.getTarget()] += move.getTargetCoins();
}
}
bool winning() const {
int s = 0;
for (int i = 0; i < heaps; i++)
s += getCoins(i);
return not s; // yeah i know how booleans work :P
}
int getHeaps() const {
return heaps;
}
friend ostream &operator<<(ostream &out, const State &state) {
for (int i = 0; i < state.getHeaps(); i++) {
out << state.heap_coins[i];
if (i != state.getHeaps() - 1)
out << ", ";
}
return out;
}
};
class Player {
public:
Player(const string &n);
virtual ~Player();
virtual const string &getType() const = 0;
virtual Move play(const State &s) = 0;
friend ostream &operator<<(ostream &out, const Player &player);
protected:
string player_name;
};
class GreedyPlayer : public Player {
private:
string player_type;
public:
GreedyPlayer(const string &n) : Player(n) {
player_type = "Greedy";
}
virtual const string &getType() const override {
return player_type;
}
virtual Move play(const State &s) override {
int source_heap = 0;
int source_coins = 0;
for (int i = 0; i < s.getHeaps(); i++) {
if (s.getCoins(i) > source_coins) {
source_heap = i;
source_coins = s.getCoins(i);
}
}
Move GreedyObject(source_heap, source_coins, 0, 0);
return GreedyObject;
}
};
class SpartanPlayer : public Player {
public:
SpartanPlayer(const string &n) : Player(n) {
player_type = "Spartan";
}
virtual const string &getType() const override {
return player_type;
}
virtual Move play(const State &s) override {
int source_heap = 0;
int source_coins = 0;
for (int i = 0; i < s.getHeaps(); i++) {
if (s.getCoins(i) > source_coins) {
source_heap = i;
source_coins = s.getCoins(i);
}
}
Move SpartanObject(source_heap, 1, 0, 0);
return SpartanObject;
}
private:
string player_type;
};
class SneakyPlayer : public Player {
public:
SneakyPlayer(const string &n) : Player(n) {
player_type = "Sneaky";
}
virtual const string &getType() const override {
return player_type;
}
virtual Move play(const State &s) override {
int j = 0;
while (s.getCoins(j) == 0) {
j++;
}
int source_heap = j;
int source_coins = s.getCoins(j);
for (int i = j + 1; i < s.getHeaps(); i++) {
if ((s.getCoins(i) < source_coins) && (s.getCoins(i) > 0)) {
source_heap = i;
source_coins = s.getCoins(i);
}
}
Move SneakyObject(source_heap, source_coins, 0, 0);
return SneakyObject;
}
private:
string player_type;
};
class RighteousPlayer : public Player {
public:
RighteousPlayer(const string &n) : Player(n) {
player_type = "Righteous";
}
virtual const string &getType() const override {
return player_type;
}
virtual Move play(const State &s) override {
int target_heap = 0;
int source_heap = 0;
int source_coins = s.getCoins(0);
int target_coins = source_coins;
for (int i = 1; i < s.getHeaps(); i++) {
if (s.getCoins(i) > source_coins) {
source_heap = i;
source_coins = s.getCoins(i);
} else if (s.getCoins(i) < target_coins) {
target_heap = i;
target_coins = s.getCoins(i);
}
}
source_coins -= source_coins / 2;
Move RighteousObject(
source_heap, source_coins, target_heap, source_coins - 1);
return RighteousObject;
}
private:
string player_type;
};
Player::Player(const string &n) {
player_name = n;
}
Player::~Player() {
player_name.clear();
}
ostream &operator<<(ostream &out, const Player &player) {
out << player.getType() << " player " << player.player_name;
return out;
}
class Game {
private:
int game_heaps, game_players, current_heap, current_player;
int *heap_coins;
Player **players_list;
public:
Game(int heaps, int players) {
heap_coins= new int [heaps];
game_heaps = heaps;
game_players = players;
current_heap = 0;
current_player = 0;
players_list = new Player*[players];
}
~Game() {
delete[] heap_coins;
delete[] players_list;
}
void addHeap(int coins) throw(logic_error) {
if (current_heap > game_heaps)
throw logic_error("All heaps are full with coins!");
else if (coins < 0)
throw logic_error("Coins must be a positive number!");
else {
heap_coins[current_heap++] = coins;
}
}
void addPlayer(Player *player) throw(logic_error) {
if (current_player > game_players)
throw logic_error("All players are added!");
else {
players_list[current_player++] = player;
}
}
void play(ostream &out) throw(logic_error) {
if ((current_player != game_players) && (current_heap != game_heaps)) {
throw logic_error("Have you added all heaps and players?");
} else {
int i = 0;
State currentState(game_heaps, heap_coins);
while (!currentState.winning()) {
out << "State: " << currentState << endl;
out << *players_list[i % game_players] << " "
<< players_list[i % game_players]->play(currentState) << endl;
currentState.next(
players_list[i % game_players]->play(currentState));
i++;
}
out << "State: " << currentState << endl;
i--;
out << *players_list[i % game_players] << " wins" << endl;
}
}
};
int main() {
Game specker(6, 5);
specker.addHeap(10);
specker.addHeap(20);
specker.addHeap(17);
specker.addHeap(17);
specker.addHeap(17);
specker.addHeap(17);
specker.addPlayer(new GreedyPlayer("Alan"));
specker.addPlayer(new SneakyPlayer("Tom"));
specker.addPlayer(new SpartanPlayer("Mary"));
specker.addPlayer(new RighteousPlayer("Robin"));
specker.addPlayer(new pt18a038("Stavros"));
specker.play(cout);
}
Updated
I see a couple of issues in your minimax program, some are serious in nature :
1) Use Alpha Beta pruning to reduce the size of the search tree.
2) There is no proper boundary condition (if depth >5 return score or something) in the minimax recursive call ( see my code snippet for details), the CPU may hang while calling.
3)Your leaf node evaluation is weak, so the evaluated moves , in spite of using minimax algorithm, is not likely to be intelligent ones.
4)To increase the search speed, you may use multi-threading only at the top level branch.
5) If a leaf node gives a winning move while maximizing, you may skip further evaluation by returning a high score.
6) Once your code is functional, refer it at code-review with 'ai' tag , rather than at SO, for more detailed analysis.
int EvaluateLeafNode(State s, const int &players)
{
//TODO analyze here
return score;
}
int minimax(State s, const int &players, int depth , const Move move, int alpha, int beta)
{
if( depth >= 5) return EvaluateLeafNode(s,players); // this was missing in your code
//don't analyze here
//rest of minimax recursive code
}

Terminate called after throwing an instance of std::bad_alloc. Using two classes, one with a pointer to the other

My program keeps getting me bad alloc error when I use a normal function that contains a member function.
The program is about taking some specific inputs from the command line and printing the elements of an array of pointers. This has to be done with array of pointers.
To begin with, I created a class that needs to have 2 strings. One for the name and one for the room. Then I created another class with a size and a pointer to my first class in order to create an array.
My main is at the end, and above main are the 2 normal functions. What is wrong with this code? When I type the commands for the first time of the loop it works until I enter a command that connects to a normal function. Probably something is wrong there but I can't seem to find it.
#include <iostream>
#include <string>
using namespace std;
class Address
{
private:
string name;
string room;
public:
Address(){};
Address(string, string);
string get_name();
string get_room();
void change_room(string);
};
Address::Address (string n, string r)
{
name = n;
room = r;
}
string Address::get_name()
{
return name;
}
string Address::get_room()
{
return room;
}
void Address::change_room(string change)
{
room = change;
}
//end of Address class
class Address_Book
{
private:
int size;
Address* addresses;
public:
Address_Book();
~Address_Book(){ delete[] addresses;}
void add(Address);
void move(string, string);
int get_size();
Address location(int);
int find(string);
void clear();
void remove_address(string);
int exists(string);
void sort();
};
Address_Book::Address_Book()
{
int s = 0;
size = s;
addresses = new Address[s];
}
void Address_Book::add(Address add)
{
Address* temp = new Address [size + 1];
for (int i = 0; i < size; i++)
{
temp[i] = addresses[i];
}
temp[size] = add;
delete[] addresses;
addresses = temp;
size ++;
}
void Address_Book::move(string name, string newroom)
{
for (int i = 0; i < size ; i++)
{
if (addresses[i].get_name() == name )
{
addresses[i].change_room(newroom);
}
}
}
void Address_Book::remove_address(string name)
{
Address* temp = new Address [size - 1];
for (int i = 0; i < size; i++)
{
if (addresses[i].get_name() != name)
{
temp[i] = addresses[i];
}
else if (addresses[i].get_name() == name)
{
for (int j = i + 1; j < size; j++)
{
temp[i] = addresses[j];
i++;
}
break;
}
}
delete[] addresses;
addresses = temp;
size--;
}
int Address_Book::get_size()
{
return size;
}
Address Address_Book::location(int index)
{
return addresses[index];
}
void Address_Book::sort()
{
Address temp;
for (int i = 0; i < size; i++)
{
for(int j = 0; j < size - 1; j++)
{
if (addresses[j].get_room() > addresses[j + 1].get_room())
{
temp = addresses[j];
addresses[j] = addresses[j + 1];
addresses[j + 1] = temp;
}
}
}
for (int i = 0; i < size; i++)
{
if (addresses[i].get_room() == addresses[i + 1].get_room())
{
if (addresses[i].get_name() > addresses[i + 1].get_name())
{
temp = addresses[i];
addresses[i] = addresses[i + 1];
addresses[i + 1] = temp;
}
}
}
}
void Address_Book::clear()
{
Address * temp = new Address[0];
delete[] addresses;
addresses = temp;
size = 0;
}
int Address_Book::find(string name)
{
for (int i = 0; i < size; i++)
{
if (addresses[i].get_name() == name)
{
return i;
}
}
return -1;
}
//end of Address_Book class
void find(string name, Address_Book addbook)
{
int index = addbook.find(name);
cout << index << endl;
if (index > -1)
{
cout << addbook.location(index).get_name() << " is in room " <<
addbook.location(index).get_room() << endl;
}
else
{
throw runtime_error("entry does not exist.");
}
}
void remove_add(string name, Address_Book book)
{
int exist = book.find(name);
if (exist > -1)
{
book.remove_address(name);
}
else
{
throw runtime_error("entry does not existt.");
}
}
int main()
{
Address_Book addbook;
string action, in_name, in_room;
do
{
try
{
cout << "> ";
cin >> action;
if (action == "add")
{
cin >> in_name >> in_room;
Address newadd(in_name, in_room);
addbook.add(newadd);
}
else if (action == "move")
{
cin >> in_name >> in_room;
addbook.move(in_name, in_room);
}
else if (action == "remove")
{
cin >> in_name;
remove_add(in_name, addbook);
}
else if (action == "find")
{
cin >> in_name;
find(in_name, addbook);
}
else if (action == "list")
{
addbook.sort();
for (int i = 0; i < addbook.get_size(); i++)
{
cout << addbook.location(i).get_name() << " is in room
" << addbook.location(i).get_room() << endl;
}
}
else if (action == "clear")
{
addbook.clear();
}
else
{
throw runtime_error("input mismatch.");
}
}
catch (runtime_error& e)
{
cerr << "error: " << e.what() << endl;
}
}while (action != "exit");
return 0;
}
The function remove_add needs to get the address book object by reference or by pointer.
The way it is now, it removes from a copy of the address book.
It should look like this:
void remove_add(string name, Address_Book& book)
{
int exist = book.find(name);
if (exist > -1)
{
book.remove_address(name);
}
else
{
throw runtime_error("entry does not existt.");
}
}
Also, you should probably do something different in case size == 1 in the following function. e.g. set addresses to NULL, zero or nullptr if your compiler supports it.
void Address_Book::remove_address(string name)
{
Address* temp = new Address[size - 1];
for (int i = 0; i < size; i++)
{
if (addresses[i].get_name() != name)
{
temp[i] = addresses[i];
}
else if (addresses[i].get_name() == name)
{
for (int j = i + 1; j < size; j++)
{
temp[i] = addresses[j];
i++;
}
break;
}
}
delete[] addresses;
addresses = temp;
size--;
}
Have fun learning the language and good luck :)
The exact commands that lead to your problem are not specified in your question, so I poked around a little bit until the code crashed with a segmentation fault.
Valgrind and Dr. Memory are awesome tools for finding root causes of such problems. In your case:
$ g++ -g 46865300.cpp
$ valgrind ./a.out
> add foo bar
> list
==102== Invalid read of size 8
==102== at 0x4EF4EF8: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) (in /usr/lib64/libstdc++.so.6.0.19)
==102== by 0x401354: Address::get_room() (46865300.cpp:33)
==102== by 0x401C05: Address_Book::sort() (46865300.cpp:152)
==102== by 0x4026A3: main (46865300.cpp:262)
==102== Address 0x5a17410 is 8 bytes after a block of size 24 alloc'd
==102== at 0x4C2A8A8: operator new[](unsigned long) (vg_replace_malloc.c:423)
==102== by 0x4014BF: Address_Book::add(Address) (46865300.cpp:74)
==102== by 0x40245C: main (46865300.cpp:243)
It says that the following code performs out-of-bounds access:
150 for (int i = 0; i < size; i++)
151 {
152 if (addresses[i].get_room() == addresses[i + 1].get_room())
153 {
154 if (addresses[i].get_name() > addresses[i + 1].get_name())
I guess the loop condition should use "size - 1" instead of "size".