#include <iostream>
#include <cstdlib>
#include <vector>
#include <algorithm>
class atomic_int
{
private:
int _value;
public:
atomic_int(int initial = 0)
: _value(initial)
{ }
operator int (void)
{
return _value;
}
atomic_int& operator = (int value)
{
_value = value;
return *this;
}
atomic_int& operator ++(void)
{
++_value;
return *this;
}
void set_if_zero(int value)
{
if(!_value) _value = value;
}
};
class semaphore
{
private:
int _value;
public:
semaphore(int initial = 0)
: _value(initial)
{
if(initial < 0)
throw std::runtime_error("Invalid value for semaphore");
}
void wait(int dec = 1)
{
while(_value < dec)
_cond.wait(l);
_value -= dec;
}
void signal(int inc = 1)
{
_value += inc;
_cond.broadcast();
}
};
struct bingo_data
{
atomic_int round;
int number_count;
int number_range;
int number_of_players;
semaphore players_ready;
semaphore server_ready;
semaphore round_finished;
int current_number;
atomic_int winner;
};
void* server_func(void* raw_ptr)
{
assert(raw_ptr);
bingo_data& game = *static_cast<bingo_data*>(raw_ptr);
game.players_ready.wait(game.number_of_players);
while(!game.winner)
{
game.players_ready.wait(game.number_of_players);
game.current_number = std::rand() % game.number_range;
game.server_ready.signal(game.number_of_players);
game.players_ready.wait(game.number_of_players);
++game.round;
game.round_finished.signal(game.number_of_players);
}
game.players_ready.wait(game.number_of_players);
return nullptr;
}
void* player_func(void* raw_ptr)
{
assert(raw_ptr);
bingo_data& game = *static_cast<bingo_data*>(raw_ptr);
int id = game.current_number;
game.players_ready.signal();
int guessed = 0;
std::vector<int> ticket(game.number_count);
for(auto b=ticket.begin(),i=b; i!=ticket.end(); ++i)
{
while(true)
{
*i = std::rand() % game.number_range;
if(std::find(b, i, *i) == i) break;
}
}
game.players_ready.signal();
while(!game.winner)
{
game.players_ready.signal();
game.server_ready.wait();
auto p = std::find(ticket.begin(), ticket.end(), game.current_number);
if(p != ticket.end())
{
*p = -1;
if(++guessed == game.number_count)
{
game.winner.set_if_zero(id);
}
}
game.players_ready.signal();
game.round_finished.wait();
}
game.players_ready.signal();
return nullptr;
}
int main(int argc, const char* argv[])
{
std::srand(::getpid());
bingo_data game;
game.round = 0;
game.number_count = 20;
game.number_range = 1000;
game.number_of_players = 4;
game.current_number = 0;
game.winner = 0;
while(game.current_number != game.number_of_players)
{
++game.current_number;
game.players_ready.wait();
}
server.wait_for();
std::cout << game.winner << std::endl;
return 0;
}