diff options
author | TinWoodman92 <chrhodgden@gmail.com> | 2023-12-16 15:03:53 -0600 |
---|---|---|
committer | TinWoodman92 <chrhodgden@gmail.com> | 2023-12-16 15:03:53 -0600 |
commit | ad8730894e0c43860299631dedadf4e027b814f3 (patch) | |
tree | 1e32399a83851946b8c04875f513f9b24049e641 | |
parent | c5c5cc0793d0c000771ddd88e49e3dd77026f15b (diff) |
Adding tic tac toe content. Like is commented out of home page to activate later.
-rw-r--r-- | index.html | 3 | ||||
-rw-r--r-- | projects_blog/Tic-Tac-Toe-ML-Lab-Kit.html | 75 | ||||
-rw-r--r-- | projects_blog/presentation_code/tictactoe.md | 175 | ||||
-rw-r--r-- | projects_blog/presentation_code/tictactoe.py | 174 | ||||
-rw-r--r-- | style.css | 5 |
5 files changed, 431 insertions, 1 deletions
@@ -25,8 +25,9 @@ </ul> <ul> - Projects + Personal Projects <li class="nnetwork"><a href="projects_blog/NNetwork.html">NNetwork</a></li> + <!-- <li class="tic-tac-toe"><a href="projects_blog/Tic-Tac-Toe-ML-Lab-Kit.html">Tic Tac Toe Machine Learning Lab Kit</a></li> --> </ul> <nav class="nav-footer"> diff --git a/projects_blog/Tic-Tac-Toe-ML-Lab-Kit.html b/projects_blog/Tic-Tac-Toe-ML-Lab-Kit.html new file mode 100644 index 0000000..7780765 --- /dev/null +++ b/projects_blog/Tic-Tac-Toe-ML-Lab-Kit.html @@ -0,0 +1,75 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <title>chrhodgden - NNetwork</title> + <link rel="stylesheet" href="../style.css"/> + <style> + :root { + --theme-color-check: 0; + --accent-hue: var(--tic-tac-toe-hue); + } + </style> +</head> +<body> + + <div class="dark-mode-container"> + <input type="checkbox" id="--dark-theme-check">Dark Mode</input> + </div> + + <h1>Tic Tac Toe Machine Learning Lab Kit</h1> + <p class="header-sub-text">An Interactive Game in which you Train an AI to Play Tic Tac Toe</p> + <nav class="nav-footer"> + <hr> + <a href="#background">Background</a> + | <a href="#the-project">The Project</a> + | <a href="#next-steps">Next Steps</a> + <hr> + </nav> + <br> + <a href="https://github.com/chrhodgden/Tic-Tac-Toe-ML-Lab-Kit" target="_blank">GitHub Repository</a> + <h2 id="background">Background</h2> + <p> + As I was learning python, I made a very simple inteactive tic tac toe game. + I kept polishing it instead of progressing through the tutorial I was in. + In pushing myself to add and debug features I found that I got to a point where I could teach myself by referencing Python's own documentation. + </p> + <a href="./presentation_code/tictactoe.md" target="_blank">Simple version</a> + <p> + This version will work on all platformas that run Python. + </p> + <p> + When I got this version complete, I continued with other tutorials to learn about object oriented programming and other Python libraries. + </p> + <h2 id="the-project">The Project</h2> + <p> + This was a simple and fun project for me to learn python. + Not all the menu items have been set up and will crash if they are selected. + The keyboard interface only works with Microsoft Windows OS. + </p> + <p> + It does not apply proper machine learning techniques. + The "machine learning" is aggregating in raw SQL for each occurance. + They do infact improve and figure out how to play. + </p> + + <h2 id="next-steps">Next Steps</h2> + <p> + Next steps for this project will be to integrate proper machine learning into the the AI profiles. + Then add the rest of the menu elements. + </p> + <p> + I may decide to do this in JavaScript and HTML with the Math.js or TensorFlow libraries. + The potential for this project is educational. + It would be nice to share easily and be more interactive. + </p> + + <nav class="nav-footer"> + <hr> + <a href="..\index.html">Home Page</a> + | <a href="..\about.html">About Page</a> + | <a href="#">Top of Page</a> + <hr> + </nav> + <script src="../app.js"></script> +</body> +</html>
\ No newline at end of file diff --git a/projects_blog/presentation_code/tictactoe.md b/projects_blog/presentation_code/tictactoe.md new file mode 100644 index 0000000..dab8c4f --- /dev/null +++ b/projects_blog/presentation_code/tictactoe.md @@ -0,0 +1,175 @@ +```python +#Next Steps: +# Build & export move log for games +# Build a board timeline variable/class - Export this? +# Build an analysys board class for bots to use thinking through the next commands. +# Look into usin scikit-learn to create a decistion tree model, then have a bot level that loads and uses the model. - See if you could have it programmed itself playing against the other bot levels. Probably need an X model & O model. +# Probably need to translate some of the variables as classes -- THIS WILL BE GOOD FOR EDUCATION -- I NEED TO PRACTICE OBJECT-ORIENTED PROGRAMMING AT LEAST ONCE YOU'D THINK. +# Probably should export the bot functionality to a separate module + + +import random + +def prt_brd(brd): + print(f""" +3 {brd[0][2]}|{brd[1][2]}|{brd[2][2]} +2 {brd[0][1]}|{brd[1][1]}|{brd[2][1]} +1 {brd[0][0]}|{brd[1][0]}|{brd[2][0]} + a b c +""") + +def rnd(i = 1): return random.randint(0,i) + +def bot_cmd(lvl, trn, brd): + if lvl >= 1: + #check for potential victory + #check files and ranks + for r in range(0,3): + if brd[r].count(trn) == 2 and brd[r].count(' ') == 1: return file_name[r]+rank_name[brd[r].index(' ')] + if (brd[0][r]+brd[1][r]+brd[2][r]).count(trn) == 2 and (brd[0][r]+brd[1][r]+brd[2][r]).count(' ') == 1: return file_name[(brd[0][r]+brd[1][r]+brd[2][r]).index(' ')]+rank_name[r] + + #check diagonals + if (brd[0][0]+brd[1][1]+brd[2][2]).count(trn) == 2 and (brd[0][0]+brd[1][1]+brd[2][2]).count(' ') == 1: return file_name[(brd[0][0]+brd[1][1]+brd[2][2]).index(' ')]+rank_name[(brd[0][0]+brd[1][1]+brd[2][2]).index(' ')] + if (brd[0][2]+brd[1][1]+brd[2][0]).count(trn) == 2 and (brd[0][2]+brd[1][1]+brd[2][0]).count(' ') == 1: return file_name[(brd[0][2]+brd[1][1]+brd[2][0]).index(' ')]+rank_name[(brd[2][0]+brd[1][1]+brd[0][2]).index(' ')] + + if lvl >= 2: + alt_trn = plr_trn[trn == 'X'] + #check for potential next-turn loss + #check files and ranks + for r in range(0,3): + if brd[r].count(alt_trn) == 2 and brd[r].count(' ') == 1: return file_name[r]+rank_name[brd[r].index(' ')] + if (brd[0][r]+brd[1][r]+brd[2][r]).count(alt_trn) == 2 and (brd[0][r]+brd[1][r]+brd[2][r]).count(' ') == 1: return file_name[(brd[0][r]+brd[1][r]+brd[2][r]).index(' ')]+rank_name[r] + + #check diagonals + if (brd[0][0]+brd[1][1]+brd[2][2]).count(alt_trn) == 2 and (brd[0][0]+brd[1][1]+brd[2][2]).count(' ') == 1: return file_name[(brd[0][0]+brd[1][1]+brd[2][2]).index(' ')]+rank_name[(brd[0][0]+brd[1][1]+brd[2][2]).index(' ')] + if (brd[0][2]+brd[1][1]+brd[2][0]).count(alt_trn) == 2 and (brd[0][2]+brd[1][1]+brd[2][0]).count(' ') == 1: return file_name[(brd[0][2]+brd[1][1]+brd[2][0]).index(' ')]+rank_name[(brd[2][0]+brd[1][1]+brd[0][2]).index(' ')] + + if lvl >= 3: + random.shuffle(vic_rng) + rng_ind = [0, 1, 2] + #build on existing rows + for rng in vic_rng: + for d in range(0,3): + if rng == file_name[d] and brd[d].count(trn) == 1 and brd[d].count(' ') == 2: + rng_ind.remove(brd[d].index(trn)) + return file_name[d]+rank_name[rng_ind[rnd()]] + elif rng == rank_name[d] and (brd[0][d]+brd[1][d]+brd[2][d]).count(trn) == 1 and (brd[0][d]+brd[1][d]+brd[2][d]).count(' ') == 2: + rng_ind.remove((brd[0][d]+brd[1][d]+brd[2][d]).index(trn)) + return file_name[rng_ind[rnd()]]+rank_name[d] + if rng == 'd1' and (brd[0][0]+brd[1][1]+brd[2][2]).count(trn) == 1 and (brd[0][0]+brd[1][1]+brd[2][2]).count(' ') == 2: + rng_ind.remove((brd[0][0]+brd[1][1]+brd[2][2]).index(trn)) + f = rng_ind[rnd()] + return file_name[f]+rank_name[f] + elif rng == 'd2' and (brd[0][2]+brd[1][1]+brd[2][0]).count(trn) == 1 and (brd[0][2]+brd[1][1]+brd[2][0]).count(' ') == 2: + rng_ind.remove((brd[0][2]+brd[1][1]+brd[2][0]).index(trn)) + f = rng_ind[rnd()] + return file_name[f]+rank_name[2 - f] + + while True: + f = rnd(2) + r = rnd(2) + if board[f][r] == ' ': return file_name[f]+rank_name[r] + +rank = [' ', ' ', ' '] +file = [' ', ' ', ' '] +file_name = ['a', 'b', 'c'] +rank_name = ['1', '2', '3'] +f = 0 +r = 0 +d = 0 +turn = 'X' +vic_chk = False +valid_move = False +board = [file[:], file[:], file[:]] +plrs = -1 +plrs_str = '0' +plr = [False, False] +plr_trn = ('X', 'O') +one_plr = 'X' +bot_lvl = [-1, -1] +lvl_str = '' +bot_lvl_name = ['Random', 'Easy', 'Medium', 'Medium_2'] +vic_rng = file_name + rank_name + ['d1', 'd2'] +rng = '' +rng_ind = [0, 1, 2] + +input("""----- TIC TAC TOE ----- +Press Enter to play! +""") + +while plrs > 2 or plrs < 0: + plrs_str = input("Enter the number of players: ") + if len(plrs_str) > 0: + if plrs_str[0].isnumeric(): plrs = int(plrs_str[0]) +print() + +for r in range(0, plrs): + plr[r] = True + +if plrs == 1: + while True: + one_plr = input("Do you want play as the X's or as the O's? ").upper() + if len(one_plr) > 0: + if one_plr[0] == 'X' or one_plr[0] == 'O': + plr = [one_plr[0] == 'X', one_plr[0] == 'O'] + print() + break + +if False in plr: + for r in range(0, len(bot_lvl_name)): + print(f"Level {r} - {bot_lvl_name[r]}") + print() + +for r in range(0,2): + while not plr[r] and bot_lvl[r] == -1: + lvl_str = input(f"Please select {plr_trn[r]} bot level number: ") + if len(lvl_str) > 0: + if lvl_str[0].isnumeric(): bot_lvl[r] = int(lvl_str[0]) + +prt_brd(board) + +while True: + + valid_move = False + while not valid_move: + #player uses input() + #computer uses bot_cmd() + if plr[turn == 'O']: cmd = input(f"{turn} to Move: ") + else: + cmd = bot_cmd(bot_lvl[turn == 'O'], turn, board) + print(f"{turn} to Move: {cmd}") + if len(cmd) == 2: + if file_name.count(cmd[0]) == 1 and rank_name.count(cmd[1]) == 1: + f = file_name.index(cmd[0]) + r = rank_name.index(cmd[1]) + if board[f][r] == ' ': + board[f][r] = turn + valid_move = True + else: print("Illegal move") + else: print("Invalid move") + else: print("Invalid move") + + prt_brd(board) + + #check for victory + #check files and ranks + for r in range(0,3): + if board[r].count(turn) == 3: vic_chk = True + if (board[0][r]+board[1][r]+board[2][r]).count(turn) == 3: vic_chk = True + + #check diagonals + if (board[0][0]+board[1][1]+board[2][2]).count(turn) == 3: vic_chk = True + if (board[0][2]+board[1][1]+board[2][0]).count(turn) == 3: vic_chk = True + + if vic_chk: break + if board[0].count(' ') + board[1].count(' ') + board[2].count(' ') == 0: break + + turn = plr_trn[turn == 'X'] + +if vic_chk: print(f"{turn} Wins!") +else: print("Draw") + +input() +input("""----- Thank you for playing! ----- +Press Enter to exit. +""")
\ No newline at end of file diff --git a/projects_blog/presentation_code/tictactoe.py b/projects_blog/presentation_code/tictactoe.py new file mode 100644 index 0000000..cad2a2f --- /dev/null +++ b/projects_blog/presentation_code/tictactoe.py @@ -0,0 +1,174 @@ +#Next Steps: +# Build & export move log for games +# Build a board timeline variable/class - Export this? +# Build an analysys board class for bots to use thinking through the next commands. +# Look into usin scikit-learn to create a decistion tree model, then have a bot level that loads and uses the model. - See if you could have it programmed itself playing against the other bot levels. Probably need an X model & O model. +# Probably need to translate some of the variables as classes -- THIS WILL BE GOOD FOR EDUCATION -- I NEED TO PRACTICE OBJECT-ORIENTED PROGRAMMING AT LEAST ONCE YOU'D THINK. +# Probably should export the bot functionality to a separate module + + +import random + +def prt_brd(brd): + print(f""" +3 {brd[0][2]}|{brd[1][2]}|{brd[2][2]} +2 {brd[0][1]}|{brd[1][1]}|{brd[2][1]} +1 {brd[0][0]}|{brd[1][0]}|{brd[2][0]} + a b c +""") + +def rnd(i = 1): return random.randint(0,i) + +def bot_cmd(lvl, trn, brd): + if lvl >= 1: + #check for potential victory + #check files and ranks + for r in range(0,3): + if brd[r].count(trn) == 2 and brd[r].count(' ') == 1: return file_name[r]+rank_name[brd[r].index(' ')] + if (brd[0][r]+brd[1][r]+brd[2][r]).count(trn) == 2 and (brd[0][r]+brd[1][r]+brd[2][r]).count(' ') == 1: return file_name[(brd[0][r]+brd[1][r]+brd[2][r]).index(' ')]+rank_name[r] + + #check diagonals + if (brd[0][0]+brd[1][1]+brd[2][2]).count(trn) == 2 and (brd[0][0]+brd[1][1]+brd[2][2]).count(' ') == 1: return file_name[(brd[0][0]+brd[1][1]+brd[2][2]).index(' ')]+rank_name[(brd[0][0]+brd[1][1]+brd[2][2]).index(' ')] + if (brd[0][2]+brd[1][1]+brd[2][0]).count(trn) == 2 and (brd[0][2]+brd[1][1]+brd[2][0]).count(' ') == 1: return file_name[(brd[0][2]+brd[1][1]+brd[2][0]).index(' ')]+rank_name[(brd[2][0]+brd[1][1]+brd[0][2]).index(' ')] + + if lvl >= 2: + alt_trn = plr_trn[trn == 'X'] + #check for potential next-turn loss + #check files and ranks + for r in range(0,3): + if brd[r].count(alt_trn) == 2 and brd[r].count(' ') == 1: return file_name[r]+rank_name[brd[r].index(' ')] + if (brd[0][r]+brd[1][r]+brd[2][r]).count(alt_trn) == 2 and (brd[0][r]+brd[1][r]+brd[2][r]).count(' ') == 1: return file_name[(brd[0][r]+brd[1][r]+brd[2][r]).index(' ')]+rank_name[r] + + #check diagonals + if (brd[0][0]+brd[1][1]+brd[2][2]).count(alt_trn) == 2 and (brd[0][0]+brd[1][1]+brd[2][2]).count(' ') == 1: return file_name[(brd[0][0]+brd[1][1]+brd[2][2]).index(' ')]+rank_name[(brd[0][0]+brd[1][1]+brd[2][2]).index(' ')] + if (brd[0][2]+brd[1][1]+brd[2][0]).count(alt_trn) == 2 and (brd[0][2]+brd[1][1]+brd[2][0]).count(' ') == 1: return file_name[(brd[0][2]+brd[1][1]+brd[2][0]).index(' ')]+rank_name[(brd[2][0]+brd[1][1]+brd[0][2]).index(' ')] + + if lvl >= 3: + random.shuffle(vic_rng) + rng_ind = [0, 1, 2] + #build on existing rows + for rng in vic_rng: + for d in range(0,3): + if rng == file_name[d] and brd[d].count(trn) == 1 and brd[d].count(' ') == 2: + rng_ind.remove(brd[d].index(trn)) + return file_name[d]+rank_name[rng_ind[rnd()]] + elif rng == rank_name[d] and (brd[0][d]+brd[1][d]+brd[2][d]).count(trn) == 1 and (brd[0][d]+brd[1][d]+brd[2][d]).count(' ') == 2: + rng_ind.remove((brd[0][d]+brd[1][d]+brd[2][d]).index(trn)) + return file_name[rng_ind[rnd()]]+rank_name[d] + if rng == 'd1' and (brd[0][0]+brd[1][1]+brd[2][2]).count(trn) == 1 and (brd[0][0]+brd[1][1]+brd[2][2]).count(' ') == 2: + rng_ind.remove((brd[0][0]+brd[1][1]+brd[2][2]).index(trn)) + f = rng_ind[rnd()] + return file_name[f]+rank_name[f] + elif rng == 'd2' and (brd[0][2]+brd[1][1]+brd[2][0]).count(trn) == 1 and (brd[0][2]+brd[1][1]+brd[2][0]).count(' ') == 2: + rng_ind.remove((brd[0][2]+brd[1][1]+brd[2][0]).index(trn)) + f = rng_ind[rnd()] + return file_name[f]+rank_name[2 - f] + + while True: + f = rnd(2) + r = rnd(2) + if board[f][r] == ' ': return file_name[f]+rank_name[r] + +rank = [' ', ' ', ' '] +file = [' ', ' ', ' '] +file_name = ['a', 'b', 'c'] +rank_name = ['1', '2', '3'] +f = 0 +r = 0 +d = 0 +turn = 'X' +vic_chk = False +valid_move = False +board = [file[:], file[:], file[:]] +plrs = -1 +plrs_str = '0' +plr = [False, False] +plr_trn = ('X', 'O') +one_plr = 'X' +bot_lvl = [-1, -1] +lvl_str = '' +bot_lvl_name = ['Random', 'Easy', 'Medium', 'Medium_2'] +vic_rng = file_name + rank_name + ['d1', 'd2'] +rng = '' +rng_ind = [0, 1, 2] + +input("""----- TIC TAC TOE ----- +Press Enter to play! +""") + +while plrs > 2 or plrs < 0: + plrs_str = input("Enter the number of players: ") + if len(plrs_str) > 0: + if plrs_str[0].isnumeric(): plrs = int(plrs_str[0]) +print() + +for r in range(0, plrs): + plr[r] = True + +if plrs == 1: + while True: + one_plr = input("Do you want play as the X's or as the O's? ").upper() + if len(one_plr) > 0: + if one_plr[0] == 'X' or one_plr[0] == 'O': + plr = [one_plr[0] == 'X', one_plr[0] == 'O'] + print() + break + +if False in plr: + for r in range(0, len(bot_lvl_name)): + print(f"Level {r} - {bot_lvl_name[r]}") + print() + +for r in range(0,2): + while not plr[r] and bot_lvl[r] == -1: + lvl_str = input(f"Please select {plr_trn[r]} bot level number: ") + if len(lvl_str) > 0: + if lvl_str[0].isnumeric(): bot_lvl[r] = int(lvl_str[0]) + +prt_brd(board) + +while True: + + valid_move = False + while not valid_move: + #player uses input() + #computer uses bot_cmd() + if plr[turn == 'O']: cmd = input(f"{turn} to Move: ") + else: + cmd = bot_cmd(bot_lvl[turn == 'O'], turn, board) + print(f"{turn} to Move: {cmd}") + if len(cmd) == 2: + if file_name.count(cmd[0]) == 1 and rank_name.count(cmd[1]) == 1: + f = file_name.index(cmd[0]) + r = rank_name.index(cmd[1]) + if board[f][r] == ' ': + board[f][r] = turn + valid_move = True + else: print("Illegal move") + else: print("Invalid move") + else: print("Invalid move") + + prt_brd(board) + + #check for victory + #check files and ranks + for r in range(0,3): + if board[r].count(turn) == 3: vic_chk = True + if (board[0][r]+board[1][r]+board[2][r]).count(turn) == 3: vic_chk = True + + #check diagonals + if (board[0][0]+board[1][1]+board[2][2]).count(turn) == 3: vic_chk = True + if (board[0][2]+board[1][1]+board[2][0]).count(turn) == 3: vic_chk = True + + if vic_chk: break + if board[0].count(' ') + board[1].count(' ') + board[2].count(' ') == 0: break + + turn = plr_trn[turn == 'X'] + +if vic_chk: print(f"{turn} Wins!") +else: print("Draw") + +input() +input("""----- Thank you for playing! ----- +Press Enter to exit. +""")
\ No newline at end of file @@ -14,6 +14,7 @@ --about-hue: 310; --nnetwork-hue: 240; + --tic-tac-toe-hue: 60; --foreground-lightness: calc(10% + calc(var(--dark-theme-check) * 70%)); --background-lightness: calc(80% - calc(var(--dark-theme-check) * 70%)); @@ -88,6 +89,10 @@ li.nnetwork { color: hsl(var(--nnetwork-hue), 100%, var(--foreground-lightness)); } +li.tic-tac-toe { + color: hsl(var(--tic-tac-toe-hue), 100%, var(--foreground-lightness)); +} + a { color: var(--contrast-color); } |