gapoera.envs.mancala
Mancala Game.
Permainan Mancala di Indonesia dikenal dengan nama Dakon / Congklak. Sebuah mancala memiliki tujuh buah lubang / lumbung di kedua sisinya. Selain itu ada dua lumbung yang berada di sisi kanan dan kiri yang digunakan untuk penilaian. Pemain secara bergiliran memilih salah satu lubang di antara tujuh lubang di depannya, lalu mengambil seluruh biji di dalamnya; dan satu-persatu memasukkan ke lubang lain secara berlawanan arah jarum jam. Ada banyak variasi aturan yang dikenal masyarakat. Pada permainan ini digunakan aturan "Kalah".
Mancala Board Representation:
Pada ilustrasi di bawah ini Mancala diilustrasikan dengan bentuk sederhana dengna tujuh buah lubang / lumbung di kedua sisinya. Setiap lubang dinomori dari 1 sammpai 7 dari kiri ke kanan, dan lumbung penilaian yang berada di ujung kanan diberi nomor 8. Penomoran dilakukan pada kedua sisi dari sudut pandang pemain. Sehingga tampak seperti di bawah. Tanda ">" dan "<" menandankan arah pergerakan biji.
<<<<< player 1 <<<<<
[7, 6, 5, 4, 3, 2, 1] player 0 player 1
[8] [8] --> [[1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7, 8]]
[1, 2, 3, 4, 5, 6, 7]
>>>>> player 0 >>>>>
Pada setiap waktu di permainan, kita mendapat informasi:
- board (list): list of list of int. Tampak seperti di atas bagian kanan.
- current_player (int): player yang sedang bermain (0 atau 1)
- round (int): banyak ronde yang telah berjalan. 1 ronde dihitung ketika semua pemain telah melakukan aksi.
- is_over (bool):
True
jika game sudah berakhir - score (list): score dari game dengan format:
[score_player_0, score_player_1]
Mancala Action Representation (act_id):
Pada Mancala, aksi yang dapat dipilih adalah nomor lubang dimana dia akan mengambil biji-bijinya [1..len_board
].
Lubang paling kiri di sisi pemain berindeks 1.
Jika suatu lubang tidak memiliki biji di dalamnya, maka lubang tersebut tidak dapat dipilih.
View Source
""" ## Mancala Game. Permainan Mancala di Indonesia dikenal dengan nama Dakon / Congklak. Sebuah mancala memiliki tujuh buah lubang / lumbung di kedua sisinya. Selain itu ada dua lumbung yang berada di sisi kanan dan kiri yang digunakan untuk penilaian. Pemain secara bergiliran memilih salah satu lubang di antara tujuh lubang di depannya, lalu mengambil seluruh biji di dalamnya; dan satu-persatu memasukkan ke lubang lain secara berlawanan arah jarum jam. Ada banyak variasi aturan yang dikenal masyarakat. Pada permainan ini digunakan [aturan "Kalah"](https://en.wikipedia.org/wiki/Kalah_(board_game)). ### Mancala Board Representation: Pada ilustrasi di bawah ini Mancala diilustrasikan dengan bentuk sederhana dengna tujuh buah lubang / lumbung di kedua sisinya. Setiap lubang dinomori dari 1 sammpai 7 dari kiri ke kanan, dan lumbung penilaian yang berada di ujung kanan diberi nomor 8. Penomoran dilakukan pada kedua sisi dari sudut pandang pemain. Sehingga tampak seperti di bawah. Tanda ">" dan "<" menandankan arah pergerakan biji. ``` <<<<< player 1 <<<<< [7, 6, 5, 4, 3, 2, 1] player 0 player 1 [8] [8] --> [[1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7, 8]] [1, 2, 3, 4, 5, 6, 7] >>>>> player 0 >>>>> ``` Pada setiap waktu di permainan, kita mendapat informasi: - **board (list)**: list of list of int. Tampak seperti di atas bagian kanan. - **current_player (int)**: player yang sedang bermain (0 atau 1) - **round (int)**: banyak ronde yang telah berjalan. 1 ronde dihitung ketika semua pemain telah melakukan aksi. - **is_over (bool)**: `True` jika game sudah berakhir - **score (list)**: score dari game dengan format: `[score_player_0, score_player_1]` ### Mancala Action Representation (act_id): Pada Mancala, aksi yang dapat dipilih adalah nomor lubang dimana dia akan mengambil biji-bijinya [1..`len_board`]. Lubang paling kiri **di sisi pemain** berindeks 1. Jika suatu lubang tidak memiliki biji di dalamnya, maka lubang tersebut tidak dapat dipilih. --- """ import numpy as np from copy import deepcopy class Mancala(object): def __init__(self, max_round=100, win_reward=10., lose_reward=-10., len_board=7, stone_each=7): """ Inisial parameter berikut digunakan untuk membuat game baru. Game mancala pada Gapoera dapat diatur berapa banyak lubang pada setiap sisinya dan berapa banyak biji yang awalnya ada pada lubang. --- **Parameter:** - max_round (int): maksimum round yang diperbolehkan. Default: 100 - win_reward (float): reward yang diberikan kepada player yang menang. Default: 10. - lose_reward (float): reward yang diberikan kepada player yang kalah. Default: -10. - len_board (int): panjang board. Default: 7 - stone_each (int): biji yang diberikan pada setiap lubang di sisi player. Default: 7 """ self.__version__ = 1.0 self.__max_round = max_round self.in_simulation = False self.WIN_R = win_reward self.LOSE_R = lose_reward self.len_board=len_board self.stone_each=stone_each self.reset() def observe(self, player_id=0) -> dict: """ return observation dari game. Observation adalah state dari game yang tampak oleh salah satu player. --- **Parameter:** - player_id (int): player id yang akan mendapatkan observation. Defaultnya adalah player 0. **Return:** - observation (dict): observation dari game. - board (list): list of list of int. dimensi 0: player 0, dimensi 1: player 1 - current_player (int): player yang sedang bermain - round (int): round yang sedang berjalan - is_over (bool): `True` jika game sudah berakhir - score (list): score dari game. Format: `[score_player_0, score_player_1]` """ board = deepcopy(self.board) if player_id==1: board = [self.board[1], self.board[0]] observed_state = { "board" : board, "current_player" : deepcopy(self.current_player), "round" : deepcopy(self.round), "is_over": self.gameover(), "score": self.get_score() } return observed_state def game_state(self) -> dict: """ return state dari game. State adalah state dari game yang ditampilkan di layar (dari mata pihak ketiga). --- **Return:** - state (dict): state dari game. - board (list): list of list of int. dimensi 0: player 0, dimensi 1: player 1 - current_player (int): player yang sedang bermain - round (int): round yang sedang berjalan - is_over (bool): `True` jika game sudah berakhir - score (list): score dari game. Format: `[score_player_0, score_player_1]` """ state = { "board" : deepcopy(self.board), "current_player" : deepcopy(self.current_player), "round" : deepcopy(self.round), "is_over": self.gameover(), "score": self.get_score() } return state def set_game_state(self, state): """ Set state dari game ke state yang diberikan. --- **Parameter:** - state (dictionary): state dari game. Format seperti yang dikembalikan oleh `game_state` atau `observe`. """ self.board = deepcopy(state["board"]) self.current_player = deepcopy(state["current_player"]) self.round = deepcopy(state["round"]) def reset(self): """ Reset game ke state awal saat game belum dimulai. Fungsi ini akan mengambalikan posisi biji, mengubah nilai menjadi 0, dan mengubah giliran pemain ke pemain ke 0 """ self.board = [[self.stone_each]*(self.len_board+1), [self.stone_each]*(self.len_board+1)] self.board[0][self.len_board]=0 self.board[1][self.len_board]=0 self.current_player = 0 self.round = 0 def valid_act(self, c) -> list: """ return list of valid actions for player `c`. List yang diberikan berisi elemen dengan nilai antara 1..`len_board` yang menunjukkan represnetasi lubang mana yang valid untuk dimainkan (jumlah biji tidak 0). --- **Parameter:** - c (int): player id """ acts = [] for i in range(self.len_board): if self.board[c][i]!=0: acts.append(i+1) # +1 for readability return acts def get_score(self) -> list: """ return score. Score ditampilkan dalam sebuah list dengan format `[score_player_0, score_player_1]` """ return [self.board[0][self.len_board], self.board[1][self.len_board]] def get_current_player(self) -> int: """ return current player, 0 untuk player pertama, 1 untuk player kedua. """ return self.current_player def get_round(self) -> int: """ return current round """ return self.round def gameover(self) -> bool: """ return `True` jika game sudah berakhir. Game berakhir jika salah satu poin ini terpenuhi: - sudah mencapai round maksimum - player meletakkan biji terakhir di sisinya ke kotak paling kanan - tidak ada aksi yang dapat dipilih oleh salah satu player """ return int((sum(self.get_score()) == self.len_board*2*self.stone_each) or \ (self.round > self.__max_round) or \ (len(self.valid_act(0))==0 or len(self.valid_act(1))==0)) def step(self, c, act) -> tuple: """ Digunakan untuk mengaplikasikan suatu aksi ke environment. Hasil dari pemanggilan fungsi ini akan mengubah kondisi dari game state. --- **Parameter:** - c (int): id player yang akan mengambil aksi. 0 untuk player pertama, 1 untuk player kedua, dst. - act (int): id aksi yang akan diambil. Deskripsi id aksi dapat dibaca di `valid_act()`. **Return:** - confirmation (bool): `True` jika aksi berhasil dilakukan, `False` jika tidak. - reward (float): reward yang diberikan kepada player `c` jika aksi berhasil dilakukan. """ act -= 1 # -1 for readability if act < 0 or act > self.len_board-1: return False, 0 if self.board[c][act]==0: return False, 0 if self.current_player != c: return False, 0 self.round += 1 bonus_move = False taken = self.board[c][act] self.board[c][act] = 0 row = c i = act+1 prev = self.board[row][self.len_board] while taken!=0: if row==c or (row!=c and i!=self.len_board): # put the stone or not self.board[row][i] += 1 taken -= 1 if taken==0 and i==self.len_board and row==c: # get the bonus turn or not bonus_move = True elif taken==0 and self.board[row][i]==1 and row==c: # take enemy stone or not self.board[row][self.len_board] += self.board[1-row][self.len_board-i-1]+1 self.board[1-row][self.len_board-i-1] = 0 self.board[row][i] = 0 elif (row==c and i==self.len_board) or (row!=c and i==self.len_board-1): # changing row row = 1-row i = -1 if taken==0 and (len(self.valid_act(0))==0 or len(self.valid_act(1))==0): for j in range(2): for i in range(self.len_board): self.board[j][self.len_board] += self.board[j][i] self.board[j][i] = 0 i += 1 if not bonus_move: self.current_player = 1-c reward = self.board[c][self.len_board] - prev if self.gameover(): if self.board[c][self.len_board] > self.board[1-c][self.len_board]: reward += self.WIN_R else: reward += self.LOSE_R return True, reward def render(self, state=None): """ Digunakan untuk menampilkan tampilan game sederhana di layar (terminal) pada suatu state. --- **Parameter:** - state (dict): state dari game yang akan ditampilkan. Defaultnya akan ambil dari `self.game_state()` """ if state is None: state = self.game_state() print(" p0 ", end="") for i in range(self.len_board): print("["+" "*int(state["board"][0][self.len_board-i-1]<=9)+str(state["board"][0][self.len_board-i-1])+"]",end="") print("\n ["+str(state["board"][0][self.len_board])+"]" + " "*(self.len_board*4-2) + "["+str(state["board"][1][self.len_board])+"]") print(" p1 ", end="") for i in range(self.len_board): print("["+" "*int(state["board"][1][i]<=9)+str(state["board"][1][i])+"]",end="") print()
View Source
class Mancala(object): def __init__(self, max_round=100, win_reward=10., lose_reward=-10., len_board=7, stone_each=7): """ Inisial parameter berikut digunakan untuk membuat game baru. Game mancala pada Gapoera dapat diatur berapa banyak lubang pada setiap sisinya dan berapa banyak biji yang awalnya ada pada lubang. --- **Parameter:** - max_round (int): maksimum round yang diperbolehkan. Default: 100 - win_reward (float): reward yang diberikan kepada player yang menang. Default: 10. - lose_reward (float): reward yang diberikan kepada player yang kalah. Default: -10. - len_board (int): panjang board. Default: 7 - stone_each (int): biji yang diberikan pada setiap lubang di sisi player. Default: 7 """ self.__version__ = 1.0 self.__max_round = max_round self.in_simulation = False self.WIN_R = win_reward self.LOSE_R = lose_reward self.len_board=len_board self.stone_each=stone_each self.reset() def observe(self, player_id=0) -> dict: """ return observation dari game. Observation adalah state dari game yang tampak oleh salah satu player. --- **Parameter:** - player_id (int): player id yang akan mendapatkan observation. Defaultnya adalah player 0. **Return:** - observation (dict): observation dari game. - board (list): list of list of int. dimensi 0: player 0, dimensi 1: player 1 - current_player (int): player yang sedang bermain - round (int): round yang sedang berjalan - is_over (bool): `True` jika game sudah berakhir - score (list): score dari game. Format: `[score_player_0, score_player_1]` """ board = deepcopy(self.board) if player_id==1: board = [self.board[1], self.board[0]] observed_state = { "board" : board, "current_player" : deepcopy(self.current_player), "round" : deepcopy(self.round), "is_over": self.gameover(), "score": self.get_score() } return observed_state def game_state(self) -> dict: """ return state dari game. State adalah state dari game yang ditampilkan di layar (dari mata pihak ketiga). --- **Return:** - state (dict): state dari game. - board (list): list of list of int. dimensi 0: player 0, dimensi 1: player 1 - current_player (int): player yang sedang bermain - round (int): round yang sedang berjalan - is_over (bool): `True` jika game sudah berakhir - score (list): score dari game. Format: `[score_player_0, score_player_1]` """ state = { "board" : deepcopy(self.board), "current_player" : deepcopy(self.current_player), "round" : deepcopy(self.round), "is_over": self.gameover(), "score": self.get_score() } return state def set_game_state(self, state): """ Set state dari game ke state yang diberikan. --- **Parameter:** - state (dictionary): state dari game. Format seperti yang dikembalikan oleh `game_state` atau `observe`. """ self.board = deepcopy(state["board"]) self.current_player = deepcopy(state["current_player"]) self.round = deepcopy(state["round"]) def reset(self): """ Reset game ke state awal saat game belum dimulai. Fungsi ini akan mengambalikan posisi biji, mengubah nilai menjadi 0, dan mengubah giliran pemain ke pemain ke 0 """ self.board = [[self.stone_each]*(self.len_board+1), [self.stone_each]*(self.len_board+1)] self.board[0][self.len_board]=0 self.board[1][self.len_board]=0 self.current_player = 0 self.round = 0 def valid_act(self, c) -> list: """ return list of valid actions for player `c`. List yang diberikan berisi elemen dengan nilai antara 1..`len_board` yang menunjukkan represnetasi lubang mana yang valid untuk dimainkan (jumlah biji tidak 0). --- **Parameter:** - c (int): player id """ acts = [] for i in range(self.len_board): if self.board[c][i]!=0: acts.append(i+1) # +1 for readability return acts def get_score(self) -> list: """ return score. Score ditampilkan dalam sebuah list dengan format `[score_player_0, score_player_1]` """ return [self.board[0][self.len_board], self.board[1][self.len_board]] def get_current_player(self) -> int: """ return current player, 0 untuk player pertama, 1 untuk player kedua. """ return self.current_player def get_round(self) -> int: """ return current round """ return self.round def gameover(self) -> bool: """ return `True` jika game sudah berakhir. Game berakhir jika salah satu poin ini terpenuhi: - sudah mencapai round maksimum - player meletakkan biji terakhir di sisinya ke kotak paling kanan - tidak ada aksi yang dapat dipilih oleh salah satu player """ return int((sum(self.get_score()) == self.len_board*2*self.stone_each) or \ (self.round > self.__max_round) or \ (len(self.valid_act(0))==0 or len(self.valid_act(1))==0)) def step(self, c, act) -> tuple: """ Digunakan untuk mengaplikasikan suatu aksi ke environment. Hasil dari pemanggilan fungsi ini akan mengubah kondisi dari game state. --- **Parameter:** - c (int): id player yang akan mengambil aksi. 0 untuk player pertama, 1 untuk player kedua, dst. - act (int): id aksi yang akan diambil. Deskripsi id aksi dapat dibaca di `valid_act()`. **Return:** - confirmation (bool): `True` jika aksi berhasil dilakukan, `False` jika tidak. - reward (float): reward yang diberikan kepada player `c` jika aksi berhasil dilakukan. """ act -= 1 # -1 for readability if act < 0 or act > self.len_board-1: return False, 0 if self.board[c][act]==0: return False, 0 if self.current_player != c: return False, 0 self.round += 1 bonus_move = False taken = self.board[c][act] self.board[c][act] = 0 row = c i = act+1 prev = self.board[row][self.len_board] while taken!=0: if row==c or (row!=c and i!=self.len_board): # put the stone or not self.board[row][i] += 1 taken -= 1 if taken==0 and i==self.len_board and row==c: # get the bonus turn or not bonus_move = True elif taken==0 and self.board[row][i]==1 and row==c: # take enemy stone or not self.board[row][self.len_board] += self.board[1-row][self.len_board-i-1]+1 self.board[1-row][self.len_board-i-1] = 0 self.board[row][i] = 0 elif (row==c and i==self.len_board) or (row!=c and i==self.len_board-1): # changing row row = 1-row i = -1 if taken==0 and (len(self.valid_act(0))==0 or len(self.valid_act(1))==0): for j in range(2): for i in range(self.len_board): self.board[j][self.len_board] += self.board[j][i] self.board[j][i] = 0 i += 1 if not bonus_move: self.current_player = 1-c reward = self.board[c][self.len_board] - prev if self.gameover(): if self.board[c][self.len_board] > self.board[1-c][self.len_board]: reward += self.WIN_R else: reward += self.LOSE_R return True, reward def render(self, state=None): """ Digunakan untuk menampilkan tampilan game sederhana di layar (terminal) pada suatu state. --- **Parameter:** - state (dict): state dari game yang akan ditampilkan. Defaultnya akan ambil dari `self.game_state()` """ if state is None: state = self.game_state() print(" p0 ", end="") for i in range(self.len_board): print("["+" "*int(state["board"][0][self.len_board-i-1]<=9)+str(state["board"][0][self.len_board-i-1])+"]",end="") print("\n ["+str(state["board"][0][self.len_board])+"]" + " "*(self.len_board*4-2) + "["+str(state["board"][1][self.len_board])+"]") print(" p1 ", end="") for i in range(self.len_board): print("["+" "*int(state["board"][1][i]<=9)+str(state["board"][1][i])+"]",end="") print()
View Source
def __init__(self, max_round=100, win_reward=10., lose_reward=-10., len_board=7, stone_each=7): """ Inisial parameter berikut digunakan untuk membuat game baru. Game mancala pada Gapoera dapat diatur berapa banyak lubang pada setiap sisinya dan berapa banyak biji yang awalnya ada pada lubang. --- **Parameter:** - max_round (int): maksimum round yang diperbolehkan. Default: 100 - win_reward (float): reward yang diberikan kepada player yang menang. Default: 10. - lose_reward (float): reward yang diberikan kepada player yang kalah. Default: -10. - len_board (int): panjang board. Default: 7 - stone_each (int): biji yang diberikan pada setiap lubang di sisi player. Default: 7 """ self.__version__ = 1.0 self.__max_round = max_round self.in_simulation = False self.WIN_R = win_reward self.LOSE_R = lose_reward self.len_board=len_board self.stone_each=stone_each self.reset()
Inisial parameter berikut digunakan untuk membuat game baru. Game mancala pada Gapoera dapat diatur berapa banyak lubang pada setiap sisinya dan berapa banyak biji yang awalnya ada pada lubang.
Parameter:
- max_round (int): maksimum round yang diperbolehkan. Default: 100
- win_reward (float): reward yang diberikan kepada player yang menang. Default: 10.
- lose_reward (float): reward yang diberikan kepada player yang kalah. Default: -10.
- len_board (int): panjang board. Default: 7
- stone_each (int): biji yang diberikan pada setiap lubang di sisi player. Default: 7
View Source
def observe(self, player_id=0) -> dict: """ return observation dari game. Observation adalah state dari game yang tampak oleh salah satu player. --- **Parameter:** - player_id (int): player id yang akan mendapatkan observation. Defaultnya adalah player 0. **Return:** - observation (dict): observation dari game. - board (list): list of list of int. dimensi 0: player 0, dimensi 1: player 1 - current_player (int): player yang sedang bermain - round (int): round yang sedang berjalan - is_over (bool): `True` jika game sudah berakhir - score (list): score dari game. Format: `[score_player_0, score_player_1]` """ board = deepcopy(self.board) if player_id==1: board = [self.board[1], self.board[0]] observed_state = { "board" : board, "current_player" : deepcopy(self.current_player), "round" : deepcopy(self.round), "is_over": self.gameover(), "score": self.get_score() } return observed_state
return observation dari game. Observation adalah state dari game yang tampak oleh salah satu player.
Parameter:
- player_id (int): player id yang akan mendapatkan observation. Defaultnya adalah player 0.
Return:
- observation (dict): observation dari game.
- board (list): list of list of int. dimensi 0: player 0, dimensi 1: player 1
- current_player (int): player yang sedang bermain
- round (int): round yang sedang berjalan
- is_over (bool):
True
jika game sudah berakhir - score (list): score dari game. Format:
[score_player_0, score_player_1]
View Source
def game_state(self) -> dict: """ return state dari game. State adalah state dari game yang ditampilkan di layar (dari mata pihak ketiga). --- **Return:** - state (dict): state dari game. - board (list): list of list of int. dimensi 0: player 0, dimensi 1: player 1 - current_player (int): player yang sedang bermain - round (int): round yang sedang berjalan - is_over (bool): `True` jika game sudah berakhir - score (list): score dari game. Format: `[score_player_0, score_player_1]` """ state = { "board" : deepcopy(self.board), "current_player" : deepcopy(self.current_player), "round" : deepcopy(self.round), "is_over": self.gameover(), "score": self.get_score() } return state
return state dari game. State adalah state dari game yang ditampilkan di layar (dari mata pihak ketiga).
Return:
- state (dict): state dari game.
- board (list): list of list of int. dimensi 0: player 0, dimensi 1: player 1
- current_player (int): player yang sedang bermain
- round (int): round yang sedang berjalan
- is_over (bool):
True
jika game sudah berakhir - score (list): score dari game. Format:
[score_player_0, score_player_1]
View Source
def set_game_state(self, state): """ Set state dari game ke state yang diberikan. --- **Parameter:** - state (dictionary): state dari game. Format seperti yang dikembalikan oleh `game_state` atau `observe`. """ self.board = deepcopy(state["board"]) self.current_player = deepcopy(state["current_player"]) self.round = deepcopy(state["round"])
Set state dari game ke state yang diberikan.
Parameter:
- state (dictionary): state dari game. Format seperti yang dikembalikan oleh
game_state
atauobserve
.
View Source
def reset(self): """ Reset game ke state awal saat game belum dimulai. Fungsi ini akan mengambalikan posisi biji, mengubah nilai menjadi 0, dan mengubah giliran pemain ke pemain ke 0 """ self.board = [[self.stone_each]*(self.len_board+1), [self.stone_each]*(self.len_board+1)] self.board[0][self.len_board]=0 self.board[1][self.len_board]=0 self.current_player = 0 self.round = 0
Reset game ke state awal saat game belum dimulai. Fungsi ini akan mengambalikan posisi biji, mengubah nilai menjadi 0, dan mengubah giliran pemain ke pemain ke 0
View Source
def valid_act(self, c) -> list: """ return list of valid actions for player `c`. List yang diberikan berisi elemen dengan nilai antara 1..`len_board` yang menunjukkan represnetasi lubang mana yang valid untuk dimainkan (jumlah biji tidak 0). --- **Parameter:** - c (int): player id """ acts = [] for i in range(self.len_board): if self.board[c][i]!=0: acts.append(i+1) # +1 for readability return acts
return list of valid actions for player c
. List yang diberikan berisi elemen dengan nilai antara 1..len_board
yang menunjukkan
represnetasi lubang mana yang valid untuk dimainkan (jumlah biji tidak 0).
Parameter:
- c (int): player id
View Source
def get_score(self) -> list: """ return score. Score ditampilkan dalam sebuah list dengan format `[score_player_0, score_player_1]` """ return [self.board[0][self.len_board], self.board[1][self.len_board]]
return score. Score ditampilkan dalam sebuah list dengan format [score_player_0, score_player_1]
View Source
def get_current_player(self) -> int: """ return current player, 0 untuk player pertama, 1 untuk player kedua. """ return self.current_player
return current player, 0 untuk player pertama, 1 untuk player kedua.
View Source
def get_round(self) -> int: """ return current round """ return self.round
return current round
View Source
def gameover(self) -> bool: """ return `True` jika game sudah berakhir. Game berakhir jika salah satu poin ini terpenuhi: - sudah mencapai round maksimum - player meletakkan biji terakhir di sisinya ke kotak paling kanan - tidak ada aksi yang dapat dipilih oleh salah satu player """ return int((sum(self.get_score()) == self.len_board*2*self.stone_each) or \ (self.round > self.__max_round) or \ (len(self.valid_act(0))==0 or len(self.valid_act(1))==0))
return True
jika game sudah berakhir. Game berakhir jika salah satu poin ini terpenuhi:
- sudah mencapai round maksimum
- player meletakkan biji terakhir di sisinya ke kotak paling kanan
- tidak ada aksi yang dapat dipilih oleh salah satu player
View Source
def step(self, c, act) -> tuple: """ Digunakan untuk mengaplikasikan suatu aksi ke environment. Hasil dari pemanggilan fungsi ini akan mengubah kondisi dari game state. --- **Parameter:** - c (int): id player yang akan mengambil aksi. 0 untuk player pertama, 1 untuk player kedua, dst. - act (int): id aksi yang akan diambil. Deskripsi id aksi dapat dibaca di `valid_act()`. **Return:** - confirmation (bool): `True` jika aksi berhasil dilakukan, `False` jika tidak. - reward (float): reward yang diberikan kepada player `c` jika aksi berhasil dilakukan. """ act -= 1 # -1 for readability if act < 0 or act > self.len_board-1: return False, 0 if self.board[c][act]==0: return False, 0 if self.current_player != c: return False, 0 self.round += 1 bonus_move = False taken = self.board[c][act] self.board[c][act] = 0 row = c i = act+1 prev = self.board[row][self.len_board] while taken!=0: if row==c or (row!=c and i!=self.len_board): # put the stone or not self.board[row][i] += 1 taken -= 1 if taken==0 and i==self.len_board and row==c: # get the bonus turn or not bonus_move = True elif taken==0 and self.board[row][i]==1 and row==c: # take enemy stone or not self.board[row][self.len_board] += self.board[1-row][self.len_board-i-1]+1 self.board[1-row][self.len_board-i-1] = 0 self.board[row][i] = 0 elif (row==c and i==self.len_board) or (row!=c and i==self.len_board-1): # changing row row = 1-row i = -1 if taken==0 and (len(self.valid_act(0))==0 or len(self.valid_act(1))==0): for j in range(2): for i in range(self.len_board): self.board[j][self.len_board] += self.board[j][i] self.board[j][i] = 0 i += 1 if not bonus_move: self.current_player = 1-c reward = self.board[c][self.len_board] - prev if self.gameover(): if self.board[c][self.len_board] > self.board[1-c][self.len_board]: reward += self.WIN_R else: reward += self.LOSE_R return True, reward
Digunakan untuk mengaplikasikan suatu aksi ke environment. Hasil dari pemanggilan fungsi ini akan mengubah kondisi dari game state.
Parameter:
- c (int): id player yang akan mengambil aksi. 0 untuk player pertama, 1 untuk player kedua, dst.
- act (int): id aksi yang akan diambil. Deskripsi id aksi dapat dibaca di
valid_act()
.
Return:
- confirmation (bool):
True
jika aksi berhasil dilakukan,False
jika tidak. - reward (float): reward yang diberikan kepada player
c
jika aksi berhasil dilakukan.
View Source
def render(self, state=None): """ Digunakan untuk menampilkan tampilan game sederhana di layar (terminal) pada suatu state. --- **Parameter:** - state (dict): state dari game yang akan ditampilkan. Defaultnya akan ambil dari `self.game_state()` """ if state is None: state = self.game_state() print(" p0 ", end="") for i in range(self.len_board): print("["+" "*int(state["board"][0][self.len_board-i-1]<=9)+str(state["board"][0][self.len_board-i-1])+"]",end="") print("\n ["+str(state["board"][0][self.len_board])+"]" + " "*(self.len_board*4-2) + "["+str(state["board"][1][self.len_board])+"]") print(" p1 ", end="") for i in range(self.len_board): print("["+" "*int(state["board"][1][i]<=9)+str(state["board"][1][i])+"]",end="") print()
Digunakan untuk menampilkan tampilan game sederhana di layar (terminal) pada suatu state.
Parameter:
- state (dict): state dari game yang akan ditampilkan. Defaultnya akan ambil dari
self.game_state()