Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save lahdjirayhan/65c0c6468e35539f7b111f8a28611a4d to your computer and use it in GitHub Desktop.
Save lahdjirayhan/65c0c6468e35539f7b111f8a28611a4d to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import json"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"class Game:\n",
" def __init__(self, PlayerA, PlayerB):\n",
" self.board = np.zeros(9, int)\n",
" self.PlayerA = PlayerA\n",
" self.PlayerB = PlayerB\n",
" self.history = []\n",
" \n",
" def reset(self):\n",
" self.board = np.zeros(9, int)\n",
" self.history = []\n",
" \n",
" def draw(self, mark, where):\n",
" self.board[where] = mark\n",
" self.history.append(str(self.board))\n",
" \n",
" def is_game_done(self):\n",
" if not self.PlayerA.evaluate_board(self.board) == 0:\n",
" # Because PlayerB's victory is equivalent to PlayerA's defeat\n",
" return True\n",
" elif len(np.argwhere(self.board == 0).tolist()) == 0:\n",
" return True\n",
" else:\n",
" return False\n",
" \n",
" def print_board(self):\n",
" print(np.reshape(self.board, (3,3)))\n",
" \n",
"class Player:\n",
" def __init__(self, mark, learning_rate, exploration_rate):\n",
" # Available marks: -1 and 1\n",
" self.mark = mark\n",
" self.learning_rate = np.random.uniform() if learning_rate is None else learning_rate\n",
" self.exploration_rate = np.random.uniform() if exploration_rate is None else exploration_rate\n",
" self.history_book = {}\n",
" self.performance_record = []\n",
" \n",
" def evaluate_board(self, board):\n",
" board = np.reshape(board, (3,3))\n",
" if (self.mark*3 in np.sum(board, axis = 0) or\n",
" self.mark*3 in np.sum(board, axis = 1) or\n",
" np.trace(board) == self.mark*3 or\n",
" sum(board[i][3-i-1] for i in range(3)) == self.mark*3):\n",
" return 10*np.count_nonzero(board==0)\n",
" elif (self.mark*-3 in np.sum(board, axis = 0) or\n",
" self.mark*-3 in np.sum(board, axis = 1) or\n",
" np.trace(board) == self.mark*-3 or\n",
" sum(board[i][3-i-1] for i in range(3)) == self.mark*-3):\n",
" return -10*np.count_nonzero(board==0)\n",
" else:\n",
" return 0\n",
" \n",
" def update_history_book(self, new_history_entries):\n",
" # Ugly because new_history_entries are strings [1 0 -1 ... ].\n",
" score = self.evaluate_board(np.array(list(map(int, new_history_entries[-1][1:-1].split()))))\n",
" new_history_scores = [score for i in range(len(new_history_entries))]\n",
" new_history_book = dict(zip(new_history_entries, new_history_scores))\n",
" \n",
" for i in new_history_book:\n",
" if self.history_book.get(i) == None:\n",
" self.history_book[i] = new_history_book[i]\n",
" else:\n",
" self.history_book[i] = (self.history_book[i] +\n",
" self.learning_rate *\n",
" (new_history_book[i]-self.history_book[i]))\n",
" \n",
" self.performance_record.append(score)\n",
" \n",
" def move_randomly(self, board):\n",
" \"\"\"\n",
" Currently choosing randomly from the empty spaces\n",
" \"\"\"\n",
" choices = [i[0] for i in np.argwhere(board == 0)]\n",
" action = np.random.choice(choices)\n",
" return action\n",
" \n",
" def move_using_knowledge(self, board):\n",
" history = self.history_book\n",
" state = str(board)\n",
" \n",
" empty_tiles = [str(i[0]) for i in np.argwhere(board == 0)]\n",
" unknown_tiles = []\n",
" max_value = -1000\n",
" action = \"\"\n",
" for i in empty_tiles:\n",
" if history.get(state+i) == None:\n",
" unknown_tiles.append(i)\n",
" elif history.get(state+i) > max_value:\n",
" action = i\n",
" \n",
" if action == \"\" or (history.get(state+i) < 0 and unknown_tiles):\n",
" return np.random.choice(unknown_tiles)\n",
" \n",
" \n",
" def move(self, board):\n",
" if np.random.uniform() > self.exploration_rate:\n",
" return self.move_using_knowledge(board)\n",
" else:\n",
" return self.move_randomly(board)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"Player1 = Player(mark = 1,\n",
" learning_rate = 0.2,\n",
" exploration_rate = 0.02) # a play-it-safe agent\n",
"\n",
"Player2 = Player(mark = -1,\n",
" learning_rate = 0.01,\n",
" exploration_rate = 0.95) # a very random and ruthless agent\n",
"\n",
"Player3 = Player(mark = 1,\n",
" learning_rate = 0.5,\n",
" exploration_rate = 0.4) # an impatient learner\n",
"\n",
"Player4 = Player(mark = -1,\n",
" learning_rate = 0.1,\n",
" exploration_rate = 0.3) # a maybe normal agent\n",
"\n",
"Game12 = Game(Player1, Player2)\n",
"Game14 = Game(Player1, Player4)\n",
"Game32 = Game(Player3, Player2)\n",
"Game34 = Game(Player3, Player4)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Iteration: 10000\n",
"Player 1:\n",
" Mean: 4.844\n",
" Stdv: 18.33836590320959\n",
"Player 2:\n",
" Mean: -4.844\n",
" Stdv: 18.33836590320959\n",
"--------------------------------------\n",
"Iteration: 20000\n",
"Player 1:\n",
" Mean: 4.579\n",
" Stdv: 18.516553648019926\n",
"Player 2:\n",
" Mean: -4.579\n",
" Stdv: 18.516553648019926\n",
"--------------------------------------\n",
"Iteration: 30000\n",
"Player 1:\n",
" Mean: 4.338\n",
" Stdv: 18.299228289739435\n",
"Player 2:\n",
" Mean: -4.338\n",
" Stdv: 18.299228289739435\n",
"--------------------------------------\n",
"Iteration: 40000\n",
"Player 1:\n",
" Mean: 4.521\n",
" Stdv: 18.333863722630863\n",
"Player 2:\n",
" Mean: -4.521\n",
" Stdv: 18.333863722630863\n",
"--------------------------------------\n",
"Iteration: 50000\n",
"Player 1:\n",
" Mean: 4.413\n",
" Stdv: 18.280465831044896\n",
"Player 2:\n",
" Mean: -4.413\n",
" Stdv: 18.280465831044896\n",
"--------------------------------------\n",
"Iteration: 60000\n",
"Player 1:\n",
" Mean: 4.202\n",
" Stdv: 18.27630148580396\n",
"Player 2:\n",
" Mean: -4.202\n",
" Stdv: 18.27630148580396\n",
"--------------------------------------\n",
"Iteration: 70000\n",
"Player 1:\n",
" Mean: 4.254\n",
" Stdv: 18.402268447123575\n",
"Player 2:\n",
" Mean: -4.254\n",
" Stdv: 18.402268447123575\n",
"--------------------------------------\n",
"Iteration: 80000\n",
"Player 1:\n",
" Mean: 4.286\n",
" Stdv: 18.430143895260287\n",
"Player 2:\n",
" Mean: -4.286\n",
" Stdv: 18.430143895260287\n",
"--------------------------------------\n",
"Iteration: 90000\n",
"Player 1:\n",
" Mean: 4.553\n",
" Stdv: 18.21099093953978\n",
"Player 2:\n",
" Mean: -4.553\n",
" Stdv: 18.21099093953978\n",
"--------------------------------------\n",
"Iteration: 100000\n",
"Player 1:\n",
" Mean: 4.266\n",
" Stdv: 18.204429241258843\n",
"Player 2:\n",
" Mean: -4.266\n",
" Stdv: 18.204429241258843\n",
"--------------------------------------\n",
"Iteration: 110000\n",
"Player 1:\n",
" Mean: 4.123\n",
" Stdv: 18.27596429740439\n",
"Player 2:\n",
" Mean: -4.123\n",
" Stdv: 18.27596429740439\n",
"--------------------------------------\n",
"Iteration: 120000\n",
"Player 1:\n",
" Mean: 4.314\n",
" Stdv: 18.481596359622188\n",
"Player 2:\n",
" Mean: -4.314\n",
" Stdv: 18.481596359622188\n",
"--------------------------------------\n",
"Iteration: 130000\n",
"Player 1:\n",
" Mean: 4.508\n",
" Stdv: 18.385808005089146\n",
"Player 2:\n",
" Mean: -4.508\n",
" Stdv: 18.385808005089146\n",
"--------------------------------------\n",
"Iteration: 140000\n",
"Player 1:\n",
" Mean: 4.371\n",
" Stdv: 18.31950760801174\n",
"Player 2:\n",
" Mean: -4.371\n",
" Stdv: 18.31950760801174\n",
"--------------------------------------\n",
"Iteration: 150000\n",
"Player 1:\n",
" Mean: 4.419\n",
" Stdv: 18.296514394823948\n",
"Player 2:\n",
" Mean: -4.419\n",
" Stdv: 18.296514394823948\n",
"--------------------------------------\n",
"Iteration: 160000\n",
"Player 1:\n",
" Mean: 4.727\n",
" Stdv: 18.401235583514495\n",
"Player 2:\n",
" Mean: -4.727\n",
" Stdv: 18.401235583514495\n",
"--------------------------------------\n",
"Iteration: 170000\n",
"Player 1:\n",
" Mean: 4.506\n",
" Stdv: 18.409670393573048\n",
"Player 2:\n",
" Mean: -4.506\n",
" Stdv: 18.409670393573048\n",
"--------------------------------------\n",
"Iteration: 180000\n",
"Player 1:\n",
" Mean: 4.422\n",
" Stdv: 18.318458341246952\n",
"Player 2:\n",
" Mean: -4.422\n",
" Stdv: 18.318458341246952\n",
"--------------------------------------\n",
"Iteration: 190000\n",
"Player 1:\n",
" Mean: 4.523\n",
" Stdv: 18.357354684158608\n",
"Player 2:\n",
" Mean: -4.523\n",
" Stdv: 18.357354684158608\n",
"--------------------------------------\n",
"Iteration: 200000\n",
"Player 1:\n",
" Mean: 4.557\n",
" Stdv: 18.259894605391345\n",
"Player 2:\n",
" Mean: -4.557\n",
" Stdv: 18.259894605391345\n",
"--------------------------------------\n",
"Iteration: 210000\n",
"Player 1:\n",
" Mean: 4.099\n",
" Stdv: 18.54799716950593\n",
"Player 2:\n",
" Mean: -4.099\n",
" Stdv: 18.54799716950593\n",
"--------------------------------------\n",
"Iteration: 220000\n",
"Player 1:\n",
" Mean: 4.421\n",
" Stdv: 18.286737243149744\n",
"Player 2:\n",
" Mean: -4.421\n",
" Stdv: 18.286737243149744\n",
"--------------------------------------\n",
"Iteration: 230000\n",
"Player 1:\n",
" Mean: 4.345\n",
" Stdv: 18.35840338918393\n",
"Player 2:\n",
" Mean: -4.345\n",
" Stdv: 18.35840338918393\n",
"--------------------------------------\n",
"Iteration: 240000\n",
"Player 1:\n",
" Mean: 4.599\n",
" Stdv: 18.40758536582134\n",
"Player 2:\n",
" Mean: -4.599\n",
" Stdv: 18.40758536582134\n",
"--------------------------------------\n",
"Iteration: 250000\n",
"Player 1:\n",
" Mean: 4.473\n",
" Stdv: 18.29705634794843\n",
"Player 2:\n",
" Mean: -4.473\n",
" Stdv: 18.29705634794843\n",
"--------------------------------------\n",
"Iteration: 260000\n",
"Player 1:\n",
" Mean: 4.376\n",
" Stdv: 18.519466083016543\n",
"Player 2:\n",
" Mean: -4.376\n",
" Stdv: 18.519466083016543\n",
"--------------------------------------\n",
"Iteration: 270000\n",
"Player 1:\n",
" Mean: 4.368\n",
" Stdv: 18.386967558572564\n",
"Player 2:\n",
" Mean: -4.368\n",
" Stdv: 18.386967558572564\n",
"--------------------------------------\n",
"Iteration: 280000\n",
"Player 1:\n",
" Mean: 4.467\n",
" Stdv: 18.581601411073265\n",
"Player 2:\n",
" Mean: -4.467\n",
" Stdv: 18.581601411073265\n",
"--------------------------------------\n",
"Iteration: 290000\n",
"Player 1:\n",
" Mean: 4.574\n",
" Stdv: 18.41951476016673\n",
"Player 2:\n",
" Mean: -4.574\n",
" Stdv: 18.41951476016673\n",
"--------------------------------------\n",
"Iteration: 300000\n",
"Player 1:\n",
" Mean: 4.476\n",
" Stdv: 18.152284263970746\n",
"Player 2:\n",
" Mean: -4.476\n",
" Stdv: 18.152284263970746\n",
"--------------------------------------\n"
]
}
],
"source": [
"TIMES = 300000\n",
"DISPLAY_DIV = 10000\n",
"\n",
"for times in range(TIMES):\n",
" while(True):\n",
" Game12.draw(Player1.mark, int(Player1.move(Game12.board)))\n",
" if Game12.is_game_done():\n",
" Player1.update_history_book(Game12.history)\n",
" Player2.update_history_book(Game12.history)\n",
" Game12.reset()\n",
" break\n",
" Game12.draw(Player2.mark, int(Player2.move(Game12.board)))\n",
" if Game12.is_game_done():\n",
" Player1.update_history_book(Game12.history)\n",
" Player2.update_history_book(Game12.history)\n",
" Game12.reset()\n",
" break\n",
" if (times+1) % DISPLAY_DIV == 0:\n",
" print(\"Iteration: \", times+1)\n",
" print(\"Player 1:\")\n",
" print(\" Mean: \", np.mean(Player1.performance_record[-DISPLAY_DIV:]))\n",
" print(\" Stdv: \", np.std(Player1.performance_record[-DISPLAY_DIV:]))\n",
" print(\"Player 2:\")\n",
" print(\" Mean: \", np.mean(Player2.performance_record[-DISPLAY_DIV:]))\n",
" print(\" Stdv: \", np.std(Player2.performance_record[-DISPLAY_DIV:]))\n",
" print(\"--------------------------------------\")\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"iter = list(range(TIMES//DISPLAY_DIV))\n",
"\n",
"p1perf = []\n",
"tempmean = 0\n",
"for i in iter:\n",
" p1perf.append(0)\n",
" for j in range(i, i + (TIMES//DISPLAY_DIV)):\n",
" p1perf[i] += Player1.performance_record[j]\n",
" p1perf[i] /= (TIMES//DISPLAY_DIV)\n",
"plt.plot(iter, p1perf)\n",
"plt.xlabel('Block iteration (x' + str(DISPLAY_DIV) +')')\n",
"plt.ylabel(\"Moving average of score\")\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"with open(\"Player1_knowledge.json\", \"w\") as file:\n",
" json.dump(Player1.history_book, file)"
]
}
],
"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.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment