From 15d394ccef9234aa32d5fa12ac63d95a839d02c2 Mon Sep 17 00:00:00 2001
From: Frederic Aust <frederic.aust@hs-bochum.de>
Date: Sat, 6 Mar 2021 19:12:02 +0100
Subject: [PATCH] Initial Init der Python Dateien fuer die Steuerung des Batte
 Pongs

---
 BattlePongAI/ActionSpace.py              |   8 ++
 BattlePongAI/Gym.py                      | 171 +++++++++++++++++++++++
 BattlePongAI/Observation.py              |  19 +++
 BattlePongAI/main.py                     |  60 ++++++++
 BattlePongAI/main_player_two.py          |  34 +++++
 BattlePongAI/main_player_two_training.py |  35 +++++
 BattlePongAI/show_image.py               |  18 +++
 7 files changed, 345 insertions(+)
 create mode 100644 BattlePongAI/ActionSpace.py
 create mode 100644 BattlePongAI/Gym.py
 create mode 100644 BattlePongAI/Observation.py
 create mode 100644 BattlePongAI/main.py
 create mode 100644 BattlePongAI/main_player_two.py
 create mode 100644 BattlePongAI/main_player_two_training.py
 create mode 100644 BattlePongAI/show_image.py

diff --git a/BattlePongAI/ActionSpace.py b/BattlePongAI/ActionSpace.py
new file mode 100644
index 0000000..056003c
--- /dev/null
+++ b/BattlePongAI/ActionSpace.py
@@ -0,0 +1,8 @@
+from enum import Enum
+
+
+class ActionSpace(Enum):
+    nothing=0
+    up=1
+    down=2
+    training=3
\ No newline at end of file
diff --git a/BattlePongAI/Gym.py b/BattlePongAI/Gym.py
new file mode 100644
index 0000000..ec68b40
--- /dev/null
+++ b/BattlePongAI/Gym.py
@@ -0,0 +1,171 @@
+import asyncio
+import random
+from socket import socket
+import json
+import websockets
+
+from ActionSpace import ActionSpace
+import logging
+
+
+class Gym:
+    host = None
+    port = None
+    player = None
+    families = None
+    types = None
+    protocols = None
+    logger = None
+    # Create a TCP/IP socket
+    sock = None
+    last_recieved_JSON = None
+    websocket_server = None
+
+    def __init__(self, host, port, player):
+        self.host = host
+        self.port = port
+        self.player = player
+        random.seed()
+
+        self.families = self.get_constants('AF_')
+        self.types = self.get_constants('SOCK_')
+        self.protocols = self.get_constants('IPPROTO_')
+
+        self.logger = logging.getLogger('websockets')
+        self.logger.setLevel(logging.INFO)
+        self.logger.addHandler(logging.StreamHandler())
+        print('New gym instance IP:%s Port:%s Playername:%S', host, port, player)
+
+    # Call reset function of environment and returns observation
+    async def reset(self):
+        message = '["'+self.player+'","start_game"]'
+        data = []
+        print('send_reset:', message)
+        await self.send_websocket(message, data)
+        print("awaited send_reset")
+        #print(data)
+        return data
+
+    # Connects the player and returns observation
+    async def connect_player(self):
+        message = '["'+self.player+'","connect_player"]'
+        data = []
+        print('connect_player: ', message)
+        await self.send_websocket(message, data)
+        print("awaited send_connect_player")
+        #print(data)
+        return data
+
+    # TPC - creates env
+    def open(self, server_ip=None, port=None):
+        if server_ip is not None:
+            self.host = server_ip
+        if port is not None:
+            self.port = port
+        # connect to server
+        self.create_socket(self.host, self.port)
+
+    # TCP - closes the env
+    def close(self):
+        # send close to server
+        # close socket
+        self.close_socket("Closing environment")
+        pass
+
+    # send action to env returns observation, reward, done, info
+    # creates JSON object
+    async def step(self, action):
+        if isinstance(action, ActionSpace):
+            # action is part of ActionSpace
+            print("go step")
+            data = await self.send_action(action)
+            #print('step done', data)
+            return data
+        else:
+            print("Action is not a valid Step")
+
+    """ Returns a random action of action space
+    """
+    def get_sample_action(self):
+        item = random.randrange(0, len(ActionSpace))
+        return ActionSpace(item)
+
+    # socket_echo_client_easy.py
+
+    def get_constants(self, prefix):
+        """Create a dictionary mapping socket module
+        constants to their names.
+        """
+        return {
+            getattr(socket, n): n
+            for n in dir(socket)
+            if n.startswith(prefix)
+        }
+
+    def create_socket(self, server_ip=None, port=None):
+        if server_ip is not None:
+            self.host = server_ip
+        if port is not None:
+            self.port = port
+
+        # Create a TCP/IP socket
+        self.sock = socket.create_connection(self.host, self.port)
+
+        print('Family  :', self.families[self.sock.family])
+        print('Type    :', self.types[self.sock.type])
+        print('Protocol:', self.protocols[self.sock.proto])
+
+    async def send_action(self, next_action):
+        message = '["'+self.player+'","' +self.player+"_"+ next_action.name + '"]'
+        data = []
+        print('send_action:',message)
+        await self.send_websocket(message, data)
+        #print("awaited send_action")
+        #print(data)
+        return data
+
+    async def send_websocket(self, message, data):
+        uri = "ws://localhost:9080"
+        async with websockets.connect(uri) as websocket:
+            await websocket.send(message)
+            # print(f"> {name}")
+            recieved_values = await websocket.recv()
+            data.append(json.loads(recieved_values))
+            #print(f"< {data}")
+            #print(data)
+
+    async def connect_to_trainer(self):
+        self.websocket_server = websockets.serve(self.get_training, "localhost", 8765)
+
+
+    async def get_training(self):
+        recieved_values = await self.websocket_server.recv()
+        print(f"<{recieved_values}")
+        return json.loads(recieved_values)
+
+
+    def send_tcp(self, message):
+        try:
+            # Send data
+            # test message
+            # message = b'This is the message.  It will be repeated.'
+            print('sending {!r}'.format(message))
+            self.sock.sendall(message)
+
+            amount_received = 0
+            amount_expected = len(message)
+            data = None
+            while amount_received < amount_expected:
+                data = self.sock.recv(16)
+                amount_received += len(data)
+                #print('received {!r}'.format(data))
+            return data
+
+        except Exception as e:
+            self.close_socket("closing socket because of exception {}".format(e.args[-1]))
+
+    # TCP - Closing the socket
+    def close_socket(self, message):
+        print("Closing Socket")
+        print("Msg: " + message)
+        self.sock.close()
diff --git a/BattlePongAI/Observation.py b/BattlePongAI/Observation.py
new file mode 100644
index 0000000..de7a3f7
--- /dev/null
+++ b/BattlePongAI/Observation.py
@@ -0,0 +1,19 @@
+class Observation():
+    # picture of the game
+    picture = None
+
+    # X-Y Coordinates
+    player_pos = None
+
+    # X-Y Coordinates
+    enemy_pos = None
+
+    # 2D-Vector
+    player_direction = None
+
+    # 2D-Vector
+    enemy_direction = None
+
+    # Given observation will be interpreted
+    def __init__(self, observation_tcp):
+        pass
\ No newline at end of file
diff --git a/BattlePongAI/main.py b/BattlePongAI/main.py
new file mode 100644
index 0000000..25bb3fd
--- /dev/null
+++ b/BattlePongAI/main.py
@@ -0,0 +1,60 @@
+import asyncio
+
+import show_image as si
+from ActionSpace import ActionSpace
+from Gym import Gym
+
+
+async def main():
+    print("Hello World!")
+    gym = Gym("localhost", 10000, "player_one")
+    # data = await gym.step(ActionSpace.UP)
+    # print('main data', data)
+    recieved_values = await gym.connect_player()
+    data = recieved_values[0]
+    recieved_values = await gym.reset()
+    data = recieved_values[0]
+    print('main data', data)
+    image_mode = 'RGB'
+    try:
+        # Test show Image
+        si.show_image(image_mode, data['info']['screenshot']['width'], data['info']['screenshot']['height'],
+                      data['info']['screenshot']['image'])
+    except Exception as e:
+        print("failed showing image: " + str(e))
+    resetted = True
+
+    while (True):
+        if data['done']:
+            recieved_values = await gym.reset()
+            data = recieved_values[0]
+        if resetted:
+            resetted = False
+        player_one_y = data['observation']['PlayerOne']['Y']
+        ball_y = data['observation']['ball']['position']['Y']
+        if (player_one_y < ball_y):
+            recieved_values = await gym.step(ActionSpace.down)
+            data = recieved_values[0]
+            print('main data', data)
+        if (player_one_y > ball_y):
+            recieved_values = await gym.step(ActionSpace.up)
+            data = recieved_values[0]
+            print('main data', data)
+        if (player_one_y == ball_y):
+            recieved_values = await gym.step(ActionSpace.nothing)
+            data = recieved_values[0]
+            print('main data', data)
+        try:
+            # Test show Image
+            si.show_image(image_mode, data['info']['screenshot']['width'],
+                          data['info']['screenshot']['height'],
+                          data['info']['screenshot']['image'])
+        except Exception as e:
+            print("failed showing image: " + str(e))
+
+    print('done')
+
+
+if __name__ == "__main__":
+    loop = asyncio.get_event_loop()
+    loop.run_until_complete(main())
diff --git a/BattlePongAI/main_player_two.py b/BattlePongAI/main_player_two.py
new file mode 100644
index 0000000..4e6fc22
--- /dev/null
+++ b/BattlePongAI/main_player_two.py
@@ -0,0 +1,34 @@
+import asyncio
+
+from ActionSpace import ActionSpace
+from Gym import Gym
+
+async def main():
+    print("Hello World!")
+    gym = Gym("localhost", 9080, "player_two")
+
+    recieved_values= await gym.connect_player()
+    data = recieved_values[0]
+    print('main data', data)
+    while(True):
+        player_two_y=data['observation']['PlayerTwo']['Y']
+        ball_y = data['observation']['ball']['position']['Y']
+        if (player_two_y <ball_y):
+            recieved_values = await gym.step(ActionSpace.down)
+            data = recieved_values[0]
+            print('main data', data)
+        if (player_two_y >ball_y):
+            recieved_values = await gym.step(ActionSpace.up)
+            data = recieved_values[0]
+            print('main data', data)
+        if (player_two_y ==ball_y):
+            recieved_values = await gym.step(ActionSpace.nothing)
+            data = recieved_values[0]
+            print('main data', data)
+
+    print('done')
+
+if __name__ == "__main__":
+    loop = asyncio.get_event_loop()
+    loop.run_until_complete(main())
+
diff --git a/BattlePongAI/main_player_two_training.py b/BattlePongAI/main_player_two_training.py
new file mode 100644
index 0000000..700d3e5
--- /dev/null
+++ b/BattlePongAI/main_player_two_training.py
@@ -0,0 +1,35 @@
+import asyncio
+
+import show_image as si
+from ActionSpace import ActionSpace
+from Gym import Gym
+
+
+async def main():
+    print("Hello World!")
+    gym = Gym("localhost", 9080, "player_one")
+
+    recieved_values = await gym.connect_player()
+    data = recieved_values[0]
+    print('main data', data)
+    while (True):
+        player_two_y = data['observation']['PlayerTwo']['Y']
+        ball_y = data['observation']['ball']['position']['Y']
+
+        recieved_values = await gym.step(ActionSpace.training)
+        data = recieved_values[0]
+        try:
+            # Test show Image
+            si.show_image("L", data['info']['screenshot']['width'],
+                          data['info']['screenshot']['height'],
+                          data['info']['screenshot']['image'])
+        except Exception as e:
+            print("failed showing image: " + str(e))
+        print('main data', data)
+
+    print('done')
+
+
+if __name__ == "__main__":
+    loop = asyncio.get_event_loop()
+    loop.run_until_complete(main())
diff --git a/BattlePongAI/show_image.py b/BattlePongAI/show_image.py
new file mode 100644
index 0000000..8a0e785
--- /dev/null
+++ b/BattlePongAI/show_image.py
@@ -0,0 +1,18 @@
+import numpy as np
+import base64
+from PIL import Image
+import zlib as zl
+
+
+def show_image(format, width, height, image):
+    image_decoded = base64.b64decode(image)
+    print(len(image_decoded))
+    print(type(image_decoded))
+    #image_data = ... # byte values of the image
+    image = Image.frombytes(format, (width,height),image_decoded,'raw')
+    #image.show()
+
+    # Save to file
+    #a=np.asarray(image)
+    #im = Image.fromarray(a)
+    #image.save("your_file.jpeg")
-- 
GitLab