aboutsummaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'README.md')
-rw-r--r--README.md171
1 files changed, 171 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..719023d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,171 @@
+# Diplomacy
+
+This project contains an open-source DATC-compliant Diplomacy game engine, a client-server architecture for network play, a web interface to play against bots and to visualize games, and a DAIDE-compatible adapter to connect DAIDE bots to the server.
+
+## Getting Started
+
+### Installation
+
+The latest version of the package can be installed with:
+
+```python3
+pip install diplomacy
+```
+
+The package is compatible with Python 3.5, 3.6, and 3.7.
+
+### Running a game
+
+The following script plays a game locally by submitting random valid orders until the game is completed.
+
+```python3
+import json
+import random
+from diplomacy import Game
+from diplomacy.utils.export import to_saved_game_format
+
+# Creating a game
+# Alternatively, a map_name can be specified as an argument. e.g. Game(map_name='pure')
+game = Game()
+while not game.is_game_done:
+
+ # Getting the list of possible orders for all locations
+ possible_orders = game.get_all_possible_orders()
+
+ # For each power, randomly sampling a valid order
+ for power_name, power in game.powers.items():
+ power_orders = [random.choice(possible_orders[loc]) for loc in game.get_orderable_locations(power_name)
+ if possible_orders[loc]]
+ game.set_orders(power_name, power_orders)
+
+ # Messages can be sent locally with game.add_message
+ # e.g. game.add_message(Message(sender='FRANCE',
+ # recipient='ENGLAND',
+ # message='This is a message',
+ # phase=self.get_current_phase(),
+ # time_sent=int(time.time())))
+
+ # Processing the game to move to the next phase
+ game.process()
+
+# Exporting the game to disk to visualize
+with open('game.json', 'w') as file:
+ file.write(json.dumps(to_saved_game_format(game)))
+```
+
+## Web interface
+
+It is also possible to install a web interface in React to play against bots and/or other humans and to visualize games.
+
+The web interface can be installed with:
+
+```bash
+# Install NVM
+curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
+
+# Clone repo
+git clone https://github.com/diplomacy/diplomacy.git
+
+# Install package locally
+# You may want to install it in a conda or virtualenv environment
+cd diplomacy/
+pip install -r requirements_dev.txt
+
+# Build node modules
+cd diplomacy/web
+npm install .
+npm install . --only=dev
+
+# In a terminal window or tab - Launch React server
+npm start
+
+# In another terminal window or tab - Launch diplomacy server
+python -m diplomacy.server.run
+```
+
+The web interface will be accessible at http://localhost:3000.
+
+To login, users can use admin/password or username/password. Additional users can be created by logging in with a username that does not exist in the database.
+
+![](docs/images/web_interface.png)
+
+### Visualizing a game
+
+It is possible to visualize a game by using the "Load a game from disk" menu on the top-right corner of the web interface.
+
+![](docs/images/visualize_game.png)
+
+
+## Network Game
+
+It is possible to join a game remotely over a network using websockets. The script below plays a game over a network.
+
+Note. The server must be started with `python -m diplomacy.server.run` for the script to work.
+
+```python3
+import asyncio
+import random
+from diplomacy.client.connection import connect
+from diplomacy.utils import exceptions
+
+POWERS = ['AUSTRIA', 'ENGLAND', 'FRANCE', 'GERMANY', 'ITALY', 'RUSSIA', 'TURKEY']
+
+async def login(connection, username, password):
+ """ Logins to the server """
+ try:
+ channel = await connection.authenticate(username, password, create_user=True)
+ except exceptions.DiplomacyException:
+ channel = await connection.authenticate(username, password, create_user=False)
+ return channel
+
+async def create_game(game_id, hostname='localhost', port=8432):
+ """ Creates a game on the server """
+ connection = await connect(hostname, port)
+ channel = await login(connection, 'random_user', 'password')
+ await channel.create_game(game_id=game_id, rules={'REAL_TIME', 'NO_DEADLINE', 'POWER_CHOICE'})
+
+async def play(game_id, power_name, hostname='localhost', port=8432):
+ """ Play as the specified power """
+ connection = await connect(hostname, port)
+ channel = await login(connection, 'user_' + power_name, 'password')
+
+ # Waiting for the game, then joining it
+ while not (await channel.list_games(game_id=game_id)):
+ await asyncio.sleep(1.)
+ game = await channel.join_game(game_id=game_id, power_name=power_name)
+
+ # Playing game
+ while not game.is_game_done:
+ current_phase = game.get_current_phase()
+
+ # Submitting orders
+ if game.get_orderable_locations(power_name):
+ possible_orders = game.get_all_possible_orders()
+ orders = [random.choice(possible_orders[loc]) for loc in game.get_orderable_locations(power_name)
+ if possible_orders[loc]]
+ print('[%s/%s] - Submitted: %s' % (power_name, game.get_current_phase(), orders))
+ await game.set_orders(power_name=power_name, orders=orders, wait=False)
+
+ # Messages can be sent with game.send_message
+ # await game.send_game_message(message=game.new_power_message('FRANCE', 'This is the message'))
+
+ # Waiting for game to be processed
+ while current_phase == game.get_current_phase():
+ await asyncio.sleep(0.1)
+
+ # A local copy of the game can be saved with to_saved_game_format
+ # To download a copy of the game with messages from all powers, you need to export the game as an admin
+ # by logging in as 'admin' / 'password'
+
+async def launch(game_id):
+ """ Creates and plays a network game """
+ await create_game(game_id)
+ await asyncio.gather(*[play(game_id, power_name) for power_name in POWERS])
+
+if __name__ == '__main__':
+ asyncio.run(launch(game_id=str(random.randint(1, 1000))))
+
+```
+## License
+
+This project is licensed under the APGLv3 License - see the [LICENSE](LICENSE) file for details