good actually
This commit is contained in:
		
							parent
							
								
									f08566c35b
								
							
						
					
					
						commit
						006997f9d5
					
				
							
								
								
									
										2
									
								
								ai.json
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								ai.json
									
									
									
									
									
								
							| @ -1 +1 @@ | ||||
| {"1": 17, "4": 17, "256": 19, "37": 19, "97": 19, "289": 19, "1057": 19, "4129": 20, "16417": 20, "65569": 20, "2149": 19, "2341": 19, "6181": 20, "18469": 20, "67621": 20, "100": 19, "292": 19, "1060": 19, "4132": 20, "16420": 20, "65572": 20, "2404": 19, "6244": 20, "18532": 20, "67684": 20, "352": 19, "1312": 21, "4384": 20, "16672": 20, "65824": 20, "2401": 19, "6433": 20, "18721": 20, "67873": 20, "6241": 20, "18529": 20, "67681": 20, "6436": 19, "18724": 20, "67876": 20, "6496": 19, "18784": 20, "67936": 20, "1573": 19, "1633": 20, "5665": 20, "17953": 20, "67105": 20, "1636": 19, "5668": 20, "17956": 20, "67108": 20, "1321": 21, "1384": 20, "5416": 20, "17704": 20, "66856": 20, "132457": 21, "136489": 20, "148777": 20, "33046": 19, "33094": 21, "34054": 20, "37126": 20, "98566": 20, "41302": 20, "42262": 20, "106774": 20, "108886": 20, "34198": 19, "37270": 20, "98710": 20, "34150": 21, "37222": 20, "98662": 20, "35158": 20, "39238": 20, "100678": 20, "265": 20, "280": 20, "328": 20, "1288": 20, "4360": 20, "16648": 20, "65800": 20, "131353": 20, "131401": 20, "132361": 20, "135433": 20, "139609": 20, "140569": 20, "155929": 20, "1": 16, "4": 16, "256": 17, "37": 19, "97": 19, "289": 19, "1057": 20, "4129": 20, "16417": 20, "65569": 20, "8293": 19, "8485": 19, "9253": 20, "24613": 20, "73765": 20, "139621": 19, "140389": 19, "155749": 20, "131077": 19, "131140": 20, "131332": 20, "132100": 22, "135172": 20, "147460": 20, "131173": 19, "131365": 20, "132133": 20, "135205": 20, "147493": 20, "292": 20, "1312": 19, "4384": 20, "16672": 20, "65824": 19, "8545": 20, "9505": 20, "24865": 20, "74017": 20, "140581": 19, "155941": 20, "157093": 21, "32869": 19, "33121": 20, "33889": 20, "36961": 20, "98401": 20, "41317": 19, "42085": 20, "106597": 20, "1060": 20, "4132": 20, "16420": 20, "65572": 20, "8548": 22, "9316": 20, "24676": 20, "73828": 20, "140644": 22, "156004": 20, "2053": 19, "2068": 20, "2116": 20, "2308": 20, "6148": 20, "18436": 20, "67588": 20, "2149": 19, "2341": 20, "6181": 20, "18469": 20, "67621": 20, "517": 19, "532": 19, "580": 19, "4612": 19, "16900": 19, "66052": 20, "613": 19, "1573": 19, "4645": 20, "16933": 19, "66085": 20, "598": 19, "1558": 20, "4630": 20, "16918": 20, "66070": 20, "33046": 19, "33094": 20, "34054": 20, "37126": 20, "98566": 20, "41302": 19, "42262": 20, "106774": 20, "529": 19, "66049": 20, "601": 19, "1561": 20, "4633": 20, "16921": 20, "66073": 20, "1606": 19, "16966": 20, "66118": 20, "8470": 19, "8530": 20, "9490": 20, "24850": 20, "74002": 20, "1633": 20, "5665": 20, "17953": 20, "16996": 20, "21028": 20, "82468": 20, "2374": 20, "2386": 20, "6466": 20, "18754": 20, "67906": 20, "35158": 20, "39238": 20, "100678": 20, "108886": 20, "265": 20, "280": 20, "1288": 20, "4360": 20, "16648": 20, "65800": 20, "131353": 20, "131401": 20, "132361": 20, "135433": 20, "139609": 20, "140569": 20, "155929": 20} | ||||
| {"1": 38, "4": 18, "256": 19, "70": 20, "82": 20, "322": 23, "1090": 20, "4162": 20, "16450": 20, "65602": 18, "65638": 20, "65890": 18, "66658": 20, "69730": 20, "82018": 20, "274": 20, "1282": 20, "65794": 20, "33046": 20, "33094": 20, "34054": 20, "37126": 20, "98566": 21, "98710": 20, "99718": 18, "102790": 23, "104854": 23, "98662": 20, "99622": 20, "102694": 20, "103846": 20, "67942": 20, "72034": 18, "84322": 20, "385": 18, "388": 20, "400": 18, "1408": 18, "34177": 20, "34180": 20, "34192": 20, "38272": 20, "99712": 18, "99730": 20, "103810": 20, "131461": 20, "131473": 20, "135553": 20, "147841": 20, "65554": 56, "66562": 20, "67606": 20, "67666": 20, "71698": 56, "83986": 20, "72214": 18, "72274": 20, "88594": 50, "65665": 20, "65668": 20, "65680": 20, "66688": 18, "69760": 35, "82048": 20, "65926": 20, "65938": 20, "66946": 20, "70018": 20, "82306": 18, "135577": 44, "136345": 20, "153241": 20, "4225": 20, "4228": 20, "5248": 20, "20608": 20, "4753": 16, "4756": 18, "5776": 18, "21136": 18, "70288": 16, "136852": 18, "153232": 20, "10309": 20, "10321": 20, "26689": 18, "75841": 20, "157765": 18, "157777": 20, "158017": 20, "36997": 20, "37009": 20, "37249": 32, "38017": 20, "102529": 20, "37273": 23, "38281": 20, "65569": 20, "65632": 20, "81952": 20, "10585": 20, "26905": 20, "2197": 23, "2449": 20, "6289": 20, "18577": 20, "517": 14, "529": 12, "1537": 12, "66049": 13, "4741": 16, "5761": 18, "5785": 20, "22153": 20, "71305": 18, "598": 18, "1558": 18, "4630": 18, "16918": 18, "66070": 20, "66148": 20, "70180": 20, "82468": 18, "68182": 20, "84502": 20, "66145": 18, "70177": 29, "1609": 20, "5641": 18, "17929": 20, "92758": 20, "66196": 18, "67216": 20, "67204": 18, "82564": 20, "71332": 20, "83620": 18, "135685": 20, "135748": 20, "135781": 20, "136741": 20, "152101": 20} | ||||
							
								
								
									
										1
									
								
								iter2.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								iter2.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| {"1": 14, "4": 14, "256": 14, "37": 19, "97": 19, "289": 18, "1057": 19, "4129": 19, "16417": 19, "65569": 19, "613": 19, "1573": 19, "4645": 20, "16933": 19, "66085": 19, "100": 19, "292": 19, "1060": 19, "4132": 19, "16420": 19, "1636": 19, "4708": 20, "16996": 19, "66148": 20, "352": 19, "4384": 19, "131365": 19, "131425": 19, "132385": 20, "135457": 19, "147745": 20, "164197": 19, "165157": 19, "168229": 20, "8293": 19, "8545": 20, "9313": 20, "24673": 19, "73825": 20, "139621": 19, "140389": 20, "33061": 19, "33124": 20, "34084": 20, "37156": 20, "98596": 20, "169381": 20, "8212": 19, "9220": 19, "8278": 19, "9238": 19, "24598": 20, "73750": 19, "139606": 19, "155734": 20, "2305": 19, "2308": 20, "2320": 20, "2368": 20, "133381": 19, "133393": 20, "133441": 20, "137473": 20, "149761": 20, "1633": 20, "5665": 20, "131428": 20, "132196": 20, "135268": 20, "147556": 20, "4261": 19, "4513": 20, "5281": 20, "20641": 20, "69793": 20, "6565": 19, "22693": 20, "71845": 20, "5668": 20, "38437": 20, "38500": 20, "103972": 20, "104101": 20, "9316": 20, "9508": 20, "1414": 19, "1426": 20, "5506": 20, "17794": 20, "34198": 19, "38278": 20, "99718": 20, "16993": 20, "21025": 20, "82465": 20, "136228": 20, "70177": 20, "21028": 20} | ||||
							
								
								
									
										1
									
								
								iter3.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								iter3.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| {"1": 13, "4": 16, "256": 14, "37": 18, "97": 19, "289": 18, "1057": 19, "4129": 19, "16417": 19, "65569": 19, "613": 19, "1573": 19, "4645": 22, "16933": 19, "66085": 19, "100": 20, "292": 19, "1060": 19, "4132": 19, "16420": 19, "1636": 19, "4708": 20, "16996": 19, "66148": 20, "352": 19, "4384": 19, "131365": 19, "131425": 19, "132385": 20, "135457": 19, "147745": 20, "164197": 19, "165157": 19, "168229": 20, "8293": 19, "8545": 20, "9313": 20, "24673": 19, "73825": 20, "139621": 19, "140389": 20, "33061": 19, "33124": 20, "34084": 20, "37156": 20, "98596": 20, "169381": 20, "8212": 19, "9220": 19, "8278": 19, "9238": 19, "24598": 20, "73750": 19, "139606": 19, "155734": 20, "2305": 19, "2308": 20, "2320": 20, "2368": 20, "133381": 19, "133393": 20, "133441": 20, "137473": 20, "149761": 20, "1633": 20, "5665": 20, "131428": 18, "132196": 20, "135268": 20, "147556": 20, "4261": 19, "4513": 20, "5281": 20, "20641": 20, "69793": 20, "6565": 19, "22693": 20, "71845": 20, "5668": 20, "38437": 20, "38500": 20, "103972": 22, "104101": 20, "9316": 20, "9508": 20, "1414": 19, "1426": 20, "5506": 20, "17794": 20, "34198": 19, "38278": 20, "99718": 20, "16993": 20, "21025": 20, "82465": 20, "136228": 20, "70177": 20, "21028": 20, "21157": 20, "70309": 20, "153253": 22, "2149": 18, "2341": 20, "6181": 20, "18469": 20, "67621": 20, "10597": 18, "26725": 20, "75877": 20, "8548": 23, "73828": 20, "26980": 23, "76132": 20, "517": 21, "580": 20, "4612": 20, "16900": 20, "133": 20, "148": 20, "1156": 20, "4228": 20, "16516": 20, "65668": 20, "421": 20, "1189": 20, "16549": 20, "65701": 20, "132517": 20, "135589": 20, "147877": 20} | ||||
							
								
								
									
										1
									
								
								iter4.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								iter4.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| {"1": 38, "4": 18, "256": 19, "70": 20, "82": 20, "322": 23, "1090": 20, "4162": 20, "16450": 20, "65602": 18, "65638": 20, "65890": 18, "66658": 20, "69730": 20, "82018": 20, "274": 20, "1282": 20, "65794": 20, "33046": 20, "33094": 20, "34054": 20, "37126": 20, "98566": 21, "98710": 20, "99718": 18, "102790": 23, "104854": 23, "98662": 20, "99622": 20, "102694": 20, "103846": 20, "67942": 20, "72034": 18, "84322": 20, "385": 18, "388": 20, "400": 18, "1408": 18, "34177": 20, "34180": 20, "34192": 20, "38272": 20, "99712": 18, "99730": 20, "103810": 20, "131461": 20, "131473": 20, "135553": 20, "147841": 20, "65554": 56, "66562": 20, "67606": 20, "67666": 20, "71698": 56, "83986": 20, "72214": 18, "72274": 20, "88594": 50, "65665": 20, "65668": 20, "65680": 20, "66688": 18, "69760": 35, "82048": 20, "65926": 20, "65938": 20, "66946": 20, "70018": 20, "82306": 18, "135577": 44, "136345": 20, "153241": 20, "4225": 20, "4228": 20, "5248": 20, "20608": 20, "4753": 16, "4756": 18, "5776": 18, "21136": 18, "70288": 16, "136852": 18, "153232": 20, "10309": 20, "10321": 20, "26689": 18, "75841": 20, "157765": 18, "157777": 20, "158017": 20, "36997": 20, "37009": 20, "37249": 32, "38017": 20, "102529": 20, "37273": 23, "38281": 20, "65569": 20, "65632": 20, "81952": 20, "10585": 20, "26905": 20, "2197": 23, "2449": 20, "6289": 20, "18577": 20, "517": 14, "529": 12, "1537": 12, "66049": 13, "4741": 16, "5761": 18, "5785": 20, "22153": 20, "71305": 18, "598": 18, "1558": 18, "4630": 18, "16918": 18, "66070": 20, "66148": 20, "70180": 20, "82468": 18, "68182": 20, "84502": 20, "66145": 18, "70177": 29, "1609": 20, "5641": 18, "17929": 20, "92758": 20, "66196": 18, "67216": 20, "67204": 18, "82564": 20, "71332": 20, "83620": 18, "135685": 20, "135748": 20, "135781": 20, "136741": 20, "152101": 20} | ||||
							
								
								
									
										145
									
								
								main.py
									
									
									
									
									
								
							
							
						
						
									
										145
									
								
								main.py
									
									
									
									
									
								
							| @ -1,16 +1,27 @@ | ||||
| from __future__ import annotations | ||||
| from enum import Enum | ||||
| import json | ||||
| from typing import Optional | ||||
| import random | ||||
| 
 | ||||
| class Ch(Enum): | ||||
|     Empty = 0 | ||||
|     Cross = 1 | ||||
|     Circle = 2 | ||||
| 
 | ||||
| def ch_str(ch: Ch, empty = " ") -> str: | ||||
| def ch_str_fancy(ch: Ch, i = 0) -> str: | ||||
|     match ch: | ||||
|         case Ch.Empty: | ||||
|             return empty | ||||
|             return f"\x1b[0;37m{i}\x1b[0m" | ||||
|         case Ch.Cross: | ||||
|             return "\x1b[1;91mX\x1b[0m" | ||||
|         case Ch.Circle: | ||||
|             return "\x1b[1;94mO\x1b[0m" | ||||
| 
 | ||||
| def ch_str(ch: Ch) -> str: | ||||
|     match ch: | ||||
|         case Ch.Empty: | ||||
|             return " " | ||||
|         case Ch.Cross: | ||||
|             return "X" | ||||
|         case Ch.Circle: | ||||
| @ -75,7 +86,7 @@ class Board: | ||||
|         return "[" + "".join(ch_str(Ch(self.val >> i * CH_WIDTH & 0b11)) for i in range(9)).replace(" ", ".") + "]" | ||||
| 
 | ||||
|     def print(self) -> None: | ||||
|         s = [ch_str(Ch(self.val >> i * CH_WIDTH & 0b11), empty=f"\x1b[0;37m{i}\x1b[0m") for i in range(9)] | ||||
|         s = [ch_str_fancy(Ch(self.val >> i * CH_WIDTH & 0b11), i) for i in range(9)] | ||||
|         print("#############") | ||||
|         print(f"# {s[0]} | {s[1]} | {s[2]} #") | ||||
|         print("#---+---+---#") | ||||
| @ -85,8 +96,9 @@ class Board: | ||||
|         print("#############") | ||||
| 
 | ||||
| START_WEIGHT = 20 | ||||
| REWARD = 1 | ||||
| PUNUSHMENT = 1 | ||||
| WIN_REWARD = 3 | ||||
| DRAW_REWARD = 0 | ||||
| PUNUSHMENT = 2 | ||||
| 
 | ||||
| class AiPlayer: | ||||
|     def __init__(self, ch: Ch) -> None: | ||||
| @ -97,11 +109,15 @@ class AiPlayer: | ||||
|     def clear_choices(self): | ||||
|         self.current_choices = [] | ||||
| 
 | ||||
|     def reward(self): | ||||
|     def reward_win(self): | ||||
|         for choice in self.current_choices: | ||||
|             self.choices[choice] += REWARD | ||||
|             self.choices[choice] += WIN_REWARD | ||||
| 
 | ||||
|     def punish(self): | ||||
|     def reward_draw(self): | ||||
|         for choice in self.current_choices: | ||||
|             self.choices[choice] += DRAW_REWARD | ||||
| 
 | ||||
|     def punish_loss(self): | ||||
|         for choice in self.current_choices: | ||||
|             self.choices[choice] -= PUNUSHMENT | ||||
| 
 | ||||
| @ -119,17 +135,20 @@ class AiPlayer: | ||||
| 
 | ||||
|     def make_play(self, board: Board) -> None: | ||||
|         possible_choices = [(idx, board.with_play(self.ch, idx)) for idx in board.possible_plays()] | ||||
|         # candiate_weigth: Optional[int] = None | ||||
|         candiate_weigth = 0 | ||||
|         candidate_idcs: list[tuple[int, int]] = [] | ||||
|         for idx, choice in possible_choices: | ||||
|             choice = self.interned_choice(choice) | ||||
|             key = choice.key() | ||||
|             if self.choices[key] > candiate_weigth: | ||||
|             if not candiate_weigth or self.choices[key] > candiate_weigth: | ||||
|                 candiate_weigth = self.choices[key] | ||||
|                 candidate_idcs = [(idx, key)] | ||||
|             elif self.choices[key] == candiate_weigth: | ||||
|                 candidate_idcs.append((idx, key)) | ||||
|         (choice_idx, choice_key) = candidate_idcs[0] | ||||
|         if len(candidate_idcs) == 0: | ||||
|             raise Exception() | ||||
|         (choice_idx, choice_key) = candidate_idcs[random.randint(0, len(candidate_idcs) - 1)] | ||||
|         self.current_choices.append(choice_key) | ||||
|         board.play(self.ch, choice_idx) | ||||
| 
 | ||||
| @ -150,59 +169,67 @@ class Game: | ||||
|         self.weights = {} | ||||
| 
 | ||||
| 
 | ||||
| p0 = AiPlayer(Ch.Cross) | ||||
| 
 | ||||
| games = 0 | ||||
| def main(): | ||||
|     p0 = AiPlayer(Ch.Cross) | ||||
| 
 | ||||
|     games = 0 | ||||
| 
 | ||||
| while True: | ||||
|     print(f"\n\nGame #{games}") | ||||
|     board = Board() | ||||
|     p0.clear_choices() | ||||
|     while True: | ||||
|         print("AI's turn") | ||||
|         p0.make_play(board) | ||||
|         board.print() | ||||
|         if board.player_has_won(Ch.Cross): | ||||
|             print("AI won!") | ||||
|             print("Rewarding AI...") | ||||
|             p0.reward() | ||||
|             break | ||||
|         print("Your turn (0..8)") | ||||
|         if board.is_draw(): | ||||
|             print("Draw!") | ||||
|             break | ||||
|         possible_choices = board.possible_plays() | ||||
|         should_restart = False | ||||
|         print(f"\n\nGame #{games}") | ||||
|         board = Board() | ||||
|         p0.clear_choices() | ||||
|         while True: | ||||
|             text = input("> ") | ||||
|             if text == ".save": | ||||
|                 p0.save_to_file() | ||||
|                 continue | ||||
|             elif text == ".load": | ||||
|                 p0.load_from_file() | ||||
|                 choice = 0 | ||||
|                 should_restart = True | ||||
|                 continue | ||||
|             elif text == ".restart": | ||||
|                 choice = 0 | ||||
|                 should_restart = True | ||||
|             print("AI's turn") | ||||
|             p0.make_play(board) | ||||
|             board.print() | ||||
|             if board.player_has_won(Ch.Cross): | ||||
|                 print("AI won!") | ||||
|                 print("Rewarding AI...") | ||||
|                 p0.reward_win() | ||||
|                 break | ||||
|             elif text == "": | ||||
|                 continue | ||||
|             choice = int(text) | ||||
|             if choice not in possible_choices: | ||||
|                 print("invalid choice") | ||||
|             else: | ||||
|             print("Your turn (0..8)") | ||||
|             if board.is_draw(): | ||||
|                 print("Draw!") | ||||
|                 print("Rewarding AI...") | ||||
|                 p0.reward_draw() | ||||
|                 break | ||||
|         if should_restart: | ||||
|             break | ||||
|         board.play(Ch.Circle, choice) | ||||
|         board.print() | ||||
|         if board.player_has_won(Ch.Circle): | ||||
|             print("Player won!") | ||||
|             print("Punishing AI...") | ||||
|             p0.punish() | ||||
|             break | ||||
|     games += 1 | ||||
|             possible_choices = board.possible_plays() | ||||
|             should_restart = False | ||||
|             while True: | ||||
|                 text = input("> ") | ||||
|                 if text == ".save": | ||||
|                     p0.save_to_file() | ||||
|                     continue | ||||
|                 elif text == ".load": | ||||
|                     p0.load_from_file() | ||||
|                     choice = 0 | ||||
|                     should_restart = True | ||||
|                     break | ||||
|                 elif text == ".restart": | ||||
|                     choice = 0 | ||||
|                     should_restart = True | ||||
|                     break | ||||
|                 elif text == "": | ||||
|                     continue | ||||
|                 choice = int(text) | ||||
|                 if choice not in possible_choices: | ||||
|                     print("invalid choice") | ||||
|                 else: | ||||
|                     break | ||||
|             if should_restart: | ||||
|                 break | ||||
|             board.play(Ch.Circle, choice) | ||||
|             board.print() | ||||
|             if board.player_has_won(Ch.Circle): | ||||
|                 print("Player won!") | ||||
|                 print("Punishing AI...") | ||||
|                 p0.punish_loss() | ||||
|                 break | ||||
|         games += 1 | ||||
| 
 | ||||
| try: | ||||
|     main() | ||||
| except KeyboardInterrupt: | ||||
|     pass | ||||
| 
 | ||||
|      | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user