static void Main(string[] args) { NodeService nodeService = NodeService.Instance; List <Node> nodes = nodeService.initializeNodes(20, 4); CommunitiesCalculationClient calculationClient = new CommunitiesCalculationClient(new NormalizeCommunities()); RoomsStruct roomsStruct = calculationClient.calculate(nodes, 4); foreach (Room room in roomsStruct.rooms) { Console.WriteLine($" {room.nodes.Count}"); } Console.WriteLine($"legnth of unassigned nodes: {roomsStruct.unassignedNodes.Length}"); }
public RoomsStruct Calculate(List <Node> nodes, int nodesPerRoom) { Random random = new Random(); List <Node> unassignedNodes = new List <Node>(nodes); List <Node> nodesThatWereAdded = new List <Node>(); int roomsAmount = (int)Math.Ceiling(nodes.Count / (decimal)nodesPerRoom); //initializes the rooms List <Room> rooms = CommunitiesCalculationInterface.initRooms(roomsAmount); List <Room> fullRooms = new List <Room>(); bool hadMutualConnection = true; int iterationCounter = 0; while (unassignedNodes.Count != 0 && iterationCounter < nodesPerRoom * 2) { iterationCounter++; //sort the rooms from shortest in length to longest rooms.Sort(new Comparison <Room>((x, y) => { return(x.nodes.Count > y.nodes.Count ? 1 : x.nodes.Count < y.nodes.Count ? -1 : 0); })); foreach (Room room in rooms) { // if the room is marked as problematic, continue if (room.isProblematic) { continue; } //the room hit the maximum nodes it should contain if (room.nodes.Count == nodesPerRoom) { fullRooms.Add(room); continue; } // the room is empty else if (room.nodes.Count == 0) { // we know in the last run we found a mutual connection between nodes, in that case, perhaps we can find another. if (hadMutualConnection) { // look for a mutual connection Node[] connectedNodes = findMutualConnection(unassignedNodes); // a mutualConnection is found, move the nodes to the room if (connectedNodes != null) { moveNodeFromListToRoom(connectedNodes[0], ref unassignedNodes, room); moveNodeFromListToRoom(connectedNodes[1], ref unassignedNodes, room); } else { hadMutualConnection = false; // move a random unassigned node to the room moveNodeFromListToRoom(unassignedNodes[random.Next(unassignedNodes.Count)], ref unassignedNodes, room); } } // we couldn't find a mutual connection earlier, so we shouldn't waste time looking for one else { // move a random unassigned node to the room moveNodeFromListToRoom(unassignedNodes[random.Next(unassignedNodes.Count)], ref unassignedNodes, room); } } // the room contains one or more nodes, but isn't full else { if (hadMutualConnection) { // the room has more than 1 empty slot if (room.nodes.Count < nodesPerRoom - 1) { // look for a mutual connection Node[] connectedNodes = findMutualConnection(unassignedNodes); // a mutualConnection is found, move the nodes to the room if (connectedNodes != null) { moveNodeFromListToRoom(connectedNodes[0], ref unassignedNodes, room); moveNodeFromListToRoom(connectedNodes[1], ref unassignedNodes, room); // we closed the room with a mutual connection, therefore we keep that in mind, so we won't manipulate it's last member if (room.nodes.Count == nodesPerRoom) { room.closedWithMutualConnection = true; } continue; } else { hadMutualConnection = false; } } } // there is no mutual connection or the room has only 1 empty slot, try to add an unassignedNode to the room bool addedNode = false; foreach (Node node in unassignedNodes) { if (isRoomGoodForNode(node, room)) { moveNodeFromListToRoom(node, ref unassignedNodes, room); addedNode = true; break; } } if (!addedNode) { room.isProblematic = true; } } } // we didn't remove them earlier, so we remove them now foreach (Room fullRoom in fullRooms) { rooms.Remove(fullRoom); } } // if some nodes are left unassigned, they are problematic and we should check if they can change a spot with another node that exists inside a room. the node that the problematic node is going to swtich places with should be the last node of the room, and only if the room wasn't closed with a mutual connection. if (unassignedNodes.Count != 0) { Console.WriteLine($"starting problematic nodes iteration with: {unassignedNodes.Count} problematic nodes"); foreach (Node problematicNode in unassignedNodes) { // because we already tried adding the nodes to each room, we know have to check only in the fullrooms List <Room> roomsWithInterestingNodes = findRoomsWithConnection(problematicNode, fullRooms, nodesPerRoom); foreach (Room room in roomsWithInterestingNodes) { // if the current room was closed with a mutual connection, we shouldn't move it's last node. if (room.closedWithMutualConnection) { continue; } Node lastNodeOfRoom = room.nodes.Last(); // we are now checking if we can find a room to add the lastNodeOfRoom to, we are iterating over the rooms array, these rooms are not full. List <Room> lastNodeRooms = findRoomsWithConnection(lastNodeOfRoom, rooms, nodesPerRoom); // we found a room to add the lastNodeOfRoom to! if (lastNodeRooms.Count != 0) { // add the nodes to their new rooms moveNodeFromRoomToRoom(lastNodeOfRoom, room, lastNodeRooms[0]); room.nodes.Add(problematicNode); nodesThatWereAdded.Add(problematicNode); break; } } } foreach (Node node in nodesThatWereAdded) { // remove all the nodes that were added now, after the iteration is complete. unassignedNodes.Remove(node); } } RoomsStruct roomsStruct = new RoomsStruct(); roomsStruct.unassignedNodes = unassignedNodes.ToArray(); roomsStruct.rooms = rooms.Concat(fullRooms).ToArray(); return(roomsStruct); }