Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
WestCoastSwing
/
RelativePlacement
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Commit
50001c8a
...
50001c8a924e40b23994164b25b2d60b57c38d3c
authored
2016-12-03 02:08:28 +0100
by
Vincent Peybernes
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
#4
Implement Relative Placement
1 parent
287e472b
Pipeline
#5
for
50001c8a
passed
in 33 seconds
Changes
4
Pipelines
1
Builds
1
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
114 additions
and
22 deletions
relative-placement.js
tests/node/GlobalSpec.js
tests/node/RelativePlacementSpec.js
tests/node/results_data.json
relative-placement.js
View file @
50001c8
/**
* Created by Techniv on 30/11/2016.
* @module relative_placement
*/
(
function
(
define
)
{
// TODO define exhaustive module platform
module
.
exports
=
define
();
})(
function
(){
/**
*
*
@name RelativePlacement
* @constructor
* @property {Candidate[]} candidateList
* @property {String[]} votes
* @property {String[]
[]
} votes
* @property {Number} numberOfCandidates
*
*/
...
...
@@ -29,6 +29,7 @@
* @this RelativePlacement
*/
RelativePlacement
.
prototype
.
addCandidate
=
function
addCandidate
(
candidateName
){
if
(
this
.
votes
.
length
)
throw
new
Error
(
"Adding candidates after votes is not permit."
);
if
(
this
.
candidateList
[
candidateName
])
throw
new
Error
(
'"'
+
candidateName
+
'" already exist in candidate list.'
);
this
.
candidateList
[
candidateName
]
=
new
Candidate
(
candidateName
);
};
...
...
@@ -74,23 +75,106 @@
}
};
RelativePlacement
.
prototype
.
addVotes
=
function
()
{};
RelativePlacement
.
prototype
.
getResult
=
function
()
{};
RelativePlacement
.
prototype
.
getResult
=
function
()
{
return
relativePlacement
(
this
.
votes
,
this
.
candidateList
);
};
/**
*
* @param name
* @param
{String}
name
* @constructor
* @property {String} name
* @property {Number[]} votes
* @property {Number[]} placements
* @property {Number[]} cumulativePlacement
*/
function
Candidate
(
name
)
{
Object
.
defineProperties
(
this
,
{
name
:
{
value
:
name
,
enumerable
:
true
},
votes
:
{
value
:[],
enumerable
:
true
},
placements
:
{
value
:[],
enumerable
:
true
,
writable
:
true
}
name
:
{
value
:
name
,
enumerable
:
true
},
votes
:
{
value
:[],
enumerable
:
true
},
placements
:
{
value
:[],
enumerable
:
true
,
writable
:
true
},
cumulativePlacement
:
{
value
:[],
enumerable
:
true
,
writable
:
true
}
});
}
/**
* @name relativePlacement
* @memberOf RelativePlacement
* @static
* @param {String[][]} votes
* @param {Object<String,Candidate>} [candidates]
* @returns {String[]}
*/
function
relativePlacement
(
votes
,
candidates
){
if
(
votes
.
length
<=
1
)
return
votes
[
0
];
// Prepare candidate list if not pass
var
init
=
false
,
majority
,
result
,
candidateNames
;
if
(
!
candidates
)
{
candidates
=
{};
init
=
true
;
}
candidateNames
=
votes
[
0
];
majority
=
Math
.
floor
(
votes
.
length
/
2
)
+
1
;
result
=
[];
candidateNames
.
forEach
((
name
)
=>
{
if
(
init
)
candidates
[
name
]
=
new
Candidate
(
name
);
candidates
[
name
].
placements
[
candidateNames
.
length
-
1
]
=
0
;
candidates
[
name
].
placements
.
fill
(
0
,
0
,
candidateNames
.
length
-
1
);
candidates
[
name
].
cumulativePlacement
[
candidateNames
.
length
-
1
]
=
0
;
candidates
[
name
].
cumulativePlacement
.
fill
(
0
,
0
,
candidateNames
.
length
-
1
);
});
// Assign votes
votes
.
forEach
((
vote
,
num
)
=>
{
vote
.
forEach
((
name
,
place
)
=>
{
var
candidate
=
candidates
[
name
];
candidate
.
votes
[
num
]
=
place
;
for
(
let
i
=
place
;
i
<
candidate
.
placements
.
length
;
i
++
){
candidate
.
placements
[
i
]
++
;
candidate
.
cumulativePlacement
[
i
]
+=
place
+
1
;
}
});
});
// Search placement
var
cursor
=
0
,
nextPlace
=
0
,
proposed
=
[];
while
(
result
.
length
<
candidateNames
.
length
&&
cursor
<
candidateNames
.
length
){
// Search majority
candidateNames
.
forEach
(
name
=>
{
if
(
result
.
indexOf
(
name
)
!=
-
1
)
return
;
var
candidate
=
candidates
[
name
];
if
(
candidate
.
placements
[
cursor
]
>=
majority
)
proposed
.
push
(
candidate
);
});
if
(
proposed
.
length
){
proposed
.
sort
((
a
,
b
)
=>
{
var
sortCursor
=
cursor
;
while
(
sortCursor
<
candidateNames
.
length
){
if
(
a
.
placements
[
sortCursor
]
!=
b
.
placements
[
sortCursor
])
return
b
.
placements
[
sortCursor
]
-
a
.
placements
[
sortCursor
];
if
(
a
.
cumulativePlacement
[
sortCursor
]
!=
b
.
cumulativePlacement
[
sortCursor
])
return
a
.
cumulativePlacement
[
sortCursor
]
-
b
.
cumulativePlacement
[
sortCursor
];
sortCursor
++
;
}
return
0
;
});
result
=
result
.
concat
(
proposed
.
map
(
candidate
=>
candidate
.
name
));
cursor
=
result
.
length
;
proposed
.
splice
(
0
);
continue
;
}
cursor
++
;
}
return
result
;
}
RelativePlacement
.
relativePlacement
=
relativePlacement
;
return
RelativePlacement
;
});
\ No newline at end of file
...
...
tests/node/GlobalSpec.js
View file @
50001c8
...
...
@@ -33,7 +33,8 @@ describe('RelativePlacement global', () => {
assert
.
deepEqual
({
name
:
'foo'
,
votes
:[],
placements
:
[]
placements
:
[],
cumulativePlacement
:
[]
},
election
.
candidateList
[
'foo'
]);
});
...
...
@@ -45,12 +46,14 @@ describe('RelativePlacement global', () => {
assert
.
deepEqual
({
name
:
'foo'
,
votes
:[],
placements
:
[]
placements
:
[],
cumulativePlacement
:
[]
},
election
.
candidateList
[
'foo'
]);
assert
.
deepEqual
({
name
:
'bar'
,
votes
:[],
placements
:
[]
placements
:
[],
cumulativePlacement
:
[]
},
election
.
candidateList
[
'bar'
]);
});
...
...
tests/node/RelativePlacementSpec.js
View file @
50001c8
...
...
@@ -2,16 +2,12 @@
* Created by Techniv on 02/12/2016.
*/
var
assert
=
require
(
'assert'
);
var
RelativePlacement
=
require
(
'../../relative-placement'
);
/** @type RelativePlacement.relativePlacement */
var
relativePlacement
=
require
(
'../../relative-placement'
).
relativePlacement
;
/** @var {TestData[]} */
var
testDataList
=
require
(
'./results_data.json'
);
describe
(
'RelativePlacement algo'
,
()
=>
{
var
election
;
beforeEach
(()
=>
{
election
=
new
RelativePlacement
();
});
describe
(
'Process result data'
,()
=>
{
...
...
@@ -22,14 +18,11 @@ describe('RelativePlacement algo', () => {
*/
(
testData
,
id
)
=>
{
it
(
'#'
+
id
+
': '
+
(
testData
.
comment
||
''
),
()
=>
{
election
.
addCandidates
(
testData
.
result
.
concat
().
sort
(()
=>
Math
.
random
()
-
Math
.
random
()));
var
votes
=
compileVotes
(
testData
);
votes
.
forEach
((
vote
)
=>
{
election
.
addVote
(
vote
);
});
var
result
=
relativePlacement
(
votes
);
assert
.
deepEqual
(
election
.
getResult
()
,
testData
.
result
);
assert
.
deepEqual
(
result
,
testData
.
result
);
});
}
);
...
...
tests/node/results_data.json
View file @
50001c8
...
...
@@ -9,6 +9,18 @@
"result"
:
[
"A"
,
"B"
,
"C"
]
},
{
"comment"
:
"boogiebythebay.org study case"
,
"votes"
:{
"Couple 1"
:[
1
,
1
,
3
,
2
,
3
],
"Couple 2"
:[
6
,
5
,
4
,
1
,
2
],
"Couple 3"
:[
2
,
4
,
1
,
5
,
5
],
"Couple 4"
:[
4
,
2
,
5
,
6
,
6
],
"Couple 5"
:[
5
,
6
,
2
,
3
,
4
],
"Couple 6"
:[
3
,
3
,
6
,
4
,
1
]
},
"result"
:
[
"Couple 1"
,
"Couple 6"
,
"Couple 3"
,
"Couple 2"
,
"Couple 5"
,
"Couple 4"
]
},
{
"comment"
:
"Novice Strictly final"
,
"votes"
:{
"320"
:
[
1
,
1
,
1
,
1
,
1
],
...
...
Please
register
or
sign in
to post a comment