Added a text implementing the search for possible turns.

This commit is contained in:
Philipp Horstenkamp 2023-02-12 16:35:53 +01:00
parent bad719c8e6
commit 839093e3f1
Signed by: Philipp
GPG Key ID: DD53EAC36AFB61B4

View File

@ -391,6 +391,27 @@
" plt.show()" " plt.show()"
] ]
}, },
{
"cell_type": "markdown",
"source": [
"## Find possible actions to take\n",
"\n",
"The frist step in the implementation of an AI like this is to get an overview over the possible actions that can be taken in a situation.\n",
"Here was the design choice taken to first find fields that are empty and have at least one neighbouring enemy stone.\n",
"This was implemented with element wise check for a stone and a binary dilation marking all fields neighboring an enemy stone.\n",
"For that the `SURROUNDING` mask was used. Both aries are then element wise combined using and.\n",
"The resulting array contains all filed where a turn could potentially be made. Those are then check in detail.\n",
"The previous element wise operations on the numpy array increase the spead for this operation dramatically.\n",
"\n",
"The check for a possible turn is done in detail by following each direction step by step as long as there are enemy stones in that direction.\n",
"If the board end is reached or en empty filed before reaching a field occupied by the player that direction does not surround enemy stones.\n",
"If one direction surrounds enemy stone a turn is possible.\n",
"This detailed step is implemented as a recursion and need to go at leas one step to return True."
],
"metadata": {
"collapsed": false
}
},
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 10, "execution_count": 10,
@ -408,7 +429,9 @@
} }
], ],
"source": [ "source": [
"SURROUNDING: Final = np.array([[[1, 1, 1], [1, 0, 1], [1, 1, 1]]])\n", "SURROUNDING: Final = np.array(\n",
" [[[1, 1, 1], [1, 0, 1], [1, 1, 1]]]\n",
") # defines the binary dilation mask to check if a field is next to an enemy stones\n",
"SURROUNDING" "SURROUNDING"
] ]
}, },
@ -427,15 +450,26 @@
} }
], ],
"source": [ "source": [
"def recursive_steps(_array, rec_direction, rec_position, step_one=True) -> bool:\n", "def _recursive_steps(board, rec_direction, rec_position, step_one=True) -> bool:\n",
" \"\"\"Check if a player can place a stone on the board specified in the direction specified and direction specified.\n",
"\n",
" Args:\n",
" board: The board that should be checked for a playable action.\n",
" rec_direction: The direction that should be checked.\n",
" rec_position: The position that should be checked.\n",
" step_one:\n",
"\n",
" Returns:\n",
"\n",
" \"\"\"\n",
" rec_position = rec_position + rec_direction\n", " rec_position = rec_position + rec_direction\n",
" if np.any((rec_position >= BOARD_SIZE) | (rec_position < 0)):\n", " if np.any((rec_position >= BOARD_SIZE) | (rec_position < 0)):\n",
" return False\n", " return False\n",
" next_field = _array[tuple(rec_position.tolist())]\n", " next_field = board[tuple(rec_position.tolist())]\n",
" if next_field == 0:\n", " if next_field == 0:\n",
" return False\n", " return False\n",
" if next_field == -1:\n", " if next_field == -1:\n",
" return recursive_steps(_array, rec_direction, rec_position, step_one=False)\n", " return _recursive_steps(board, rec_direction, rec_position, step_one=False)\n",
" if next_field == 1:\n", " if next_field == 1:\n",
" return not step_one\n", " return not step_one\n",
"\n", "\n",
@ -456,7 +490,7 @@
" position = idx, idy\n", " position = idx, idy\n",
" if _poss_turns[game, idx, idy]:\n", " if _poss_turns[game, idx, idy]:\n",
" _poss_turns[game, idx, idy] = any(\n", " _poss_turns[game, idx, idy] = any(\n",
" recursive_steps(boards[game, :, :], direction, position)\n", " _recursive_steps(boards[game, :, :], direction, position)\n",
" for direction in DIRECTIONS\n", " for direction in DIRECTIONS\n",
" )\n", " )\n",
" return _poss_turns\n", " return _poss_turns\n",
@ -512,7 +546,7 @@
" if np.all(move == -1):\n", " if np.all(move == -1):\n",
" return not np.any(get_possible_turns(np.reshape(board, (1, 8, 8))))\n", " return not np.any(get_possible_turns(np.reshape(board, (1, 8, 8))))\n",
" return any(\n", " return any(\n",
" recursive_steps(board[:, :], direction, move) for direction in DIRECTIONS\n", " _recursive_steps(board[:, :], direction, move) for direction in DIRECTIONS\n",
" )\n", " )\n",
"\n", "\n",
"\n", "\n",
@ -540,7 +574,7 @@
" )\n", " )\n",
" else:\n", " else:\n",
" arr_moves_possible[game] = any(\n", " arr_moves_possible[game] = any(\n",
" recursive_steps(boards[game, :, :], direction, moves[game])\n", " _recursive_steps(boards[game, :, :], direction, moves[game])\n",
" for direction in DIRECTIONS\n", " for direction in DIRECTIONS\n",
" )\n", " )\n",
" return arr_moves_possible\n", " return arr_moves_possible\n",