unit test on connect is working, lets start the worst ....
authorDavid MAECHLER <d.maechler@thecodingmachine.com>
Thu, 9 Apr 2020 21:26:19 +0000 (23:26 +0200)
committerDavid MAECHLER <d.maechler@thecodingmachine.com>
Thu, 9 Apr 2020 21:26:19 +0000 (23:26 +0200)
back/src/Model/Group.ts
back/src/Model/UserInterface.ts
back/src/Model/World.ts
back/tests/WorldTest.ts

index ed57e47358109f1ed73fce4ecf5504cbb1fbf1c3..38b912577135f64709d0c92d971a29b8647cc27e 100644 (file)
@@ -1,15 +1,26 @@
 import {MessageUserPosition} from "./Websocket/MessageUserPosition";
 import { World } from "./World";
+import { UserInterface } from "./UserInterface";
+
 export class Group {
     static readonly MAX_PER_GROUP = 4;
     
-    users: MessageUserPosition[];
+    private users: UserInterface[];
+    private connectCallback: (user1: string, user2: string) => void;
+    private disconnectCallback: (user1: string, user2: string) => void;
+
 
-    constructor(users: MessageUserPosition[]) {
-        this.users = users;
+    constructor(users: UserInterface[], connectCallback: (user1: string, user2: string) => void, disconnectCallback: (user1: string, user2: string) => void) {
+        this.users = [];
+        this.connectCallback = connectCallback;
+        this.disconnectCallback = disconnectCallback;
+        
+        users.forEach((user: UserInterface) => {
+            this.join(user);
+        });
     }
 
-    getUsers(): MessageUserPosition[] {
+    getUsers(): UserInterface[] {
         return this.users;
     }
 
@@ -17,12 +28,22 @@ export class Group {
         return this.users.length >= Group.MAX_PER_GROUP;
     }
 
-    isPartOfGroup(user: MessageUserPosition): boolean
+    join(user: UserInterface): void
+    {
+        // Broadcast on the right event
+        this.users.forEach((groupUser: UserInterface) => {
+            this.connectCallback(user.id, groupUser.id);
+        });
+        this.users.push(user);
+        user.group = this;
+    }
+
+    isPartOfGroup(user: UserInterface): boolean
     {
         return this.users.indexOf(user) !== -1;
     }
 
-    isStillIn(user: MessageUserPosition): boolean
+    isStillIn(user: UserInterface): boolean
     {
         if(!this.isPartOfGroup(user)) {
             return false;
@@ -30,7 +51,7 @@ export class Group {
         let stillIn = true;
         for(let i = 0; i <= this.users.length; i++) {
             let userInGroup = this.users[i];
-            let distance = World.computeDistance(user.position, userInGroup.position);
+            let distance = World.computeDistance(user, userInGroup);
             if(distance > World.MIN_DISTANCE) {
                 stillIn = false;
                 break;
@@ -39,7 +60,7 @@ export class Group {
         return stillIn;
     }
 
-    removeFromGroup(users: MessageUserPosition[]): void
+    removeFromGroup(users: UserInterface[]): void
     {
         for(let i = 0; i < users.length; i++) {
             let user = users[i];
index c75d3f3aec69b7b68ed0ee6ca7c69d73c4a4a061..743f8b4d4ec00b490f510ef8bcad33a9fa6bc674 100644 (file)
@@ -1,7 +1,8 @@
 import { Group } from "./Group";
 import { PointInterface } from "./Websocket/PointInterface";
 
-export interface Userinteface {
-    group: Group,
-    pointInterface: PointInterface
+export interface UserInterface {
+    id: string,
+    group?: Group,
+    position: PointInterface
 }
\ No newline at end of file
index dd4ec3a924c8626b38c273584ae67b1256cdeb91..804a176b40843e6dd9fed5bed5ca23cfbb9a6045 100644 (file)
@@ -2,12 +2,13 @@ import {MessageUserPosition, Point} from "./Websocket/MessageUserPosition";
 import {PointInterface} from "./Websocket/PointInterface";
 import {Group} from "./Group";
 import {Distance} from "./Distance";
+import {UserInterface} from "./UserInterface";
 
 export class World {
-    static readonly MIN_DISTANCE = 12;
+    static readonly MIN_DISTANCE = 160;
 
     // Users, sorted by ID
-    private users: Map<string, PointInterface>;
+    private users: Map<string, UserInterface>;
     private groups: Group[];
 
     private connectCallback: (user1: string, user2: string) => void;
@@ -15,22 +16,96 @@ export class World {
 
     constructor(connectCallback: (user1: string, user2: string) => void, disconnectCallback: (user1: string, user2: string) => void) 
     {
-        this.users = new Map<string, PointInterface>();
+        this.users = new Map<string, UserInterface>();
         this.groups = [];
         this.connectCallback = connectCallback;
         this.disconnectCallback = disconnectCallback;
     }    
 
     public join(userPosition: MessageUserPosition): void {
-        this.users.set(userPosition.userId, userPosition.position);
+        this.users.set(userPosition.userId, {
+            id: userPosition.userId,
+            position: userPosition.position
+        });
     }
 
     public updatePosition(userPosition: MessageUserPosition): void {
         let context = this;
+        let user = this.users.get(userPosition.userId);
+        if(typeof user === 'undefined') {
+            return;
+        }
+
+        user.position.x = userPosition.position.x;
+        user.position.y = userPosition.position.y;
+
+        if (typeof user.group === 'undefined') {
+            // If the user is not part of a group:
+            //  should he join a group?
+            let closestUser: UserInterface|null = this.searchClosestAvailableUser(user);
+
+            if (closestUser !== null) {
+                // Is the closest user part of a group?
+                if (typeof closestUser.group === 'undefined') {
+                    let group: Group = new Group([
+                        user,
+                        closestUser
+                    ], this.connectCallback, this.disconnectCallback);
+                } else {
+                    closestUser.group.join(user);
+                }
+            }
+            
+        }
+       // TODO : vérifier qu'ils ne sont pas déja dans un groupe plein 
+    }
+
+    /**
+     * Looks for the closest user that is:
+     * - close enough (distance <= MIN_DISTANCE)
+     * - not in a group OR in a group that is not full
+     */
+    private searchClosestAvailableUser(user: UserInterface): UserInterface|null
+    {
+/*
+        let sortedUsersByDistance: UserInteface[] = Array.from(this.users.values()).sort((user1: UserInteface, user2: UserInteface): number => {
+            let distance1 = World.computeDistance(user, user1);
+            let distance2 = World.computeDistance(user, user2);
+            return distance1 - distance2;
+        });
+
+        // The first element should be the current user (distance 0). Let's remove it.
+        if (sortedUsersByDistance[0] === user) {
+            sortedUsersByDistance.shift();
+        }
+
+        for(let i = 0; i < sortedUsersByDistance.length; i++) {
+            let currentUser = sortedUsersByDistance[i];
+            let distance = World.computeDistance(currentUser, user);
+            if(distance > World.MIN_DISTANCE) {
+                return;
+            }
+        }
+*/
         let usersToBeGroupedWith: Distance[] = [];
-        this.users.forEach(function(user, userId) {
-            let distance = World.computeDistance(userPosition.position, user); // compute distance between peers.
-            if(distance <= World.MIN_DISTANCE) {
+        let minimumDistanceFound: number = World.MIN_DISTANCE;
+        let matchingUser: UserInterface | null = null;
+        this.users.forEach(function(currentUser, userId) {
+            if(currentUser === user) {
+                return;
+            }
+
+            let distance = World.computeDistance(user, currentUser); // compute distance between peers.
+            
+            if(distance <= minimumDistanceFound) {
+
+                if (typeof currentUser.group === 'undefined' || !currentUser.group.isFull()) {
+                    // We found a user we can bind to.
+                    minimumDistanceFound = distance;
+                    matchingUser = currentUser;
+                    return;
+                }
+            /*
                 if(context.groups.length > 0) {
                     
                     context.groups.forEach(group => {
@@ -52,28 +127,27 @@ export class World {
 
                 } else {
                     // Aucun groupe n'existe donc je stock les users assez proches de moi
-                    let dist = {
+                    let dist: Distance = {
                         distance: distance,
                         first: userPosition,
                         second: user // TODO: convertir en messageUserPosition
                     }
                     usersToBeGroupedWith.push(dist);
                 }
+            */
             }
         
-        }, context);
-
-        usersToBeGroupedWith.sort(World.compareDistances);
-       // TODO : vérifier qu'ils ne sont pas déja dans un groupe plein 
+        }, this.users);
 
+        return matchingUser;
     }
 
-    public static computeDistance(user1: PointInterface, user2: PointInterface): number
+    public static computeDistance(user1: UserInterface, user2: UserInterface): number
     {
-        return Math.sqrt(Math.pow(user2.x - user1.x, 2) + Math.pow(user2.y - user1.y, 2));
+        return Math.sqrt(Math.pow(user2.position.x - user1.position.x, 2) + Math.pow(user2.position.y - user1.position.y, 2));
     }
 
-    getDistancesBetweenGroupUsers(group: Group): Distance[]
+    /*getDistancesBetweenGroupUsers(group: Group): Distance[]
     {
         let i = 0;
         let users = group.getUsers();
@@ -82,7 +156,7 @@ export class World {
             users.forEach(function(user2, key2) {
                 if(key1 < key2) {
                     distances[i] = {
-                        distance: World.computeDistance(user1.position, user2.position),
+                        distance: World.computeDistance(user1, user2),
                         first: user1,
                         second: user2
                     };
@@ -132,5 +206,5 @@ export class World {
             return 1;
         }
         return 0;
-    }
+    }*/
 }
\ No newline at end of file
index a0cced43f235aa0fbc5f1ec6e1e016867ae94c8b..1f5affc8ed9184a9c92bb05c475fef0d4dcb6c36 100644 (file)
@@ -29,15 +29,31 @@ describe("World", () => {
             position: new Point(500, 100)
         }));
 
+        world.updatePosition(new MessageUserPosition({
+            userId: "bar",
+            roomId: 1,
+            position: new Point(261, 100)
+        }));
+
+        expect(connectCalled).toBe(false);
+
         world.updatePosition(new MessageUserPosition({
             userId: "bar",
             roomId: 1,
             position: new Point(101, 100)
         }));
 
-        //expect(connectCalled).toBe(true);
+        expect(connectCalled).toBe(true);
 
-    }),
+        connectCalled = false;
+        world.updatePosition(new MessageUserPosition({
+            userId: "bar",
+            roomId: 1,
+            position: new Point(102, 100)
+        }));
+        expect(connectCalled).toBe(false);
+    });
+    /** 
     it('Should return the distances between all users', () => {
         let connectCalled: boolean = false;
         let connect = (user1: string, user2: string): void => {
@@ -83,4 +99,5 @@ describe("World", () => {
 
         //expect(distances).toBe([]);
     })
+    **/
 })
\ No newline at end of file