diff --git a/CrashV2.ipynb b/CrashV2.ipynb new file mode 100644 index 0000000..185e7c6 --- /dev/null +++ b/CrashV2.ipynb @@ -0,0 +1,289 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Necessary Libraries and Constants" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#https://www.youtube.com/watch?v=F1HA7e3acSI\n", + "#https://www.bustabit.com/play\n", + "#https://bitcointalk.org/index.php?topic=2807542.0\n", + "#https://jsfiddle.net/Dexon95/2fmuxLza/" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import hashlib\n", + "import random\n", + "import string\n", + "import hmac\n", + "import math\n", + "import codecs\n", + "\n", + "# https://www.blockchain.com/btc/block/0000000000000000004d6ec16dafe9d8370958664c1dc422f452892264c59526\n", + "salt505750 = \"0000000000000000004d6ec16dafe9d8370958664c1dc422f452892264c59526\"\n", + "SALT = salt505750" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Get Result and Get Previous Game Function" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "results = [('319aa8124bbcddac2bae8438cfd5e658aeca56d524736739622dfb0a09942b22', 159.93),\n", + "('c64559640b124fa354eaaee31510eaa0f1a5fdd5aa004363b95693e52d274d28',2.36),\n", + "('c263a30ad8820e8c3d46f9a5db3c34d3b081cd349a11367a9fbd52063f17cd34',1.31),\n", + "('a6bb64e83b8efa52524ba526cd036ae17c3ec00b9fbec49b8cd4dc1321d7b4ce',1.09),\n", + "('17612b37d97f0faf0930762a328ab383bd2e107c5cc5c975cc76405f41a4bbc2',1.43)]\n", + "\n", + "\n", + "def get_prev_game(hash_code):\n", + " m = hashlib.sha256()\n", + " m.update(hash_code.encode(\"utf-8\"))\n", + " return m.hexdigest()\n", + "for i in range(len(results)-1):\n", + " assert get_prev_game(results[i][0]) == results[i+1][0]\n", + "print(\"get_prev_game passed\")\n", + "\n", + "def get_result(seed, salt=SALT):\n", + " salt = salt.encode(\"utf8\")\n", + " seed = codecs.decode(bytes(seed, \"utf8\"), \"hex\") #https://tinyurl.com/2bf4dann\n", + " hm = hmac.new(salt, seed, hashlib.sha256)\n", + " h = hm.hexdigest()\n", + " \n", + " r = int(h[:13], 16) # 52 most significant bits as int\n", + " x = r / 2**52 # [0,1)\n", + " x = 99 / (1-x) # [99.0, 4.458563631096791e+17]\n", + " result = math.floor(x) # [99, 445856363109679104]\n", + " return (max(1, result/100))\n", + " \n", + "for res in results[:]: \n", + " assert getResult(res[0]) == res[1], print(f\"\\n\\n{res}: {getResult(res[0])}\")\n", + "print(\"get_result passed\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def sim(numerator=99):\n", + " results = []\n", + " for x in range(0,1000):\n", + " x = x/1000 # [0,0.999]\n", + " x = numerator/(1-x) # [99, 99/(0.001) 99,000]\n", + " result = math.floor(x) # [99, 99000]\n", + " answer = max(1, result/100) # [1, 990]\n", + " results.append(answer)\n", + " return results\n", + " \n", + "game = sim()\n", + "fair = sim(100)\n", + "\n", + "print(\"game\", min(game), sum(game)/len(game), max(game))\n", + "print(\"fair?\", min(fair), sum(fair)/len(fair), max(fair))\n", + "\n", + "if False:\n", + " for g in game:\n", + " print(g)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Collecting All Game Results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "game_hash = '4fc2f264ea3e0bbf8405f74f0bf354bef946283d6023352f5f8d441d6aaad861' # 29oct2021 Update to latest game's hash for more results\n", + "first_game = \"86728f5fc3bd99db94d3cdaf105d67788194e9701bf95d049ad0e1ee3d004277\" #https://bitcointalk.org/index.php?topic=2807542.0\n", + "\n", + "results = []\n", + "count = 0\n", + "while game_hash != first_game:\n", + " count += 1\n", + " results.append(get_result(game_hash))\n", + " game_hash = get_prev_game(game_hash)\n", + " \n", + "results = np.array(results)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(count)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Testing Probability Formula" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# What's the analytical EV of this new algorithm? " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Testing Expected Value Formula" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#realized results from start of game to now \n", + "#confirms a 1% house edge\n", + "multiplier = 1.7\n", + "(results < multiplier).mean() * -1 + (multiplier - 1)*(results >= multiplier).mean()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualizations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import seaborn as sns\n", + "sns.set(rc={'figure.figsize':(11.7,8.27)})\n", + "\n", + "plt.hist(results, range=(0, 25))\n", + "plt.title(\"Histogram of Game Results\", fontsize=20)\n", + "plt.xticks(fontsize=15)\n", + "plt.yticks(fontsize=15)\n", + "plt.ylabel(\"Number of Games\", fontsize=15)\n", + "plt.xlabel(\"Multiplier\", fontsize=15)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def calculate_ev(multiplier):\n", + " # This is for the version 1 algorithm, not the version 2.\n", + " return ((1/33) + (32/33)*(.01 + .99*(1 - 1/(multiplier-.01))))*-1 + (multiplier-1)*(1 - ((1/33) + (32/33)*(.01 + .99*(1 - 1/(multiplier-.01)))))\n", + "\n", + "xs = np.linspace(101, 1001, 901) / 100\n", + "ys = [calculate_ev(x) for x in xs]\n", + "y2s = [(results < x).mean() * -1 + (x - 1)*(results >= x).mean() for x in xs]\n", + "\n", + "plt.plot(xs, ys, linewidth=5)\n", + "plt.xlabel(\"Multiplier\", fontsize=15)\n", + "plt.ylabel(\"Expected Value\", fontsize=15)\n", + "plt.xticks(fontsize=15)\n", + "plt.yticks(fontsize=15)\n", + "plt.ylim(-.045, -.000)\n", + "plt.plot(xs, y2s, linewidth=3)\n", + "plt.title(\"Expected Value by Multiplier\", fontsize=20)\n", + "plt.legend([\"(error) Theoretical Results\", \"Actual Results\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Martingale Test" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "negatives = []\n", + "in_a_row = 0\n", + "for multiplier in results:\n", + " if multiplier < 2:\n", + " in_a_row += 1\n", + " else:\n", + " in_a_row = 0\n", + " negatives.append(in_a_row)\n", + "negatives = np.array(negatives)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for i in range(1, 14):\n", + " print(\"Probability of Losing %d Game(s) in a Row:\"%i, (negatives >= i).mean())" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.4" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}