From f73b4688844d2aec6a92474d7ccb8aae793d14ad Mon Sep 17 00:00:00 2001
From: Lars-Dominik Braun <lars@6xq.net>
Date: Sat, 5 Oct 2019 09:06:23 +0200
Subject: optimize: Support wildcard pins

---
 gen.sh            |  2 +-
 lulua/optimize.py | 30 +++++++++++++++++++++++++++---
 2 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/gen.sh b/gen.sh
index 0d7a066..6e984c3 100755
--- a/gen.sh
+++ b/gen.sh
@@ -14,7 +14,7 @@ docdir=doc
 wikiextractor=3rdparty/wikiextractor/WikiExtractor.py
 optrounds=100000
 # pin layers, keep hand-optimized numbers, keep top row free
-optpins=0;1;2;0,Bl1;0,Bl2;0,Bl3;0,Bl4;0,Bl5;0,Bl6;0,Bl7;0,Br6;0,Br5;0,Br4;0,Br3;0,Br2;0,Br1;3,Cl4;3,Cl3;3,Cl2;3,Cl1;3,Dl4;3,Dl3;3,Dl2;3,Dl1;3,El5;3,El4;3,El3;3,El2;3,Dl5;3,Cl5;3,El6
+optpins=0;1;2;0,B*;3,*
 optmodel=mod01
 
 ### pools ###
diff --git a/lulua/optimize.py b/lulua/optimize.py
index 281f0ab..db5807b 100644
--- a/lulua/optimize.py
+++ b/lulua/optimize.py
@@ -19,6 +19,7 @@
 # THE SOFTWARE.
 
 import pickle, sys, random, time, logging, argparse
+from fnmatch import fnmatch
 from copy import deepcopy
 from typing import List, Tuple, Optional, Text, FrozenSet
 from abc import abstractmethod
@@ -237,7 +238,20 @@ class LayoutOptimizer (Annealer):
         return super().run (steps)
 
 def parsePin (s: Text):
-    """ Parse --pin argument """
+    """
+    Parse --pin argument
+
+    Synax: <layer>[;<button>]
+    Examples:
+    0
+    (keeps all buttons on the first layer on this layer)
+    1;Bl1
+    (keeps Bl1 on layer 1 in place)
+    2;B*
+    (pins all buttons matching B* on layer 2 in place)
+
+    (Expansion is performed when the keyboard is known)
+    """
     pins = []
     for p in s.split (';'):
         p = p.split (',', 1)
@@ -289,13 +303,23 @@ def optimize ():
             # mutate modifier key positions.
             # XXX: only works for single-button-modifier
             if not isinstance (k, LetterButton) or layout.isModifier (frozenset ([k])):
-                logging.info (f'ignoring {k}')
+                logging.info (f'not mutating {k}')
                 continue
             keys.append ((i, k))
             values.append ((i, k))
     buttonMap = dict (zip (keys, values))
 
-    pins = [(x, keyboard[y] if y else None) for x, y in args.pin]
+    pins = []
+    for layer, match in args.pin:
+        # special pin, which just keeps buttons on the same layer
+        if match is None:
+            pins.append ((layer, match))
+            continue
+        # wildcard matches
+        for k in keyboard.keys ():
+            if fnmatch (k.name, match):
+                pins.append ((layer, k))
+                logging.info (f'pinning layer {layer} {k}')
 
     opt = LayoutOptimizer (buttonMap, triads, layout, pins, writer, model=models[args.model])
     if args.randomize:
-- 
cgit v1.2.3