Moved the function that checks a whole stack of actions if they are possible on a stack of boards.
This commit is contained in:
1 file changed
+204
-59
+204
-59
@@ -159,7 +159,10 @@
|
||||
"BOARD_SIZE: Final[int] = 8 # defines the board side length as 8\n",
|
||||
"PLAYER: Final[int] = 1 # defines the number symbolising the player as 1\n",
|
||||
"ENEMY: Final[int] = -1 # defines the number symbolising the enemy as -1\n",
|
||||
"EXAMPLE_STACK_SIZE: Final[int] = 1000 # defines the game stack size for examples"
|
||||
"EXAMPLE_STACK_SIZE: Final[int] = 1000 # defines the game stack size for examples\n",
|
||||
"IMPOSSIBLE: Final[np.ndarray] = np.array([-1, -1], dtype=int)\n",
|
||||
"IMPOSSIBLE.setflags(write=False)\n",
|
||||
"SIMULATE_TURNS: Final[int] = 70"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -588,13 +591,71 @@
|
||||
"assert move_possible(np.ones((8, 8)) * 0, np.array([-1, -1])) is True"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def moves_possible(boards: np.ndarray, moves: np.ndarray) -> np.ndarray:\n",
|
||||
" \"\"\"Checks if a stack of moves can be executed on a stack of boards.\n",
|
||||
"\n",
|
||||
" Args:\n",
|
||||
" boards: A board where the next stone should be placed.\n",
|
||||
" moves: A stack stones to be placed. Each move is formatted as an array in the form of [x, y] if no turn is possible the value [-1, -1] is expected.\n",
|
||||
"\n",
|
||||
" Returns:\n",
|
||||
" An array marking for each and every game and move in the stack if the move can be executed.\n",
|
||||
" \"\"\"\n",
|
||||
" arr_moves_possible = np.zeros(boards.shape[0], dtype=bool)\n",
|
||||
" for game in range(boards.shape[0]):\n",
|
||||
" if np.all(\n",
|
||||
" moves[game] == -1\n",
|
||||
" ): # can be all or any. All should be faster since most times neither value will be -1.\n",
|
||||
" arr_moves_possible[game] = not np.any(\n",
|
||||
" get_possible_turns(np.reshape(boards[game], (1, 8, 8)))\n",
|
||||
" )\n",
|
||||
" else:\n",
|
||||
" arr_moves_possible[game] = any(\n",
|
||||
" _recursive_steps(boards[game, :, :], direction, moves[game])\n",
|
||||
" for direction in DIRECTIONS\n",
|
||||
" )\n",
|
||||
" return arr_moves_possible\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"np.testing.assert_array_equal(\n",
|
||||
" moves_possible(np.ones((3, 8, 8)) * 1, np.array([[-1, -1]] * 3)),\n",
|
||||
" np.array([True] * 3),\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"np.testing.assert_array_equal(\n",
|
||||
" moves_possible(get_new_games(3), np.array([[2, 3], [3, 2], [3, 2]])),\n",
|
||||
" np.array([True] * 3),\n",
|
||||
")\n",
|
||||
"np.testing.assert_array_equal(\n",
|
||||
" moves_possible(get_new_games(3), np.array([[2, 2], [1, 1], [0, 0]])),\n",
|
||||
" np.array([False] * 3),\n",
|
||||
")\n",
|
||||
"np.testing.assert_array_equal(\n",
|
||||
" moves_possible(np.ones((3, 8, 8)) * -1, np.array([[-1, -1]] * 3)),\n",
|
||||
" np.array([True] * 3),\n",
|
||||
")\n",
|
||||
"np.testing.assert_array_equal(\n",
|
||||
" moves_possible(np.zeros((3, 8, 8)), np.array([[-1, -1]] * 3)),\n",
|
||||
" np.array([True] * 3),\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## Reword functions\n",
|
||||
"\n",
|
||||
"For any kind of reinforcement learning is a reword function needed. For otello this would be the final score, the information who won or changes to the score. A combination of those three would also be possible.\n",
|
||||
"It is probably not be possible to weight the current score to high in a reword function since that would be to close to a classic greedy algorithm. But some influce would increase learning behavior.\n",
|
||||
"For any kind of reinforcement learning is a reword function needed.\n",
|
||||
"For otello this would be the final score, the information who won or changes to the score.\n",
|
||||
"A combination of those three would also be possible.\n",
|
||||
"It is probably not be possible to weight the current score to high in a reword function since that would be to close to a classic greedy algorithm.\n",
|
||||
"But some direct influence would increase the learning speed.\n",
|
||||
"In the next section are all three reword functions implemented to be combined and weight later on as needed."
|
||||
],
|
||||
"metadata": {
|
||||
@@ -674,48 +735,16 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"def moves_possible(boards: np.ndarray, moves: np.ndarray) -> np.ndarray:\n",
|
||||
" arr_moves_possible = np.zeros(boards.shape[0], dtype=bool)\n",
|
||||
" for game in range(boards.shape[0]):\n",
|
||||
" if np.all(moves[game] == -1):\n",
|
||||
" arr_moves_possible[game] = not np.any(\n",
|
||||
" get_possible_turns(np.reshape(boards[game], (1, 8, 8)))\n",
|
||||
" )\n",
|
||||
" else:\n",
|
||||
" arr_moves_possible[game] = any(\n",
|
||||
" _recursive_steps(boards[game, :, :], direction, moves[game])\n",
|
||||
" for direction in DIRECTIONS\n",
|
||||
" )\n",
|
||||
" return arr_moves_possible\n",
|
||||
"## Execute a chosen action\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"np.testing.assert_array_equal(\n",
|
||||
" moves_possible(np.ones((3, 8, 8)) * 1, np.array([[-1, -1]] * 3)),\n",
|
||||
" np.array([True] * 3),\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"np.testing.assert_array_equal(\n",
|
||||
" moves_possible(get_new_games(3), np.array([[2, 3], [3, 2], [3, 2]])),\n",
|
||||
" np.array([True] * 3),\n",
|
||||
")\n",
|
||||
"np.testing.assert_array_equal(\n",
|
||||
" moves_possible(get_new_games(3), np.array([[2, 2], [1, 1], [0, 0]])),\n",
|
||||
" np.array([False] * 3),\n",
|
||||
")\n",
|
||||
"np.testing.assert_array_equal(\n",
|
||||
" moves_possible(np.ones((3, 8, 8)) * -1, np.array([[-1, -1]] * 3)),\n",
|
||||
" np.array([True] * 3),\n",
|
||||
")\n",
|
||||
"np.testing.assert_array_equal(\n",
|
||||
" moves_possible(np.zeros((3, 8, 8)), np.array([[-1, -1]] * 3)),\n",
|
||||
" np.array([True] * 3),\n",
|
||||
")"
|
||||
]
|
||||
"After an evaluation what turns are possible there needs to be a function that executes a turn.\n",
|
||||
"This next sections does that."
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -724,13 +753,60 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class InvalidTurn(ValueError):\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" \"\"\"\n",
|
||||
" This error is thrown if a given turn is not valid.\n",
|
||||
" \"\"\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 28,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"95.1 ms ± 3.5 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": "<Figure size 300x300 with 1 Axes>",
|
||||
"image/png": "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 truncated
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def do_moves(boards: np.ndarray, moves: np.ndarray) -> np.ndarray:\n",
|
||||
" \"\"\"Executes a single move on a stack o Othello boards.\n",
|
||||
"\n",
|
||||
" Args:\n",
|
||||
" boards: A stack of Othello boards where the next stone should be placed.\n",
|
||||
" moves: A stack of stone placement orders for the game. Formatted as coordinates in an array [x, y] of the place where the stone should be placed. Should contain [-1,-1] if no new placement is possible.\n",
|
||||
"\n",
|
||||
" Returns:\n",
|
||||
" The new state of the board.\n",
|
||||
" \"\"\"\n",
|
||||
"\n",
|
||||
" def _do_directional_move(\n",
|
||||
" board: np.ndarray, rec_move: np.ndarray, rev_direction, step_one=True\n",
|
||||
" ) -> bool:\n",
|
||||
" \"\"\"Changes the color of enemy stones in one direction.\n",
|
||||
"\n",
|
||||
" This function works recursive. The argument step_one should always be used in its default value.\n",
|
||||
"\n",
|
||||
" Args:\n",
|
||||
" board: A bord on which a stone was placed.\n",
|
||||
" rec_move: The position on the board in x and y where this function is called from. Will be moved by recursive called.\n",
|
||||
" rev_direction: The position where the stone was placed. Inside this recursion it will also be the last step that was checked.\n",
|
||||
" step_one: Set to true if this is the first step in the recursion. False later on.\n",
|
||||
"\n",
|
||||
" Returns:\n",
|
||||
" True if a stone could be flipped.\n",
|
||||
" All changes are made on the view of the numpy array and therefore not included in the return value.\n",
|
||||
" \"\"\"\n",
|
||||
" rec_position = rec_move + rev_direction\n",
|
||||
" if np.any((rec_position >= 8) | (rec_position < 0)):\n",
|
||||
" return False\n",
|
||||
@@ -746,16 +822,32 @@
|
||||
" return False\n",
|
||||
"\n",
|
||||
" def _do_move(_board: np.ndarray, move: np.ndarray) -> None:\n",
|
||||
" \"\"\"Executes a turn on a board.\n",
|
||||
"\n",
|
||||
" Args:\n",
|
||||
" _board: The game board on wich to place a stone.\n",
|
||||
" move: The coordinates of a stone that should be placed. Should be formatted as an array of the form [x, y]. The value [-1, -1] is expected if no turn is possible.\n",
|
||||
"\n",
|
||||
" Returns:\n",
|
||||
" All changes are made on the view of the numpy array.\n",
|
||||
" \"\"\"\n",
|
||||
" if np.all(move == -1):\n",
|
||||
" if not move_possible(_board, move):\n",
|
||||
" raise InvalidTurn(\"An action should be taken. A turn is possible.\")\n",
|
||||
" return\n",
|
||||
"\n",
|
||||
" # noinspection PyTypeChecker\n",
|
||||
" if _board[tuple(move.tolist())] != 0:\n",
|
||||
" raise InvalidTurn\n",
|
||||
" raise InvalidTurn(\"This turn is not possible.\")\n",
|
||||
"\n",
|
||||
" action = False\n",
|
||||
" for direction in DIRECTIONS:\n",
|
||||
" if _do_directional_move(_board, move, direction):\n",
|
||||
" action = True\n",
|
||||
" if not action:\n",
|
||||
" raise InvalidTurn()\n",
|
||||
" raise InvalidTurn(\"This turn is not possible.\")\n",
|
||||
"\n",
|
||||
" # noinspection PyTypeChecker\n",
|
||||
" _board[tuple(move.tolist())] = 1\n",
|
||||
"\n",
|
||||
" boards = boards.copy()\n",
|
||||
@@ -764,8 +856,28 @@
|
||||
" return boards\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"do_moves(get_new_games(10), np.array([[2, 3]] * 10))[0]"
|
||||
]
|
||||
"%timeit do_moves(get_new_games(EXAMPLE_STACK_SIZE), np.array([[2, 3]] * EXAMPLE_STACK_SIZE))[0]\n",
|
||||
"plot_othello_board(\n",
|
||||
" do_moves(\n",
|
||||
" get_new_games(EXAMPLE_STACK_SIZE), np.array([[2, 3]] * EXAMPLE_STACK_SIZE)\n",
|
||||
" )[0]\n",
|
||||
")"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## An abstract reversi game policy\n",
|
||||
"\n",
|
||||
"For an easy use of policies an abstract class containing the policy generation / requests an action in an inherited instance of this class.\n",
|
||||
"This class filters the policy to only propose valid actions. Inherited instance do not need to care about this."
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -774,33 +886,66 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class GamePolicy(ABC):\n",
|
||||
"\n",
|
||||
" IMPOSSIBLE: np.ndarray = np.array([-1, -1], dtype=int)\n",
|
||||
" \"\"\"\n",
|
||||
" A game policy. Proposes where to place a stone next.\n",
|
||||
" \"\"\"\n",
|
||||
"\n",
|
||||
" @property\n",
|
||||
" @abc.abstractmethod\n",
|
||||
" def policy_name(self) -> str:\n",
|
||||
" \"\"\"The name of this policy\"\"\"\n",
|
||||
" raise NotImplementedError()\n",
|
||||
"\n",
|
||||
" @abc.abstractmethod\n",
|
||||
" def internal_policy(self, boards: np.ndarray) -> np.ndarray:\n",
|
||||
" def _internal_policy(self, boards: np.ndarray) -> np.ndarray:\n",
|
||||
" \"\"\"The internal policy is an unfiltered policy. It should only be called from inside this function\n",
|
||||
"\n",
|
||||
" Args:\n",
|
||||
" boards: A board where a policy should be calculated for.\n",
|
||||
"\n",
|
||||
" Returns:\n",
|
||||
" The policy for this board. Should have the same size as the boards array.\n",
|
||||
" \"\"\"\n",
|
||||
" raise NotImplementedError()\n",
|
||||
"\n",
|
||||
" def get_policy(self, boards: np.ndarray) -> np.ndarray:\n",
|
||||
" policies = self.internal_policy(boards)\n",
|
||||
" def get_policy(\n",
|
||||
" self, boards: np.ndarray, epsilon: float = 1\n",
|
||||
" ) -> tuple[np.ndarray, np.ndarray]:\n",
|
||||
" assert len(boards.shape) == 3\n",
|
||||
" assert boards.shape == (BOARD_SIZE, BOARD_SIZE)\n",
|
||||
"\n",
|
||||
" # todo possibly change this function to only validate the purpose turn and\n",
|
||||
"\n",
|
||||
" policies = self._internal_policy(boards)\n",
|
||||
" raw_policy = policies.copy()\n",
|
||||
" if epsilon < 1:\n",
|
||||
" policies = policies + np.random.rand(*boards.shape)\n",
|
||||
"\n",
|
||||
" # todo talk to team about backpropagation epsilon for greedy factor\n",
|
||||
"\n",
|
||||
" possible_turns = get_possible_turns(boards)\n",
|
||||
" policies[possible_turns == False] = -1.0\n",
|
||||
" max_indices = [\n",
|
||||
" np.unravel_index(policy.argmax(), policy.shape) for policy in policies\n",
|
||||
" ]\n",
|
||||
" policy_vector = np.array(max_indices)\n",
|
||||
"\n",
|
||||
" max_policy = policy_vector\n",
|
||||
" no_turn_possible = np.all(policy_vector == 0, 1) & (policies[:, 0, 0] == -1.0)\n",
|
||||
"\n",
|
||||
" policy_vector[no_turn_possible] = GamePolicy.IMPOSSIBLE\n",
|
||||
" return policy_vector"
|
||||
" policy_vector[no_turn_possible] = IMPOSSIBLE\n",
|
||||
" max_policy[no_turn_possible] = 0\n",
|
||||
" return policy_vector, raw_policy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## A first policy"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -854,7 +999,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"SIMULATE_TURNS = 70\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def simulate_game(\n",
|
||||
|
||||
Reference in new issue
Block a user