From 1606653546958fd6d621809ab3cfdc8c5e7b8494 Mon Sep 17 00:00:00 2001
From: Philip Paquette <pcpaquette@gmail.com>
Date: Mon, 9 Sep 2019 17:57:09 -0400
Subject: Added ability to load a custom map by specifying the path to a '.map'
 file

---
 diplomacy/engine/game.py             |  4 ++--
 diplomacy/engine/map.py              | 15 ++++++++++-----
 diplomacy/maps/tests/test_map_gen.py |  9 +++++++++
 diplomacy/utils/convoy_paths.py      |  6 +++++-
 4 files changed, 26 insertions(+), 8 deletions(-)

(limited to 'diplomacy')

diff --git a/diplomacy/engine/game.py b/diplomacy/engine/game.py
index 8da3480..5f0bb2e 100644
--- a/diplomacy/engine/game.py
+++ b/diplomacy/engine/game.py
@@ -79,8 +79,8 @@ class Game(Jsonable):
                 e.g. {'PAR': 'FRANCE'}  to indicate that PAR was lost by France (previous owner)
         - map: Contains a reference to the current map (Map instance)
                 e.g. map = Map('standard')
-        - map_name: Contains a reference to the name of the map that was loaded
-                e.g. map_name = 'standard'
+        - map_name: Contains a reference to the name of the map that was loaded (or a full path to a custom map file)
+                e.g. map_name = 'standard' or map_name = '/some/path/to/file.map'
         - messages (only for non-observer games): history of messages exchanged inside this game.
                 Sorted dict mapping message timestamps to message objects (instances of diplomacy.Message).
                 Format: {message.time_sent => message}
diff --git a/diplomacy/engine/map.py b/diplomacy/engine/map.py
index 13d430b..65bcdfa 100644
--- a/diplomacy/engine/map.py
+++ b/diplomacy/engine/map.py
@@ -74,8 +74,8 @@ class Map():
                 e.g. {'MAO': 'WATER', 'SER': 'LAND', 'SYR': 'COAST', 'MOS': 'LAND', 'VEN': 'COAST', ... }
         - locs: List of 3 letter locations (With coasts)
                 e.g. ['ADR', 'AEG', 'ALB', 'ANK', 'APU', 'ARM', 'BAL', 'BAR', 'BEL', 'BER', ... ]
-        - name: Name of the map
-                e.g. 'standard'
+        - name: Name of the map (or full path to a custom map file)
+                e.g. 'standard' or '/some/path/to/file.map'
         - own_word: Dict to indicate the word used to refer to people living in each power's country
                 e.g. {'RUSSIA': 'RUSSIAN', 'FRANCE': 'FRENCH', 'UNOWNED': 'UNOWNED', 'TURKEY': 'TURKISH', ... }
         - owns: List that indicates which power have a OWNS or CENTERS line
@@ -128,7 +128,7 @@ class Map():
 
     def __init__(self, name='standard', use_cache=True):
         """ Constructor function
-            :param name: Name of the map to load
+            :param name: Name of the map to load (or full path to a custom map file)
             :param use_cache: Boolean flag to indicate we want a blank object that doesn't use cache
         """
         if name in MAP_CACHE:
@@ -302,8 +302,13 @@ class Map():
         # Otherwise file_name is the file handler
         power = 0
         if file_name is None:
-            file_name = '{}.map'.format(self.name)
-        file_path = os.path.join(settings.PACKAGE_DIR, 'maps', file_name)
+            file_name = '{}.map'.format(self.name) if not self.name.endswith('.map') else self.name
+
+        # If file_name is a path to a custom map, we use that path, otherwise, we check in the maps folder
+        if os.path.exists(file_name):
+            file_path = file_name
+        else:
+            file_path = os.path.join(settings.PACKAGE_DIR, 'maps', file_name)
 
         # Checking if file exists:
         found_map = 1 if os.path.exists(file_path) else 0
diff --git a/diplomacy/maps/tests/test_map_gen.py b/diplomacy/maps/tests/test_map_gen.py
index 84884db..48084fb 100644
--- a/diplomacy/maps/tests/test_map_gen.py
+++ b/diplomacy/maps/tests/test_map_gen.py
@@ -34,3 +34,12 @@ def test_map_creation():
         this_map = Map(map_name)
         assert this_map.error == [], 'Map %s should have no errors' % map_name
         del this_map
+
+def test_map_with_full_path():
+    """ Tests for map creation """
+    maps = glob.glob(os.path.join(MODULE_PATH, 'maps', '*.map'))
+    assert maps, 'Expected maps to be found.'
+    for current_map in maps:
+        this_map = Map(current_map)
+        assert this_map.error == [], 'Map %s should have no errors' % current_map
+        del this_map
diff --git a/diplomacy/utils/convoy_paths.py b/diplomacy/utils/convoy_paths.py
index 5929d51..27b6836 100644
--- a/diplomacy/utils/convoy_paths.py
+++ b/diplomacy/utils/convoy_paths.py
@@ -188,7 +188,10 @@ def add_to_cache(map_name):
             pass
 
     # Getting map MD5 hash
-    map_path = os.path.join(settings.PACKAGE_DIR, 'maps', map_name + '.map')
+    if os.path.exists(map_name):
+        map_path = map_name
+    else:
+        map_path = os.path.join(settings.PACKAGE_DIR, 'maps', map_name + '.map')
     if not os.path.exists(map_path):
         return None
     map_hash = get_file_md5(map_path)
@@ -227,6 +230,7 @@ def get_convoy_paths_cache():
         map_hash = get_file_md5(file_path)
         if map_hash in disk_convoy_paths:
             cache_convoy_paths[map_name] = disk_convoy_paths[map_hash]
+            cache_convoy_paths[file_path] = disk_convoy_paths[map_hash]
 
     # Returning
     return cache_convoy_paths
-- 
cgit v1.2.3