aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJean-Pierre Appel <jeanpierre.appel01@gmail.com>2023-10-23 01:34:33 -0400
committerJean-Pierre Appel <jeanpierre.appel01@gmail.com>2023-10-23 01:34:33 -0400
commit424be4138123e7d8e2e9fef36c71e1638d4e6b2a (patch)
treebc7339af6966ff78fd3ee7fbfe05c4e7974bb256
parent7815a927374db87393d104d095b5de8dfd3a3488 (diff)
testing wsgi post
-rw-r--r--server/.gitignore3
-rw-r--r--server/fast_p_sage.py35
-rw-r--r--server/old/fast_P_nim.py41
-rw-r--r--server/old/human_game.py115
-rw-r--r--server/server.py42
-rw-r--r--server/toggle_game.py134
-rw-r--r--site/game.js56
-rw-r--r--site/index.html26
8 files changed, 452 insertions, 0 deletions
diff --git a/server/.gitignore b/server/.gitignore
new file mode 100644
index 0000000..cfd027d
--- /dev/null
+++ b/server/.gitignore
@@ -0,0 +1,3 @@
+.DS_Store
+__py_cache
+.venv
diff --git a/server/fast_p_sage.py b/server/fast_p_sage.py
new file mode 100644
index 0000000..54902ad
--- /dev/null
+++ b/server/fast_p_sage.py
@@ -0,0 +1,35 @@
+hashStuff = {0: 0, 1: 1, 2: 1, 3: 1, 4: 2, 5: 2}
+
+
+def MEX(S: set) -> int:
+ i = 0
+ while True:
+ if i not in S:
+ return i
+ i += 1
+
+
+def P(n: int) -> int:
+ """
+ Compute nimber for a path of a certain length
+ """
+ if n in hashStuff:
+ return hashStuff[n]
+ res = Prec(n)
+ hashStuff[n] = res
+ return res
+
+
+def Prec(n: int) -> int:
+ S = set()
+ # Works only for n >= 5
+ S.add(P(n-2))
+ S.add(P(n-3))
+ S.add(P(n-4))
+ for i in range(2, n-5+1):
+ S.add(nimAdd(P(i), P(n-3-i)))
+ return MEX(S)
+
+
+def nimAdd(x: int, y: int) -> int:
+ return x ^ y
diff --git a/server/old/fast_P_nim.py b/server/old/fast_P_nim.py
new file mode 100644
index 0000000..adafca1
--- /dev/null
+++ b/server/old/fast_P_nim.py
@@ -0,0 +1,41 @@
+hashStuff = {0: 0, 1: 1, 2: 1, 3: 1, 4: 2, 5: 2}
+
+def MEX(S):
+ i = 0
+ while True:
+ if i not in S:
+ return i
+ i += 1
+
+def P(n):
+ if n in hashStuff:
+ return hashStuff[n]
+ res = Prec(n)
+ hashStuff[n] = res
+ return res
+
+def Prec(n):
+ S = set()
+ # Works only for n >= 5
+ S.add(P(n-2))
+ S.add(P(n-3))
+ S.add(P(n-4))
+ for i in range(2,n-5+1):
+ S.add(nimAdd(P(i),P(n-3-i)))
+ return MEX(S)
+
+def nimAdd(x, y):
+ return x ^ y
+
+# P(7)
+# for i in range(1,1000):
+# print(f"Path, n={i} (oeis={i-1}): {P(i)}")
+
+# Pgames = set()
+# for i in range(20000):
+# if hashStuff[i] == 0:
+# Pgames.add(i)
+
+# for i in range(200):
+# print(i, P(1000*i))
+
diff --git a/server/old/human_game.py b/server/old/human_game.py
new file mode 100644
index 0000000..dbf1f61
--- /dev/null
+++ b/server/old/human_game.py
@@ -0,0 +1,115 @@
+from fast_P_nim import P
+
+def safe_int_parse(s):
+ try:
+ return int(s)
+ except ValueError:
+ return -1
+
+n = int(input("Path size to play on> "))
+
+nimb = P(n)
+
+human_turn = -1 # placeholder
+if nimb > 0:
+ human_turn = False
+ print("I'll play first!")
+else:
+ human_turn = True
+ print("You can play first!")
+
+game_state = [True for _ in range(n)]
+
+def display_game():
+ for i in range(n):
+ if game_state[i]:
+ print(f'{i+1:02d}', end="")
+ else:
+ print(f' ', end="")
+ if i + 1 != n:
+ print('-', end="")
+ print()
+
+def valid_move(i):
+ if i >= n or i < 0:
+ return False
+ if game_state[i]:
+ if i > 0:
+ if i < n-1:
+ return game_state[i-1] or game_state[i+1]
+ else:
+ return game_state[i-1]
+ else:
+ if i < n-1:
+ return game_state[i+1]
+ else:
+ return True
+
+def make_move(i):
+ gs = game_state.copy()
+ gs[i] = False
+ if i > 0:
+ gs[i-1] = not gs[i-1]
+ if i < n-1:
+ gs[i+1] = not gs[i+1]
+ return gs
+
+def get_nimber(gs):
+ nimber_so_far = 0
+ path_size = 0
+ for i in range(n):
+ if gs[i]:
+ path_size += 1
+ else:
+ if path_size == 1 and n != 1:
+ path_size = 0
+ nimber_so_far = nimber_so_far ^ P(path_size)
+ path_size = 0
+ if path_size == 1 and n != 1:
+ path_size = 0
+ nimber_so_far = nimber_so_far ^ P(path_size)
+ return nimber_so_far
+
+def i_have_won():
+ for i in range(n):
+ if valid_move(i):
+ return False
+ return True
+
+def find_move():
+ game_state_orig = game_state.copy()
+ for i in range(n):
+ if valid_move(i):
+ gs = make_move(i)
+ if get_nimber(gs) == 0:
+ return i
+ raise Exception("I have been beat!")
+
+# game_state = make_move(2-1)
+# game_state = make_move(6-1)
+# game_state = make_move(6-1)
+# display_game()
+# print(get_nimber(game_state))
+# raise Exception()
+
+while True:
+ display_game()
+ if human_turn:
+ if i_have_won():
+ print("You're out of moves. I win!")
+ break
+ human_turn = False
+ i = -1 # placeholder
+ while True:
+ i = safe_int_parse(input("Make your move> ")) - 1
+ if valid_move(i):
+ break
+ print("Hey! That's not allowed!")
+ display_game()
+ game_state = make_move(i)
+ else:
+ human_turn = True
+ i = find_move()
+ print(f"Hmm... I'll toggle {i + 1}")
+ game_state = make_move(i)
+
diff --git a/server/server.py b/server/server.py
new file mode 100644
index 0000000..9f04e4e
--- /dev/null
+++ b/server/server.py
@@ -0,0 +1,42 @@
+import json
+import toggle_game
+
+
+def recieve_game(game_json: str) -> dict:
+ game = json.loads(game_json)
+ if game['size'] < 0 or game['size'] > 100:
+ raise Exception("Invalid Board size")
+ if game['finished']:
+ raise Exception("The game is finished")
+ if game['human_turn']:
+ raise Exception("Not the computer's turn")
+ if game['version'] != "0.0.0":
+ raise Exception("Invalid version")
+ return game
+
+
+def send_game(game: dict) -> str:
+ # TODO: mutate game
+ game_json = json.dumps(game)
+ return game_json
+
+
+def application(env, start_response):
+ headers = [('Content-Type', 'application/json')]
+ start_response('200 OK', headers)
+
+ if env['REQUEST_METHOD'] == 'POST':
+ game = {'test': 0}
+ try:
+ game = json.load(env['wsgi.input'])
+ except json.JSONDecodeError:
+ return [json.dumps({'failure': True}).encode('utf-8')]
+ game_json = json.dumps(game)
+ return [game_json.encode('utf-8')]
+
+ return [json.dumps({'not_post': True}).encode('utf-8')]
+
+
+
+def main():
+ pass
diff --git a/server/toggle_game.py b/server/toggle_game.py
new file mode 100644
index 0000000..7932de9
--- /dev/null
+++ b/server/toggle_game.py
@@ -0,0 +1,134 @@
+from fast_P_nim import P
+
+
+def safe_int_parse(s):
+ try:
+ return int(s)
+ except ValueError:
+ return -1
+
+
+def display_game(game: dict) -> None:
+ for i in range(game['size']):
+ if game['board'][i]:
+ print(f'{i+1:02d}', end="")
+ else:
+ print(' ', end="")
+ if i + 1 != game['size']:
+ print('-', end="")
+ print()
+
+
+def valid_move(game: dict, i: int):
+ if i >= game['size'] or i < 0:
+ return False
+ if game['board'][i]:
+ if i > 0:
+ if i < game['size']-1:
+ return game['board'][i-1] or game['board'][i+1]
+ else:
+ return game['board'][i-1]
+ else:
+ if i < game['size']-1:
+ return game['board'][i+1]
+ else:
+ return True
+
+
+def make_move(game: dict, i: int):
+ gs = game['board'].copy()
+ gs[i] = False
+ if i > 0:
+ gs[i-1] = not gs[i-1]
+ if i < game['size']-1:
+ gs[i+1] = not gs[i+1]
+ return gs
+
+
+def get_nimber(gs: list) -> int:
+ n = len(gs)
+ nimber_so_far = 0
+ path_size = 0
+ for i in range(n):
+ if gs[i]:
+ path_size += 1
+ else:
+ if path_size == 1 and n != 1:
+ path_size = 0
+ nimber_so_far = nimber_so_far ^ P(path_size)
+ path_size = 0
+ if path_size == 1 and n != 1:
+ path_size = 0
+ nimber_so_far = nimber_so_far ^ P(path_size)
+ return nimber_so_far
+
+
+def i_have_won(game: dict) -> bool:
+ for i in range(game['size']):
+ if valid_move(game, i):
+ return False
+ return True
+
+
+def find_move(game: dict) -> int:
+ game_state_orig = game['board'].copy()
+ for i in range(game['size']):
+ if valid_move(game, i):
+ gs = make_move(game, i)
+ if get_nimber(gs) == 0:
+ return i
+ raise Exception("I have been beat!")
+
+
+def new_game(size: int) -> dict:
+ game = {}
+ game['board'] = [True] * size
+ game['human_turn'] = not P(size) > 0
+ game['size'] = size
+ game['version'] = '0.0.0'
+ game['finished'] = False
+ game['winner'] = ""
+ game['turn'] = 1
+ return game
+
+
+def main():
+ n = int(input("Path size to play on> "))
+ game = new_game(n)
+
+ if game['human_turn']:
+ print("You can play first!")
+ else:
+ print("I'll play first!")
+
+ while True:
+ display_game(game)
+ if game['human_turn']:
+ if i_have_won(game):
+ print("You're out of moves. I win!")
+ game['finished'] = True
+ game['winner'] = "Computer"
+ break
+ game['human_turn'] = False
+ i = -1 # placeholder
+ while True:
+ i = safe_int_parse(input("Make your move> ")) - 1
+ if valid_move(game, i):
+ break
+ print("Hey! That's not allowed!")
+ display_game(game)
+ game['turn'] += 1
+ game['board'] = make_move(game, i)
+ else:
+ game['human_turn'] = True
+ i = find_move(game)
+ print(f"Hmm... I'll toggle {i + 1}")
+ game['turn'] += 1
+ game['board'] = make_move(game, i)
+
+ print('-'*8)
+ for key, val in game.items():
+ print(f'{key}: {val}')
+
+if __name__ == "__main__":
+ main()
diff --git a/site/game.js b/site/game.js
new file mode 100644
index 0000000..4a5eff9
--- /dev/null
+++ b/site/game.js
@@ -0,0 +1,56 @@
+const order = document.getElementById("graphOrder");
+//TODO: read in player's name
+
+
+function foo(){
+ console.log(order.valueAsNumber);
+}
+
+function getNimber(length){
+ //TODO: copy from fast_p_sage
+ //TODO: put in seperate file
+}
+
+function createGame(length){
+ const game = {
+ board: Array(length).fill(1),
+ turn: getNimber(length) > 0 ? "computer" : "human",
+ finished: false,
+ result: "In Progress...",
+ //FIXME: turn shouldn't be an argument,
+ //FIXME: human and computer Play needs the game as an argument
+ nextTurn: (turn) => {
+ if(turn === "computer")
+ computerPlay()
+ else
+ humanPlay()
+ }
+ }
+ //TODO: create game in DOM
+ return game;
+}
+
+function computerPlay(game){
+
+}
+
+function humanPlay(game){
+
+}
+
+function renderGame(game){
+ //TODO: update game in DOM
+}
+
+function displayMessage(text){
+
+}
+
+function playGame(){
+ const length = order.valueAsNumber;
+ const game = createGame(length);
+ while(!game.finished){
+ game.nextTurn(game.turn);
+ }
+ displayMessage(game.result);
+}
diff --git a/site/index.html b/site/index.html
new file mode 100644
index 0000000..24d50d2
--- /dev/null
+++ b/site/index.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Toggle Online</title>
+ </head>
+ <body>
+ <h1>Toggle Online</h1>
+ Try to beat the computer :)
+ <nav></nav>
+ <button onclick="foo()">Test</button>
+ <main>
+ <section id="options" class="screen">
+ <h2>Options</h2>
+ <label for="graphOrder">Select a number of vertices for a path (0-100):</label>
+ <input type="number" name="graphOrder" id="graphOrder" defaultValue=7 min=0 max=100></input>
+ </section>
+ <section id="game" class="screen">
+ <h2>Game</h2>
+
+ <script src="game.js"></script>
+ </section>
+ </main>
+ </body>
+</html>