├── .gitignore ├── 2.gif ├── 3.gif ├── ALGORITHM.py ├── Board.py ├── Gif 1.gif ├── Main.py ├── ProperitesBoard.py ├── README.md └── gui.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarwanaMostafa/Chinese_Checker/4b32488534d9fe03b8558992be919151b380b740/2.gif -------------------------------------------------------------------------------- /3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarwanaMostafa/Chinese_Checker/4b32488534d9fe03b8558992be919151b380b740/3.gif -------------------------------------------------------------------------------- /ALGORITHM.py: -------------------------------------------------------------------------------- 1 | from ProperitesBoard import * 2 | import copy 3 | 4 | player1_set, player2_set = Intalize_sets() 5 | player1_obj, player2_obj = buildGoalSets() 6 | 7 | def alphabeta(board, depth, player, NUmberCallingPlayer, player1_set, player2_set, alpha, beta): 8 | TempBoard = board[:][:] 9 | if depth == 0: 10 | board_score = CALCULATEBOARDSCORE( 11 | NUmberCallingPlayer, player1_set, player2_set) 12 | return board_score, None 13 | 14 | set_pieces = assign_set(player, player1_set, player2_set) 15 | 16 | GoalSet = assignGOAlSet(player, player1_obj, player2_obj) 17 | 18 | inv_homes_set = [] 19 | 20 | valid_moves = FindALLVALIDMOVE( 21 | TempBoard, set_pieces, GoalSet, inv_homes_set) 22 | 23 | scores = [] 24 | moves = [] 25 | 26 | if player == NUmberCallingPlayer: 27 | 28 | for move in valid_moves: 29 | 30 | TempBoard2 = copy.copy(TempBoard) 31 | new_board, new_set_pieces = MOVE( 32 | TempBoard2, move, set_pieces) 33 | 34 | player1_set, player2_set = ModifySet( 35 | new_set_pieces, player, player1_set, player2_set) 36 | 37 | next_player = player + 1 38 | if next_player == 3: 39 | next_player = 1 40 | 41 | score, something = alphabeta( 42 | new_board, depth - 1, next_player, NUmberCallingPlayer, player1_set, player2_set, alpha, beta) 43 | 44 | scores.append(score) 45 | moves.append(move) 46 | alpha = max(score, alpha) 47 | 48 | if beta <= alpha: 49 | break 50 | 51 | if len(scores) == 0: 52 | return 53 | INDEXAXSCORE = scores.index(max(scores)) 54 | BESTMOVE = moves[INDEXAXSCORE] 55 | return scores[INDEXAXSCORE], BESTMOVE 56 | 57 | else: 58 | for move in valid_moves: 59 | TempBOard2 = copy.copy(TempBoard) 60 | new_board, new_set_pieces = MOVE( 61 | TempBOard2, move, set_pieces) 62 | 63 | player1_set, player2_set = \ 64 | ModifySet(new_set_pieces, player, 65 | player1_set, player2_set) 66 | 67 | next_player = player + 1 68 | if next_player == 3: 69 | next_player = 1 70 | 71 | score, something = alphabeta( 72 | new_board, depth - 1, next_player, NUmberCallingPlayer, player1_set, player2_set, alpha, beta) 73 | 74 | scores.append(score) 75 | moves.append(move) 76 | beta = min(score, beta) 77 | if beta <= alpha: 78 | break 79 | 80 | if len(scores) == 0: 81 | return 82 | INDEXMINSCORE = scores.index(min(scores)) 83 | WORST = moves[INDEXMINSCORE] 84 | return scores[INDEXMINSCORE], WORST 85 | 86 | 87 | 88 | 89 | def minimax(board, depth, player, first_player, player1_set, player2_set): 90 | 91 | TEMPBOARD = board[:][:] 92 | 93 | if depth == 0: 94 | board_score = CALCULATEBOARDSCORE(first_player, player1_set, player2_set) 95 | return board_score, None 96 | 97 | 98 | set_pieces = assign_set(player, player1_set,player2_set) 99 | 100 | obj_set = assignGOAlSet(player, player1_obj, player2_obj) 101 | inv_homes_set = [] 102 | 103 | valid_moves = FindALLVALIDMOVE(TEMPBOARD, set_pieces, obj_set, inv_homes_set) 104 | 105 | 106 | # # -[0,12] 107 | # # -,[1,11] -[1,13] 108 | # # -2,10 -2,12 -2,14 109 | # # -3.9 empty -3,13 -3,15 110 | # # - nodemove - - - 111 | # # 5,7 5,9 5,11 5,13 5,15 5,17 112 | 113 | # # [0.29340139870755805,[[1, 13], [3, 11]] 114 | # # 0.48113629034061417,[[1, 13], [5, 9] 115 | # # 0.19704264032061153,[[2, 10], [3, 11]] 116 | # # 0.2763145659610082, [[2, 10], [4, 8]] 117 | # # 0.2983233934250304, [[2, 10], [4, 12]] 118 | # # 0.2880321533983416,[[2, 12], [4, 14]] 119 | # # 0.19229127669785234,[[2, 12], [3, 11]] 120 | # # 0.2763145659610082, [[2, 14], [4, 16]] 121 | # # 0.2983233934250304,[[2, 14], [4, 12]], 122 | # # 0.2763145659610082,[[2, 14], [4, 8]], 123 | # # 0.10377302861055,[[3, 9], [3, 11]], 124 | # # 0.3035404597800941, [[3, 9], [5, 11]], 125 | # # 0.18304495425094486, [[3, 9], [4, 8]], 126 | # # 0.09357202980226838, [[3, 13], [3, 11]], 127 | # # 0.18931290650275762, [[3, 13], [4, 14]], 128 | # # 0.19485278290668723, [[3, 13], [4, 12]], 129 | # # 0.10377302861055,[[3, 15], [3, 11]], 130 | # # # 0.2915079202436061,[[3, 15], [5, 9]], 131 | # # 0.18304495425094486, [[3, 15], [4, 16]], 132 | # # 0.19951390531103924, [[3, 15], [4, 14]], 133 | # # 0.09911190620619799,[[4, 10], [4, 12]], 134 | # # 0.07710307874217577, [[4, 10], [4, 8]], 135 | # # 0.19759858427132676, [[4, 10], [5, 11]], 136 | # # 0.18556604473483523, [[4, 10], [5, 9]], 137 | # # -0.0021688468982173246 [[4, 10], [3, 11]]] 138 | 139 | 140 | 141 | 142 | 143 | 144 | # [3.6797398707379196, 3.6488147885142688, 3.57973987073792, 3.6151721168448954, 3.691124555589329, 3.6455992566016824, 3.6348793310094223, 3.6141826773899375, 3.7288698521338093, 3.7288921936711414, 3.697116762984306, 3.639846739035154, 3.6031262418599193, 3.6138461674521793, 3.729308708564005, 3.6971391045216384] 145 | # [3.6294249929792315, 3.6375874257090586, 3.6066623434854077, 3.5375874257090585, 3.629424992979231, 3.5730418046906793, 3.573019671816034, 3.684836322276056, 3.6489721105604684, 3.6034468115728213, 3.5927268859805612, 3.5720302323610764, 3.6867174071049478, 3.661178082128734, 3.654368385381875, 3.5972553889368646, 3.597233047399532, 3.5716937224233183, 3.7448875340910566, 3.7758126163147074, 3.6703104094487013, 3.6703104094487013, 3.6543906500460652] 146 | # [3.8332073769328634, 3.833207376932863, 3.7768241886443112, 3.7413698096626904, 3.8104447274390396, 3.7413698096626904, 3.776802055769666, 3.8886187062296877, 3.8527544945141003, 3.8072291955264537, 3.7965092699341936, 3.7758126163147088, 3.89049979105858, 3.8649604660823664, 3.8250449442030354, 3.802282294709212, 3.6868197535973866, 3.727705170066857, 3.727705170066857, 3.88045627349986] 147 | # [3.8783179676026194, 3.878317967602619, 3.821934779314067, 3.7864804003324464, 3.8555553181087956, 3.7864804003324464, 3.8219126464394217, 3.9337292968994437, 3.8701555348727914, 3.847392885378968, 3.731930344267142, 3.661993102142964, 3.772815760736613, 3.772815760736613, 3.925566864169616, 3.896347822331248, 3.8527786426264052, 3.840572671058139, 3.8210255534769018, 3.9354533055849616, 3.9105099131823176] 148 | # [3.9040367263732176, 3.9040367263732176, 3.847653538084666, 3.812199159103045, 3.8812740768793943, 3.812199159103045, 3.847631405210021, 3.959448055670042, 3.8958742936433897, 3.8731116441495663, 3.757649103037741, 3.7985345195072115, 3.7985345195072115, 3.7985345195072115, 3.9512856229402145, 3.919978750440044, 3.879093333970573, 3.8649312431195035, 3.8469013883908745, 3.960913203413025, 3.9609353362876707] 149 | # [4.009747495381982, 4.009747495381982, 3.95336430709343, 3.9179099281118095, 3.9869848458881583, 3.9179099281118095, 3.9533421742187844, 4.0651588246788055, 4.001585062652154, 3.9788224131583303, 3.904287883649104, 3.8633598720465048, 3.904245288515975, 3.904245288515975, 4.056996391948978, 4.0433680341767095, 3.968833504667484, 3.952848885467528, 3.9528711501317186] 150 | # [4.025999266925107, 4.048761916418929, 3.951422142282751, 3.951422142282751, 4.090544887943485, 4.01601035843426, 4.000025739234304, 4.0000480038984945] 151 | # [4.022921698721165, 4.045684348214988, 3.9483445740788095, 3.9483445740788095, 4.076609430438639, 4.020226242150088, 4.020204109275442, 3.93838423983299] 152 | # [3.9982482594478146, 3.9982482594478146, 3.882785718335989, 3.9775130555713343, 3.9236711348054594, 4.006410692177642, 3.9373357744012933, 3.9158915434684607, 3.9727680205082687] 153 | # [3.936006582224108, 3.9587692317179313, 3.9152713783476276, 3.8614294575817527, 3.989694313941582, 3.9333111256530304, 3.9332889927783854, 3.909200393891846] 154 | # [3.9982482594478146, 3.9982482594478146, 3.882785718335989, 3.9775130555713343, 3.9236711348054594, 4.006410692177642, 3.9373357744012933, 3.9158915434684607, 3.9727680205082687] 155 | # [3.9225304088559865, 3.94529305834981, 3.901795204979506, 3.8479532842136313, 3.9762181405734607, 3.919834952284909, 3.919812819410264, 3.837992949967812] 156 | # [4.045029711788794, 4.045029711788794, 3.929567170676968, 4.024294507912313, 3.9704525871464385, 4.053192144518621, 3.9841172267422724, 3.9626729958094398, 3.879974184738578, 3.879974184738578, 4.019549472849247] 157 | # [3.9754856099539913, 3.9982482594478146, 3.954750406077511, 3.900908485311636, 4.0291733416714655, 3.9727901533829137, 3.9727680205082687, 3.8909481510658166] 158 | # [4.049172753792488, 4.049172753792488, 3.933710212680663, 4.028437549916008, 3.974595629150133, 4.057335186522316, 3.988260268745967, 3.9668160378131345, 3.8841172267422728, 4.023692514852943] 159 | 160 | x=1 161 | scores = [] 162 | moves = [] 163 | for move in valid_moves: 164 | TEMPBOARD2 = copy.copy(TEMPBOARD) 165 | new_board, new_set_pieces = MOVE(TEMPBOARD2, move, set_pieces) 166 | 167 | 168 | player1_set, player2_set = \ 169 | ModifySet(new_set_pieces, player, player1_set, player2_set) 170 | 171 | next_player = player + 1 172 | if next_player == 3: 173 | next_player = 1 174 | 175 | score, something = minimax(new_board, depth - 1, next_player, first_player, player1_set, player2_set) 176 | 177 | scores.append(score) 178 | moves.append(move) 179 | 180 | if len(scores) == 0: 181 | return 182 | 183 | 184 | if player == first_player: 185 | # print(scores) 186 | INDEXMAXSCORE = scores.index(max(scores)) 187 | BESTMOVE = moves[INDEXMAXSCORE] 188 | return scores[INDEXMAXSCORE], BESTMOVE 189 | 190 | else: 191 | MINSCOREINDEX = scores.index(min(scores)) 192 | WORST = moves[MINSCOREINDEX] 193 | return scores[MINSCOREINDEX], WORST 194 | 195 | 196 | def CALCULATEBOARDSCORE(NUMPLAYER, p1_pieces, p2_pieces): 197 | 198 | p1_avg_distance = FINDDISTANCEAVGGG( 199 | p1_pieces, player1_obj, 16, 12) # 16,12goalll 200 | p2_avg_distance = FINDDISTANCEAVGGG(p2_pieces, player2_obj, 12, 0) 201 | score = CALCULATECURRENTSCORE(NUMPLAYER, p1_avg_distance, p2_avg_distance) 202 | return score 203 | 204 | 205 | def FINDDISTANCEAVGGG(p_pieces, p_GOAL, _x, _y): 206 | total_distance = 0 207 | Goal_x = _x 208 | Goal_y = _y 209 | x = 1 210 | for obj_piece in p_GOAL: 211 | if obj_piece not in p_pieces: 212 | [Goal_x, Goal_y] = obj_piece 213 | break 214 | for piece in p_pieces: 215 | [x, y] = piece 216 | square_y = (y * 14.43) / 25 217 | square_obj_y = (Goal_y * 14.43) / 25 218 | distance_diag = math.sqrt( 219 | ((Goal_x - x) ** 2) + ((square_obj_y - square_y) ** 2)) 220 | total_distance = total_distance + distance_diag 221 | avg_distance = total_distance / 10 222 | 223 | return avg_distance 224 | 225 | 226 | def CALCULATECURRENTSCORE(Nump, Avg1p1, Avg2p2): 227 | score = 0 228 | if Nump == 1: 229 | pturn_avg_distance = Avg1p1 230 | score = ((Avg2p2 - pturn_avg_distance)) / 2 231 | elif Nump == 2: 232 | pturn_avg_distance = Avg2p2 233 | score = ((Avg1p1 - pturn_avg_distance))/2 234 | return score 235 | -------------------------------------------------------------------------------- /Board.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from ALGORITHM import minimax,alphabeta 3 | def build_board(): 4 | board = np.zeros((17, 25)) 5 | board[:][:] = -1 6 | board[0][12] = 1 7 | board[1][11] = 1 8 | board[1][13] = 1 9 | board[2][10] = 1 10 | board[2][12] = 1 11 | board[2][14] = 1 12 | board[3][9] = 1 13 | board[3][11] = 1 14 | board[3][13] = 1 15 | board[3][15] = 1 16 | 17 | board[4][18] = 0 18 | board[4][20] = 0 19 | board[4][22] = 0 20 | board[4][24] = 0 21 | board[5][19] = 0 22 | board[5][21] = 0 23 | board[5][23] = 0 24 | board[6][20] = 0 25 | board[6][22] = 0 26 | board[7][21] = 0 27 | 28 | board[9][21] = 0 29 | board[10][20] = 0 30 | board[10][22] = 0 31 | board[11][19] = 0 32 | board[11][21] = 0 33 | board[11][23] = 0 34 | board[12][18] = 0 35 | board[12][20] = 0 36 | board[12][22] = 0 37 | board[12][24] = 0 38 | 39 | board[13][9] = 2 40 | board[13][11] = 2 41 | board[13][13] = 2 42 | board[13][15] = 2 43 | board[14][10] = 2 44 | board[14][12] = 2 45 | board[14][14] = 2 46 | board[15][11] = 2 47 | board[15][13] = 2 48 | board[16][12] = 2 49 | 50 | board[9][ 3] = 0 51 | board[10][2] = 0 52 | board[10][4] = 0 53 | board[11][1] = 0 54 | board[11][3] = 0 55 | board[11][5] = 0 56 | board[12][0] = 0 57 | board[12][2] = 0 58 | board[12][4] = 0 59 | board[12][6] = 0 60 | 61 | board[4][0] = 0 62 | board[4][2] = 0 63 | board[4][4] = 0 64 | board[4][6] = 0 65 | board[5][1] = 0 66 | board[5][3] = 0 67 | board[5][5] = 0 68 | board[6][2] = 0 69 | board[6][4] = 0 70 | board[7][3] = 0 71 | 72 | board[4][8] = 0 73 | board[4][10] = 0 74 | board[4][12] = 0 75 | board[4][14] = 0 76 | board[4][16] = 0 77 | 78 | board[5][7] = 0 79 | board[5][9] = 0 80 | board[5][11] = 0 81 | board[5][13] = 0 82 | board[5][15] = 0 83 | board[5][17] = 0 84 | 85 | board[6][6] = 0 86 | board[6][8] = 0 87 | board[6][10] = 0 88 | board[6][12] = 0 89 | board[6][14] = 0 90 | board[6][16] = 0 91 | board[6][18] = 0 92 | 93 | board[7][5] = 0 94 | board[7][7] = 0 95 | board[7][9] = 0 96 | board[7][11] = 0 97 | board[7][13] = 0 98 | board[7][15] = 0 99 | board[7][17] = 0 100 | board[7][19] = 0 101 | 102 | board[8][4] = 0 103 | board[8][6] = 0 104 | board[8][8] = 0 105 | board[8][10] = 0 106 | board[8][12] = 0 107 | board[8][14] = 0 108 | board[8][16] = 0 109 | board[8][18] = 0 110 | board[8][20] = 0 111 | 112 | board[9][5] = 0 113 | board[9][7] = 0 114 | board[9][9] = 0 115 | board[9][11] = 0 116 | board[9][13] = 0 117 | board[9][15] = 0 118 | board[9][17] = 0 119 | board[9][19] = 0 120 | 121 | board[10][6] = 0 122 | board[10][8] = 0 123 | board[10][10] = 0 124 | board[10][12] = 0 125 | board[10][14] = 0 126 | board[10][16] = 0 127 | board[10][18] = 0 128 | 129 | board[11][7] = 0 130 | board[11][9] = 0 131 | board[11][11] = 0 132 | board[11][13] = 0 133 | board[11][15] = 0 134 | board[11][17] = 0 135 | 136 | board[12][8] = 0 137 | board[12][10] = 0 138 | board[12][12] = 0 139 | board[12][14] = 0 140 | board[12][16] = 0 141 | 142 | return board 143 | 144 | 145 | def find_move(board, all_Valid_moves, obj_set, PlayerNUmber, set_pieces, player1_set, player2_set,depth,ALGO): 146 | 147 | # print("objsetttt",obj_set) 148 | # print("PlayerTUREEE",player_turn) 149 | # print("setPIECESSSS",set_pieces) 150 | # print("Player1111_set",player1_set) 151 | # print("Player2222222222_set",player2_set) 152 | 153 | OBJLEF = [i for i in obj_set + 154 | set_pieces if i not in obj_set or i not in set_pieces] 155 | 156 | if len(OBJLEF) == 2: 157 | for move in all_Valid_moves: 158 | start_move = move[0] 159 | end_move = move[1] 160 | if start_move == OBJLEF[1] and end_move == OBJLEF[0]: 161 | return move 162 | try: 163 | if ALGO==1: 164 | score, best_move = minimax(board, depth, PlayerNUmber, PlayerNUmber, player1_set, player2_set) 165 | else: 166 | score, best_move = alphabeta(board, depth, PlayerNUmber, PlayerNUmber, player1_set, player2_set,-99999,99999) 167 | 168 | except Exception: 169 | return 170 | return best_move 171 | 172 | def ISWin(set_pieces, obj_set): 173 | ISWIN = True 174 | for piece in set_pieces: 175 | if piece not in obj_set: 176 | ISWIN = False 177 | return ISWIN 178 | -------------------------------------------------------------------------------- /Gif 1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarwanaMostafa/Chinese_Checker/4b32488534d9fe03b8558992be919151b380b740/Gif 1.gif -------------------------------------------------------------------------------- /Main.py: -------------------------------------------------------------------------------- 1 | from msilib.schema import CheckBox 2 | import tkinter as tk 3 | import sys 4 | from pygame.locals import * 5 | from Board import * 6 | from ProperitesBoard import * 7 | from gui import * 8 | from tkinter import simpledialog 9 | 10 | def main(): 11 | depth = 1 12 | ALGORITHM = 1 13 | ROOT = tk.Tk() 14 | ROOT.withdraw() 15 | Level = simpledialog.askstring( 16 | title="LEVEL", prompt="1-Easy \n2-Medium \n3-Hard") 17 | if int(Level) == 1: 18 | depth = 1 19 | elif int(Level) == 2: 20 | depth = 2 21 | elif int(Level) == 3: 22 | depth = 3 23 | ROOT.destroy() 24 | ROOT.mainloop() 25 | 26 | # ROOT = tk.Tk() 27 | # ROOT.withdraw() 28 | # ALGO = simpledialog.askstring( 29 | # title="LEVEL", prompt="Which Alogrithm \n1-MINMAX\n2-ALPHA-BETA") 30 | # if int(ALGO) == 1: 31 | # ALGORITHM = 1 32 | # elif int(ALGO) == 2: 33 | ALGORITHM = 2 34 | # print(ALGORITHM) 35 | # ROOT.destroy() 36 | # ROOT.mainloop() 37 | p1_win = 0 38 | p2_win = 0 39 | 40 | 41 | board = build_board() 42 | player1_set, player2_set = Intalize_sets() 43 | player1_obj, player2_obj = buildGoalSets() 44 | display_surface = init_board() 45 | 46 | player_turn = 1 47 | 48 | game_over = False 49 | counter = 1 50 | FROM = [] 51 | while True: 52 | draw_board(board, display_surface) 53 | for event in pg.event.get(): 54 | 55 | if event.type == QUIT: 56 | pg.quit() 57 | sys.exit() 58 | if event.type == pg.MOUSEBUTTONDOWN and not game_over: 59 | mouse_pos = pg.mouse.get_pos() 60 | 61 | set_pieces = assign_set(player_turn, player1_set, player2_set) 62 | invalid_homes_set = [] 63 | obj_set = assignGOAlSet(player_turn, player1_obj, player2_obj) 64 | all_legal_moves = FindALLVALIDMOVE( 65 | board, set_pieces, obj_set, invalid_homes_set) 66 | 67 | if player_turn == 1: 68 | XIndex = int((mouse_pos[1]-(mouse_pos[1] % 40) + 20)/40) 69 | YIndex = int((mouse_pos[0]-(mouse_pos[0] % 40)+20)/40)*2 70 | CALC = int((mouse_pos[0] / 40)+0.5) 71 | if XIndex % 2 != 0: 72 | if (mouse_pos[0])/40 < CALC: 73 | YIndex = 1 + \ 74 | int((mouse_pos[0]-(mouse_pos[0] % 40)+20)/40)*2 75 | else: 76 | YIndex = -1 + \ 77 | int((mouse_pos[0]-(mouse_pos[0] % 40)+20)/40)*2 78 | 79 | if counter == 1: 80 | for i in all_legal_moves: 81 | if i[0] == [XIndex, YIndex]: 82 | highlight_move(i, display_surface) 83 | FROM = [XIndex, YIndex] 84 | counter = 2 85 | pg.display.update() 86 | elif counter == 2: 87 | for i in all_legal_moves: 88 | if i[1] == [XIndex, YIndex] and i[0] == FROM: 89 | best_move = i 90 | # print(i) 91 | board, set_pieces = MOVE( 92 | board, best_move, set_pieces) 93 | player1_set, player2_set = ModifySet( 94 | set_pieces, player_turn, player1_set, player2_set) 95 | pg.display.update() 96 | player_turn = 2 97 | counter = 1 98 | 99 | if player_turn == 2: 100 | set_pieces = assign_set( 101 | player_turn, player1_set, player2_set) 102 | invalid_homes_set = [] 103 | obj_set = assignGOAlSet( 104 | player_turn, player1_obj, player2_obj) 105 | all_legal_moves = FindALLVALIDMOVE( 106 | board, set_pieces, obj_set, invalid_homes_set) 107 | best_move = find_move(board, all_legal_moves, obj_set, player_turn, set_pieces, 108 | player1_set, player2_set,depth,ALGORITHM) 109 | 110 | pg.display.update() 111 | board, set_pieces = MOVE(board, best_move, set_pieces) 112 | player1_set, player2_set = ModifySet( 113 | set_pieces, player_turn, player1_set, player2_set) 114 | player_turn = 1 115 | 116 | if best_move is None: 117 | game_over = True 118 | break 119 | 120 | game_over = ISWin(set_pieces, obj_set) 121 | if game_over: 122 | if player_turn == 1: 123 | p1_win = p1_win + 1 124 | if player_turn == 2: 125 | p2_win = p2_win + 1 126 | print('Player 1 wins:', p1_win) 127 | print('Player 2 wins:', p2_win) 128 | 129 | 130 | if __name__ == '__main__': 131 | main() 132 | -------------------------------------------------------------------------------- /ProperitesBoard.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import math 3 | VISITED = 20 4 | NOT_VISITED = 15 5 | 6 | def Intalize_sets(): 7 | # marbles each player 8 | player1_set = [[0, 12], [1, 11], [1, 13], [2, 10], [2, 12], 9 | [2, 14], [3, 9], [3, 11], [3, 13], [3, 15]] # 10 | player2_set = [[13, 9], [13, 11], [13, 13], [13, 15], [14, 10], [ 11 | 14, 12], [14, 14], [15, 11], [15, 13], [16, 12]] # 12 | 13 | return player1_set, player2_set 14 | 15 | def buildGoalSets(): 16 | player1_obj = [[16, 12], [15, 11], [15, 13], [14, 10], [14, 14], [ 17 | 14, 12], [13, 9], [13, 15], [13, 13], [13, 11]] # 18 | player2_obj = [[0, 12], [1, 13], [1, 11], [2, 14], [2, 10], 19 | [2, 12], [3, 15], [3, 9], [3, 11], [3, 13]] # 20 | 21 | return player1_obj, player2_obj 22 | 23 | 24 | def assign_set(player_turn, player1_set, player2_set): 25 | 26 | set_player = player1_set 27 | 28 | if player_turn == 1: 29 | set_player = player1_set 30 | if player_turn == 2: 31 | set_player = player2_set 32 | return set_player 33 | 34 | def assignGOAlSet(NumPlayer, player1_GOal, player2_GOal): 35 | 36 | GOal_set = player1_GOal 37 | 38 | if NumPlayer == 1: 39 | GOal_set = player1_GOal 40 | if NumPlayer == 2: 41 | GOal_set = player2_GOal 42 | return GOal_set 43 | 44 | def ModifySet(pieces, NumPlayer, player1_set, player2_set): 45 | 46 | if NumPlayer == 1: 47 | player1_set = pieces 48 | if NumPlayer == 2: 49 | player2_set = pieces 50 | 51 | return player1_set, player2_set 52 | 53 | 54 | def FindALLVALIDMOVE(board, pieces, Goalset, invalid_homes_set): 55 | valid_moves = [] 56 | 57 | for piece in pieces: 58 | # if piece not in obj_set: 59 | color_board = np.full(board.shape, NOT_VISITED) 60 | valid_moves = check_moves( 61 | board, color_board, piece, 0, piece, valid_moves) # valid moves :contain only marbles which can move 62 | # [[[2, 10], [4, 12]], [[2, 10], [4, 8]], 63 | 64 | # [[[2, 10], [4, 12]], [[2, 10], [4, 8]], 65 | # [[2, 12], [4, 14]], [[2, 12], [4, 10]], 66 | # [[2, 14], [4, 16]], [[2, 14], [4, 12]], 67 | # [[3, 9], [4, 10]], [[3, 9], [4, 8]], 68 | # [[3, 11], [4, 12]], [[3, 11], [4, 10]], 69 | # [[3, 13], [4, 14]], [[3, 13], [4, 12]], 70 | # [[3, 15], [4, 16]], [[3, 15], [4, 14]]] 71 | 72 | # valid_moves = valid_move_in_house(valid_moves, invalid_set, obj_set) 73 | valid_moves = VALIDMOVES(valid_moves, Goalset) 74 | # # [[[0, 12], [2, 14]], [[0, 12], [4, 12]], 75 | # # [[1, 13], [2, 14]], 76 | # # [[2, 10], [2, 14]], [[2, 10], [4, 12]], [[2, 10], [4, 12]], [[2, 10], [4, 8]], 77 | # # [[2, 12], [2, 14]], [[2, 12], [4, 14]], [[2, 12], [4, 10]], 78 | # # [[3, 9], [4, 10]], [[3, 9], [4, 8]], [[3, 11], [4, 12]], [[3, 11], [4, 10]], 79 | # # [[3, 13], [4, 14]], [[3, 13], [4, 12]], [[3, 13], [2, 14]], 80 | # # [[3, 15], [5, 17]], [[3, 15], [4, 14]], [[3, 15], [2, 14]], 81 | # # [[4, 16], [4, 14]], [[4, 16], [5, 17]], [[4, 16], [5, 15]], [[4, 16], [2, 14]], [[4, 16], [4, 12]]] 82 | 83 | # # [[[1, 13], [3, 15]], [[1, 13], [5, 13]], 84 | # # [[2, 10], [4, 12]], [[2, 10], [4, 16]], [[2, 10], [4, 8]], 85 | # # [[2, 12], [4, 10]], [[2, 14], [3, 15]], [[2, 14], [4, 12]], [[2, 14], [4, 16]], 86 | # # [[3, 9], [4, 10]], [[3, 9], [4, 8]], 87 | # # [[3, 11], [3, 15]], [[3, 11], [5, 13]], [[3, 11], [4, 12]], [[3, 11], [4, 10]], 88 | # # [[3, 13], [3, 15]], [[3, 13], [5, 15]], [[3, 13], [4, 12]], 89 | # # [[4, 14], [4, 16]], [[4, 14], [4, 12]], [[4, 14], [5, 15]], [[4, 14], [5, 13]], [[4, 14], [3, 15]]] 90 | 91 | 92 | return valid_moves 93 | 94 | 95 | def check_moves(board, color_board, start, depth, origin, v_moves): 96 | 97 | # set(which has role to play ) which we must choose best node to move 98 | [x_v0, y_v0] = start 99 | color_board[x_v0][y_v0] = VISITED 100 | neighbors_list = neighbors(start) 101 | for x_v1, y_v1 in neighbors_list: # filterrrrrrrrrrrrrrrrrrrrrrrrrrrrrr 102 | if depth == 0 and board[x_v1][y_v1] == 0: 103 | v_moves.append([start, [x_v1, y_v1]]) 104 | 105 | if depth == 0 and board[x_v1][y_v1] > 0: 106 | x_v2, y_v2 = JumbIN(start, x_v1, y_v1) 107 | if board[x_v2][y_v2] == 0: 108 | v_moves.append([start, [x_v2, y_v2]]) 109 | v_moves = check_moves(board, color_board, [ 110 | x_v2, y_v2], depth + 1, origin, v_moves) 111 | if depth > 0 and board[x_v1][y_v1] > 0: 112 | x_v2, y_v2 = JumbIN(start, x_v1, y_v1) 113 | if board[x_v2][y_v2] == 0 and color_board[x_v2][y_v2] == NOT_VISITED: 114 | v_moves.append([origin, [x_v2, y_v2]]) 115 | v_moves = check_moves(board, color_board, [ 116 | x_v2, y_v2], depth + 1, origin, v_moves) 117 | return v_moves 118 | 119 | 120 | def neighbors(node): 121 | [x, y] = node 122 | neighbors = [] 123 | temp = [x, y + 2] 124 | 125 | if 0 <= temp[1] <= 24: 126 | neighbors.append([x, y + 2]) 127 | 128 | temp = [x, y - 2] 129 | if 0 <= temp[1] <= 24: 130 | neighbors.append([x, y - 2]) 131 | temp = [x + 1, y + 1] 132 | 133 | if 0 <= temp[0] <= 16 and 0 <= temp[1] <= 24: 134 | neighbors.append([x + 1, y + 1]) 135 | temp = [x + 1, y - 1] 136 | 137 | if 0 <= temp[0] <= 16 and 0 <= temp[1] <= 24: 138 | neighbors.append([x + 1, y - 1]) 139 | temp = [x - 1, y + 1] 140 | 141 | if 0 <= temp[0] <= 16 and 0 <= temp[1] <= 24: 142 | neighbors.append([x - 1, y + 1]) 143 | temp = [x - 1, y - 1] 144 | 145 | if 0 <= temp[0] <= 16 and 0 <= temp[1] <= 24: 146 | neighbors.append([x - 1, y - 1]) 147 | return neighbors 148 | 149 | 150 | def JumbIN(start, x_1, y_1): 151 | 152 | [start_x, start_y] = start 153 | 154 | x_v2 = x_1 + (x_1 - start_x) 155 | y_v2 = y_1 + (y_1 - start_y) 156 | 157 | if 0 <= x_v2 <= 16 and 0 <= y_v2 <= 24: 158 | return x_v2, y_v2 159 | else: 160 | return 0, 0 161 | 162 | 163 | def VALIDMOVES(valid_moves, obj_set): 164 | # [[2, 10], [4, 12]], [[2, 10], [4, 8]], 165 | # [[2, 12], [4, 14]], [[2, 12], [4, 10]], 166 | # [[2, 14], [4, 16]], [[2, 14], [4, 12]], 167 | # [[3, 9], [4, 10]], [[3, 9], [4, 8]], 168 | # [[3, 11], [4, 12]], [[3, 11], [4, 10]], 169 | # [[3, 13], [4, 14]], [[3, 13], [4, 12]], 170 | # [[3, 15], [4, 16]], [[3, 15], [4, 14]] 171 | 172 | # [[16, 12], [15, 11], [15, 13], [14, 10], [14, 14], [14, 12], [13, 9], [13, 15], [13, 13], [13, 11]] objset 173 | 174 | RemoveMove = [] 175 | for valid_move in valid_moves: 176 | start_move = valid_move[0]#[2,10] 177 | end_move = valid_move[1]#[4,12] 178 | if start_move in obj_set: 179 | 180 | start_y = (start_move[1] * 14.43) / 25 181 | end_y = (end_move[1] * 14.43) / 25 182 | central_pos = (12 * 14.43) / 25 183 | st_diag = math.sqrt( 184 | ((8 - start_move[0]) ** 2) + ((central_pos - start_y) ** 2)) 185 | end_diag = math.sqrt( 186 | ((8 - end_move[0]) ** 2) + ((central_pos - end_y) ** 2)) 187 | if st_diag > end_diag: 188 | RemoveMove.append(valid_move) 189 | 190 | new_valid_moves = [i for i in valid_moves +RemoveMove if i not in valid_moves or i not in RemoveMove] 191 | # print(new_valid_moves) 192 | return new_valid_moves 193 | 194 | def MOVE(board, move, pieces): 195 | [start_x, start_y] = move[0]#0,12 196 | [end_x, end_y] = move[1]#2,14 197 | 198 | piece = board[start_x][start_y] 199 | board[start_x][start_y] = 0#هنا صفر المكان اللى هشيل منه النود 200 | board[end_x][end_y] = piece#هنا بغير القيمة اللى فى المكان ده ولاحظ ان انا بعمل كل ده فى نسخة من البوردة الاصلية مش البورده نفسها 201 | remove = [[start_x, start_y]] 202 | new_set_pieces = [i for i in pieces + 203 | remove if i not in pieces or i not in remove] 204 | new_set_pieces.append([end_x, end_y]) 205 | return board, new_set_pieces 206 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chinese_Checker 2 | Player Vs Computer . different Algorithms AI(like Alpha-Beta Pruning, Min-Max) for computer .support different Levels (Easy,Medium,Hard). board divide 17 *25 and each player has set of marbles 3 | 4 | 5 | ## How To Run : 6 | 1- you must Install Python 7 | 8 | 2- you must Install libraries which using in project like (tkinter ,numby...) 9 | 10 | ## How to Play : 11 | 12 | 1-After installing 1, 2, run Project and enter the level you want to play against 13 | 14 | 2-choose marble which do u need move 15 | 16 | 3-choose destination 17 | ## Rules Game : 18 | __1- can move their piece to any adjacent empty hole like this :__ 19 | 20 | ![](https://github.com/marwana2001/Chinese_Checker/blob/main/3.gif) 21 | 22 | __2-A player’s piece can also hop over an adjacent piece, into an empty hole. That piece can be their own colored piece or the opponent piece. The player can continually hop over subsequent pieces during that turn, and in any direction, as long as there are empty holes on the other side of those pieces.__ 23 | 24 | ![](https://github.com/marwana2001/Chinese_Checker/blob/main/2.gif) 25 | 26 | 27 | -------------------------------------------------------------------------------- /gui.py: -------------------------------------------------------------------------------- 1 | import pygame as pg 2 | # 1 = PLAYER 1 3 | PLAYER1_GREEN = (0, 255, 0) 4 | # 2 = PLAYER 2 5 | PLAYER2_RED = (255, 0, 0) 6 | # board 7 | RADIUS = 20 8 | CIRCLE_DIAMETER = 2 * RADIUS 9 | WINDOW_WIDTH = (CIRCLE_DIAMETER * 13) 10 | WINDOW_HEIGHT = (CIRCLE_DIAMETER * 17) 11 | 12 | 13 | def init_board(): 14 | pg.init() 15 | display_surface = pg.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT)) 16 | pg.display.set_caption('Chinese Checkers AI') 17 | return display_surface 18 | 19 | 20 | def draw_board(board, display_surface): 21 | display_surface.fill((0, 0, 0)) 22 | # لو اتغير الرسمة هتنزل لتحت اوهتطلع 23 | SpaceCol = RADIUS 24 | 25 | for ROW in range(0, 17): 26 | SPACE = RADIUS 27 | space = int(CIRCLE_DIAMETER) 28 | for circle_in_a_row in range(0, 13): 29 | if ROW % 2 == 0: 30 | board_value = board[ROW][circle_in_a_row * 2] 31 | CloroingBoard(board_value, display_surface, 32 | SPACE, SpaceCol) 33 | SPACE = SPACE + CIRCLE_DIAMETER 34 | elif ROW % 2 != 0 and circle_in_a_row != 12: 35 | board_value = board[ROW][circle_in_a_row * 2 + 1] 36 | CloroingBoard(board_value, display_surface, 37 | space, SpaceCol) 38 | space = space + CIRCLE_DIAMETER 39 | 40 | SpaceCol = SpaceCol + CIRCLE_DIAMETER 41 | 42 | 43 | def CloroingBoard(board, surface, x, y): 44 | 45 | if board == -1: 46 | pg.draw.circle(surface, (0, 0, 0), 47 | (x, y), RADIUS, 0) 48 | if board == 0: 49 | pg.draw.circle(surface, (255, 255, 255), 50 | (x, y), RADIUS, 0) 51 | if board == 1: 52 | pg.draw.circle(surface, PLAYER1_GREEN, 53 | (x, y), RADIUS, 0) 54 | if board == 2: 55 | pg.draw.circle(surface, PLAYER2_RED, 56 | (x, y), RADIUS, 0) 57 | 58 | 59 | def highlight_move(move, surface): 60 | 61 | [start_x, start_y] = move[0] # source 62 | [end_x, end_y] = move[1] # destination 63 | 64 | circle_start_x, circle_start_y = find_coordinates(start_x, start_y) 65 | # print("circle_start_x",circle_start_x) 66 | # print("circle_start_y",circle_start_y) 67 | pg.draw.ellipse(surface, (0, 255, 255), (circle_start_x - RADIUS, circle_start_y - RADIUS, 68 | CIRCLE_DIAMETER, CIRCLE_DIAMETER), 5) 69 | 70 | circle_end_x, circle_end_y = find_coordinates(end_x, end_y) 71 | pg.draw.ellipse(surface, (0, 255, 255), (circle_end_x - RADIUS, circle_end_y - RADIUS, 72 | CIRCLE_DIAMETER, CIRCLE_DIAMETER), 5) # 5 :الدايرة تظلل قد ايه سمكها 73 | 74 | 75 | def find_coordinates(x, y): 76 | 77 | if x % 2 == 0: 78 | circle_x = int(RADIUS + 79 | (CIRCLE_DIAMETER) * (y / 2)) 80 | else: 81 | circle_x = int(CIRCLE_DIAMETER + (CIRCLE_DIAMETER) * ((y - 1) 82 | / 2)) 83 | circle_y = RADIUS + (CIRCLE_DIAMETER) * x 84 | 85 | return circle_x, circle_y 86 | 87 | 88 | def highlight_All_move(x, y, surface, move): 89 | 90 | [end_x, end_y] = move 91 | pg.draw.ellipse(surface, (0, 255, 255), (x - RADIUS, y - RADIUS, 92 | CIRCLE_DIAMETER, CIRCLE_DIAMETER), 5) 93 | 94 | circle_end_x, circle_end_y = find_coordinates(end_x, end_y) 95 | pg.draw.ellipse(surface, (0, 255, 255), (circle_end_x - RADIUS, circle_end_y - RADIUS, 96 | CIRCLE_DIAMETER, CIRCLE_DIAMETER), 5) # 5 :الدايرة تظلل قد ايه سمكها 97 | --------------------------------------------------------------------------------