diff --git a/pydtnsim/community.py b/pydtnsim/community.py
index e104338f12210e386fcfa19565bb3cc602dedc29..2e2f3437dab8c59de5c873eb4b8a6e0cb379ed4b 100644
--- a/pydtnsim/community.py
+++ b/pydtnsim/community.py
@@ -15,7 +15,6 @@ __all__ = [
     "KCliqueCommunity",
     "LouvainCommunity",
     "AGKmeansCommunity",
-
     "CommunityNode",
     "KCliqueNode",
     "AGKmeansNode",
@@ -30,7 +29,7 @@ __all__ = [
     "HCBFLouvainNode",
 ]
 __author__ = "Jarrod Pas <j.pas@usask.ca>"
-__author__ = 'Fatemeh zr <faz361@usask.ca>'
+__author__ = "Fatemeh zr <faz361@usask.ca>"
 
 from collections import defaultdict
 from itertools import product
@@ -174,9 +173,7 @@ class Community:
         if node not in graph:
             return 0
 
-        return len(
-            [other for other in node.community if graph.has_edge(node, other)]
-        )
+        return len([other for other in node.community if graph.has_edge(node, other)])
 
     def community_betweenness(self, node_a, node_b):
         """Return community betweenness for 2 nodes."""
@@ -202,9 +199,7 @@ class Community:
             return 0
 
         return sum(
-            graph[node_a][b]["weight"]
-            for b in community_b
-            if graph.has_edge(node_a, b)
+            graph[node_a][b]["weight"] for b in community_b if graph.has_edge(node_a, b)
         )
 
 
@@ -218,9 +213,7 @@ class KCliqueCommunity(Community):
 
     def partition(self):
         """Partition graph by k-clique communities method."""
-        return nx.algorithms.community.k_clique_communities(
-            self.graph_old, k=self.k
-        )
+        return nx.algorithms.community.k_clique_communities(self.graph_old, k=self.k)
 
 
 class AGKmeansCommunity(Community):
@@ -234,12 +227,9 @@ class AGKmeansCommunity(Community):
     def partition(self):
         """Partition graph by AGk-means communities method."""
         graph = nx.Graph()
-        nodes = {
-            id(node): node
-            for node in self.graph_old.nodes()
-        }
+        nodes = {id(node): node for node in self.graph_old.nodes()}
         graph.add_nodes_from(nodes)
-        for node_a, node_b, weight in self.graph_old.edges(data='weight'):
+        for node_a, node_b, weight in self.graph_old.edges(data="weight"):
             graph.add_edge(id(node_a), id(node_b), weight=weight)
 
         partitions = agkmeans(graph, k=self.agk)
@@ -319,9 +309,7 @@ class CommunityNode(Node):
     def in_community_neighbours(self):
         """Return nodes in my community."""
         return [
-            neighbour
-            for neighbour in self.neighbours
-            if neighbour in self.community
+            neighbour for neighbour in self.neighbours if neighbour in self.community
         ]
 
     @property
@@ -333,19 +321,20 @@ class CommunityNode(Node):
             if neighbour not in self.community
         ]
 
+
 def shared_community(context, create):
-        """
-        Check context for shared community and return a shared community.
+    """
+    Check context for shared community and return a shared community.
 
-        Use this for community detection algorithms that must have one instance
-        for a set of nodes.
-        """
-        if "shared-community" in context:
-            return context["shared-community"]
+    Use this for community detection algorithms that must have one instance
+    for a set of nodes.
+    """
+    if "shared-community" in context:
+        return context["shared-community"]
 
-        community = create()
-        context["shared-community"] = community
-        return community
+    community = create()
+    context["shared-community"] = community
+    return community
 
 
 class LouvainNode(CommunityNode):
@@ -396,31 +385,53 @@ class AGKmeansNode(CommunityNode):
         epoch -- how often to recalculate communities
         k -- initial community size
         """
+
         def _create():
-            return AGKmeansCommunity(options['epoch'], options['agk'])
-        options['community'] = shared_community(options['context'], _create)
+            return AGKmeansCommunity(options["epoch"], options["agk"])
+
+        options["community"] = shared_community(options["context"], _create)
         super().__init__(**options)
 
 
 def _decide(node, others, key):
-        """
-        Make a decision on which node to send to best is decided based on key.
+    """
+    Make a decision on which node to send to best is decided based on key.
 
-        If the best is better than node, return best.
-        If node is better than the best, return node.
-        If the best and node are equal, return None.
-        """
-        best = max(others, key=key)
-        best_key = key(best)
-        node_key = key(node)
+    If the best is better than node, return best.
+    If node is better than the best, return node.
+    If the best and node are equal, return None.
+    """
+    best = max(others, key=key)
+    best_key = key(best)
+    node_key = key(node)
+
+    if best_key > node_key:
+        return best
+
+    if best_key < node_key:
+        return node
+
+    return None
+
+def _tie_breaker(node, others, tiedkey, newkey):
+    """
+    Call after decide returns None to determine the best node based on a second key
+    """
+    best = max(others, key=tiedkey)
+    tied_list = [node for node in others if tiedkey(node) == tiedkey(best)]
+
+    new_best = max(tied_list, key=newkey)
+
+    best_key = tiedkey(new_best)
+    node_key = tiedkey(node)
 
-        if best_key > node_key:
-            return best
+    if best_key > node_key:
+        return best
 
-        if best_key < node_key:
-            return node
+    if best_key < node_key:
+        return node
 
-        return None
+    return None
 
 
 class BubbleNode(CommunityNode):
@@ -457,62 +468,83 @@ class BubbleNode(CommunityNode):
 class BubbleKCliqueNode(KCliqueNode, BubbleNode):
     """Bubble node with k-clique community detection."""
 
-    pass
-
 
 class BubbleAGKmeansNode(AGKmeansNode, BubbleNode):
     """Bubble node with k-clique community detection."""
 
-    pass
-
 
 class BubbleLouvainNode(LouvainNode, BubbleNode):
     """Bubble node with louvain community detection."""
 
-    pass
-
 
 class HCBFNode(CommunityNode):
     """Node with Hybrid Community Based forwarding."""
 
     def forward(self, packet):
         """Forward packet with Hybrid Community Based heuristic."""
-        # direct forwarding
+        # direct forwarding to destination node
         forward = super().forward(packet)
         if forward:
             return forward
 
         dest = packet.destination
 
+        # get the packet to the destination community
         if self.community != dest.community:
+            # transmit to the dest community if possible
+            dest_community_neighbours = [
+                neighbour
+                for neighbour in self.out_community_neighbours
+                if neighbour in dest.community
+            ]
+            if dest_community_neighbours:
+                target = _decide(
+                None,
+                dest_community_neighbours,
+                dest._community.unique_interactions,
+            )
+                if not (target is None):
+                    return {target: "dest-community-unique-interactions"}
+
+            # else, transmit to another community with better betweenness with dest
             if self.out_community_neighbours:
                 cbc = partial(self._community.community_betweenness, dest)
                 target = _decide(self, self.out_community_neighbours, cbc)
                 if not (target is None or target is self):
                     return {target: "community-betweenness"}
 
+            # else, within this community, transmit to node with higher nodal contribution with dest
             if self.in_community_neighbours:
                 ncf = partial(self._community.nodal_contribution, dest)
                 target = _decide(self, self.in_community_neighbours, ncf)
                 if not (target is None or target is self):
                     return {target: "nodal-contribution"}
 
-        if self.in_community_neighbours:
+        # the packet is in the destination community, pick the best carrier in this community
+        elif self.in_community_neighbours:
             target = _decide(
                 self,
                 self.in_community_neighbours,
                 self._community.unique_interactions,
             )
-            if not (target is None or target is self):
+
+            if target is self:      # stay here with the highest UI
+                return {}
+
+            if target is not None:  # send to highest UI
                 return {target: "unique-interactions"}
 
-            target = _decide(
-                self,
-                self.in_community_neighbours,
-                self._community.local_popularity,
-            )
-            if not (target is None or target is self):
-                return {target: "local-popularity"}
+            else:                   # use LP to break UI ties
+                target = _tie_breaker(
+                    self,
+                    self.in_community_neighbours,
+                    self._community.unique_interactions,
+                    self._community.local_popularity
+                )
+                if not (target is None or target is self):
+                    return {target: "local-popularity"}
+          
+                
 
         return {}
 
@@ -520,16 +552,10 @@ class HCBFNode(CommunityNode):
 class HCBFKCliqueNode(KCliqueNode, HCBFNode):
     """HCBF node with k-clique community detection."""
 
-    pass
-
 
 class HCBFAGKmeansNode(AGKmeansNode, HCBFNode):
     """HCBF node with k-clique community detection."""
 
-    pass
-
 
 class HCBFLouvainNode(LouvainNode, HCBFNode):
     """HCBF node with louvain community detection."""
-
-    pass