<commit_before>/* Android: Netrunner - Arena drafting */
constexpr int BUILD_NUMBER = 446;

/* Dependency: JSON for Modern C++
 * https://github.com/nlohmann/json
 */
#include <json.hpp>
using json = nlohmann::json;

/* Dependency: Bloat-free Immediate Mode Graphical User interface for C++ 
 * https://github.com/ocornut/imgui
 */
#include <imgui.h>
#include "imgui_impl_glfw.h"

 /* Dependency: GLFW is a free, Open Source, multi-platform library for OpenGL, OpenGL ES and Vulkan application development.
 * http://www.glfw.org/
 */
#include <GLFW/glfw3.h>

 /* Dependency: stb single-file public domain libraries for C/C++
 * https://github.com/nothings/stb
 */
#define STB_IMAGE_IMPLEMENTATION
#define STBI_ONLY_PNG
#include <stb_image.h>

#include <random>
#include <chrono>
#include <iostream>
#include <fstream>
#include <future>
#include <algorithm>
#include <cassert>

#include "enums.h"

std::default_random_engine g_rng;

constexpr size_t g_max_cards = 5120;
GLuint g_texture[g_max_cards];
GLuint g_side_tex[2];

class Card
{
public:
	Faction faction;
	int influence;
	int agenda_points;
	std::string name;
	std::string type;
	int pack_number;
	Pack pack;
	int copies;
	GLuint texId;
};

class Deck
{
public:
	Card identity;
	std::vector<Card> cards;
};

enum class GuiState
{
	Start,
	SideSelect,
	CorpFactionSelect,
	RunnerFactionSelect,
	CorpCardsSelect,
	RunnerCardsSelect,
	Summary
};

// Available cards and ids, unavailable cards will be removed during drafting
std::vector<Card> g_corp_ids;
std::vector<Card> g_runner_ids;
std::vector<Card> g_corp_cards;
std::vector<Card> g_runner_cards;

// card statistics
std::map<int, std::pair<int, int>> g_stats;

// user options:
// allow duplicates in selection?
bool opt_allowDuplicates = false;
// meaning of influence
enum OPT_INFLUENCE
{
	OPT_NORMAL = 0,  // normal influence rules
	OPT_NOINF,		 // influence has no meaning
	OPT_DISALLOW3INF // ensure atleast one 0 influence card in choice
};
int opt_influence = OPT_NORMAL;
// draw more than minimum deck size?
int opt_plusCards = 0;
// selected packs
std::map<Pack, int> g_allowed_packs;

// draw and remove a random card from the deck vector
// reqs contains optional requierments 
Card draw_card(std::vector<Card>& deck, std::vector<std::function<bool(Card)>> reqs = std::vector<std::function<bool(Card)>>())
{
	// TODO: gracefully handling
	assert(deck.size() > 0 && "Can't draw from empty deck.");
	size_t pos;

	std::vector<size_t> req_deck;
	for (size_t i = 0; i < deck.size(); i++)
	{
		bool skip = false;
		for (auto req : reqs) if (!req(deck[i])) { skip = true; break; }
		if (!skip) req_deck.push_back(i);
	}
	assert(req_deck.size() > 0 && "Can't draw from filtered deck.");
	std::uniform_int_distribution<size_t> distribution(0, req_deck.size() - 1);
	pos = distribution(g_rng);
	pos = req_deck.at(pos);

	Card c = deck.at(pos);
	deck.erase(deck.begin() + pos);
	return c;
}

int influenceCost(Card c, Faction id)
{
	if (c.faction == id) return 0;
	return c.influence;
}

// get min deck size, available influence and corp points for a specific identity.
// remove Jinteki cards when using "Custom Biotics"
// TODO: read this information from nrdb json dump 
void setIdentity(Card identity, int& cards, int& influence, int& points)
{
	cards = 45;
	influence = 15;
	if (identity.pack == Pack::CreationAndControl && identity.pack_number == 2)						/* identity.name == "Custom Biotics: Engineered for Success" */
	{
		influence = 22;
		g_corp_cards.erase(std::remove_if(g_corp_cards.begin(), g_corp_cards.end(), [](const Card& c) { return c.faction == Faction::Jinteki; }), g_corp_cards.end());
	}
	if (identity.pack == Pack::ChromeCity && identity.pack_number == 50) cards = 40;				/* identity.name == "Cybernetics Division: Humanity Upgraded" */
	if (identity.pack == Pack::FearAndLoathing && identity.pack_number == 97) influence = 10;		/* identity.name == "GRNDL: Power Unleashed" */
	if (identity.pack == Pack::HonorAndProfit && identity.pack_number == 1)							/* identity.name == "Harmony Medtech: Biomedical Pioneer" */
	{
		cards = 40;
		influence = 12;
	}
	if (identity.pack == Pack::FutureProof && identity.pack_number == 114)							/* identity.name == "NBN: The World is Yours*" */
	{
		cards = 40;
		influence = 12;
	}
	if (identity.pack == Pack::Upstalk && identity.pack_number == 5) influence = 17;				/* identity.name == "Near-Earth Hub: Broadcast Center" */
	if (identity.pack == Pack::CreationAndControl && identity.pack_number == 3) influence = 12;		/* identity.name == "NEXT Design: Guarding the Net" */
	if (identity.pack == Pack::DataAndDestiny && identity.pack_number == 1) cards = 40;				/* identity.name == "SYNC: Everything, Everywhere" */
	if (identity.pack == Pack::OrderAndChaos && identity.pack_number == 3) influence = 17;			/* identity.name == "Titan Transnational: Investing In Your Future" */

	if (identity.pack == Pack::CyberExodus && identity.pack_number == 46) cards = 40;				/* identity.name == "Chaos Theory: W\u00fcnderkind" */
	if (identity.pack == Pack::HonorAndProfit && identity.pack_number == 28) influence = 10;		/* identity.name == "<NAME>: Retired Spook" */
	if (identity.pack == Pack::HonorAndProfit && identity.pack_number == 29) influence = 17;		/* identity.name == "Ken \"Express\" Tenma: Disappeared Clone" */
	if (identity.pack == Pack::CreationAndControl && identity.pack_number == 28) influence = 10;	/* identity.name == "Rielle \"Kit\" Peddler: Transhuman" */
	if (identity.pack == Pack::HonorAndProfit && identity.pack_number == 30) cards = 40;			/* identity.name == "Silhouette: Stealth Operative" */
	if (identity.pack == Pack::CreationAndControl && identity.pack_number == 29) influence = 1;		/* identity.name == "The Professor: Keeper of Knowledge" */<commit_msg>fully support 23 Seconds data pack<commit_after>/* Android: Netrunner - Arena drafting */
constexpr int BUILD_NUMBER = 446;

/* Dependency: JSON for Modern C++
 * https://github.com/nlohmann/json
 */
#include <json.hpp>
using json = nlohmann::json;

/* Dependency: Bloat-free Immediate Mode Graphical User interface for C++ 
 * https://github.com/ocornut/imgui
 */
#include <imgui.h>
#include "imgui_impl_glfw.h"

 /* Dependency: GLFW is a free, Open Source, multi-platform library for OpenGL, OpenGL ES and Vulkan application development.
 * http://www.glfw.org/
 */
#include <GLFW/glfw3.h>

 /* Dependency: stb single-file public domain libraries for C/C++
 * https://github.com/nothings/stb
 */
#define STB_IMAGE_IMPLEMENTATION
#define STBI_ONLY_PNG
#include <stb_image.h>

#include <random>
#include <chrono>
#include <iostream>
#include <fstream>
#include <future>
#include <algorithm>
#include <cassert>

#include "enums.h"

std::default_random_engine g_rng;

constexpr size_t g_max_cards = 5120;
GLuint g_texture[g_max_cards];
GLuint g_side_tex[2];

class Card
{
public:
	Faction faction;
	int influence;
	int agenda_points;
	std::string name;
	std::string type;
	int pack_number;
	Pack pack;
	int copies;
	GLuint texId;
};

class Deck
{
public:
	Card identity;
	std::vector<Card> cards;
};

enum class GuiState
{
	Start,
	SideSelect,
	CorpFactionSelect,
	RunnerFactionSelect,
	CorpCardsSelect,
	RunnerCardsSelect,
	Summary
};

// Available cards and ids, unavailable cards will be removed during drafting
std::vector<Card> g_corp_ids;
std::vector<Card> g_runner_ids;
std::vector<Card> g_corp_cards;
std::vector<Card> g_runner_cards;

// card statistics
std::map<int, std::pair<int, int>> g_stats;

// user options:
// allow duplicates in selection?
bool opt_allowDuplicates = false;
// meaning of influence
enum OPT_INFLUENCE
{
	OPT_NORMAL = 0,  // normal influence rules
	OPT_NOINF,		 // influence has no meaning
	OPT_DISALLOW3INF // ensure atleast one 0 influence card in choice
};
int opt_influence = OPT_NORMAL;
// draw more than minimum deck size?
int opt_plusCards = 0;
// selected packs
std::map<Pack, int> g_allowed_packs;

// draw and remove a random card from the deck vector
// reqs contains optional requierments 
Card draw_card(std::vector<Card>& deck, std::vector<std::function<bool(Card)>> reqs = std::vector<std::function<bool(Card)>>())
{
	// TODO: gracefully handling
	assert(deck.size() > 0 && "Can't draw from empty deck.");
	size_t pos;

	std::vector<size_t> req_deck;
	for (size_t i = 0; i < deck.size(); i++)
	{
		bool skip = false;
		for (auto req : reqs) if (!req(deck[i])) { skip = true; break; }
		if (!skip) req_deck.push_back(i);
	}
	assert(req_deck.size() > 0 && "Can't draw from filtered deck.");
	std::uniform_int_distribution<size_t> distribution(0, req_deck.size() - 1);
	pos = distribution(g_rng);
	pos = req_deck.at(pos);

	Card c = deck.at(pos);
	deck.erase(deck.begin() + pos);
	return c;
}

int influenceCost(Card c, Faction id)
{
	if (c.faction == id) return 0;
	return c.influence;
}

// get min deck size, available influence and corp points for a specific identity.
// remove Jinteki cards when using "Custom Biotics"
// TODO: read this information from nrdb json dump 
void setIdentity(Card identity, int& cards, int& influence, int& points)
{
	cards = 45;
	influence = 15;
	if (identity.pack == Pack::CreationAndControl && identity.pack_number == 2)						/* identity.name == "Custom Biotics: Engineered for Success" */
	{
		influence = 22;
		g_corp_cards.erase(std::remove_if(g_corp_cards.begin(), g_corp_cards.end(), [](const Card& c) { return c.faction == Faction::Jinteki; }), g_corp_cards.end());
	}
	if (identity.pack == Pack::ChromeCity && identity.pack_number == 50) cards = 40;				/* identity.name == "Cybernetics Division: Humanity Upgraded" */
	if (identity.pack == Pack::FearAndLoathing && identity.pack_number == 97) influence = 10;		/* identity.name == "GRNDL: Power Unleashed" */
	if (identity.pack == Pack::HonorAndProfit && identity.pack_number == 1)							/* identity.name == "Harmony Medtech: Biomedical Pioneer" */
	{
		cards = 40;
		influence = 12;
	}
	if (identity.pack == Pack::FutureProof && identity.pack_number == 114)							/* identity.name == "NBN: The World is Yours*" */
	{
		cards = 40;
		influence = 12;
	}
	if (identity.pack == Pack::Upstalk && identity.pack_number == 5) influence = 17;				/* identity.name == "Near-Earth Hub: Broadcast Center" */
	if (identity.pack == Pack::CreationAndControl && identity.pack_number == 3) influence = 12;		/* identity.name == "NEXT Design: Guarding the Net" */
	if (identity.pack == Pack::DataAndDestiny && identity.pack_number == 1) cards = 40;				/* identity.name == "SYNC: Everything, Everywhere" */
	if (identity.pack == Pack::OrderAndChaos && identity.pack_number == 3) influence = 17;			/* identity.name == "Titan Transnational: Investing In Your Future" */
	if (identity.pack == Pack::Seconds && identity.pack_number == 17) influence = 12;				/* identity.name == "NBN: Controlling the Message" */

	if (identity.pack == Pack::CyberExodus && identity.pack_number == 46) cards = 40;				/* identity.name == "Chaos Theory: W\u00fcnderkind" */
	if (identity.pack == Pack::HonorAndProfit && identity.pack_number == 28) influence = 10;		/* identity.name == "<NAME>: Retired Spook" */
	if (identity.pack == Pack::HonorAndProfit && identity.pack_number == 29) influence = 17;		/* identity.name == "<NAME>\" Tenma: Disappeared Clone" */
	if (identity.pack == Pack::CreationAndControl && identity.pack_number == 28) influence = 10;	/* identity.name == "<NAME>\" Peddler: Transhuman" */
	if (identity.pack == Pack::HonorAndProfit && identity.pack_number == 30) cards = 40;			/* identity.name == "Silhouette: Stealth Operative" */
	if (identity.pack == Pack::CreationAndControl && identity.pack_number == 29) influence = 1;		/* identity.name == "The Professor: Keeper of Knowledge" */
{'fraction_non_alphanumeric': 0.14675592173017507, 'fraction_numerical': 0.014761414349467903, 'mean_word_length': 4.476033834586466, 'pattern_counts': {'":': 0, '<': 61, '<?xml version=': 0, '>': 63, 'https://': 6, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5156244', 'n_tokens_mistral': 4258, 'n_tokens_neox': 3922, 'n_words': 1083}