anchor.diff:            return true;
           } else {
             var playedHasExit = CardUtil.exits(card.type, playedDir).contains(dir);
  -          var neighborHasExit = CardUtil.exits(boardMap[neighborLoc].card.type, 
  +          var neighborHasExit = CardUtil.exits(boardMap[neighborLoc].card.type,
               boardMap[neighborLoc].dir).contains(CardUtil.opposite(dir));
  -          
  +
             //return true if both have the exit, or neither have it
             log("Played type: ${card.type} Played dir: ${playedDir}" +
               "Neighbor type: ${boardMap[neighborLoc].card.type} Neighbor dir: ${boardMap[neighborLoc].dir}");
  
positive.code:     if(!fringe.contains(loc)) return false;
  
      //Test each side of the played card to see if it fits
      return CardUtil.allDirections.every( 
        (CardDirection dir) {
          BoardLoc neighborLoc = loc.neighborLoc(dir);
          if (!boardMap.keys.contains(neighborLoc)) {
  
negative.code:           return playedHasExit == neighborHasExit;
          }
        });
  
    }
  
    bool playSabotage(BoardLoc loc){
      if(isLegalSabotage(loc)){
        boardMap.remove(loc);
        fringe.add(loc);
        //TODO remove fringe locations that are now unreachable
        return true;
      } else {
        return false;
  