Identifying the Loser from a Game of Word Chain
Rule of the Game
Certain number of players present a word in turns, that begins with the letter of the last word’s ending. For instance, if the last word was apple, the current player needs to present a word that starts with e. No word can be presented twice in the same game.
Therefore the loser is a. whose word presented didn't begin with the last word's ending(let's call this following the previous word)
or b. whose word has already been presented in the game
.
In this problem, the inputs are the number of players and an array of words they are going to present.
Example
3, [tank, kick, know, wheel, land, dream, mother, robot, tank]
5, [hello, observe, effect, take, either, recognize, encourage, ensure, establish, hang, gather, refer, reference, estimate, executive]
Create a function that returns an answer array of the loser, and in how many turns the game ended. If there is no loser with the array provided, return [0, 0]
Obstacles
1. End the game if requirements are met
Loop the array, until below
1. If the word matches any of the previous word, end game.
2. If the word doesn't follow the previous word, end game.
1. Solved by creating array of called words and comparing the current one
let called = [];
for(let i = 0; i < words.length; i++){
if(called.includes(words[i])){
break
}
called.push(words[i])
}
2.
for(let i = 0; i < words.length; i++){
if(i != words.length -1){
if(words[i].charAt(words[i].length - 1) != words[i + 1].charAt(0)){
break;
}
}
}
2. Calculating the loser and turn
I couldn’t finish the test in time because I struggled with calculating the correct loser and turn.
I thought since the index was 1 smaller than the actual turn, I had to add 1 before dividing and getting the remainder.
However I later found out that by doing this, the outcome of the division needed to be broken down into cases of when the remainder is 0 (in other words the player n) and when not.
For Case 1.
if((i + 1) % n == 0){
answer[0] = n;
answer[1] = (i + 1) / n;
} else {
answer[0] = (i + 1) % n;
answer[1] = parseInt((i + 1) / n) + 1;
}
For Case 2.
if((i + 2) % n == 0){
answer[0] = n;
answer[1] = (i + 2) / n;
} else {
answer[0] = (i + 2) % n;
answer[1] = parseInt((i + 2) / n) + 1;
}
Cleaning the Code
After submitting the code, I figured out that my code was very repetitve and inefficient. So with the help of other people’s submissions, I refactored my code, with almost the same logical flow.
The Final Code
function solution(n, words) {
let answer = [0, 0];
for(let i = 1; i < words.length; i++){
if(words.indexOf(words[i]) != i
|| words[i - 1].charAt(words[i - 1].length - 1) != words[i].charAt(0)){
answer = [(i % n) + 1, parseInt(i / n) + 1];
break;
}
}
return answer;
}
First thing I did was to merge the two different condtions into one with the or operator(||
). In order to do this, the indexing needed to match, unlike my original code, where it checked for i
th word for condition 1 and i+1
th for the second condition.
While fixing this, the fact that the first word will never be repeating, since there is no previous word, came into my mind. So the initial value of index was changed to 1, and the i
th word is being checked for both conditions.
Second thing to be fixed was the calculation of the player and the number of turn. I first changed this to a ternary operator. However, with further consideration and reading other people’s submission, the problem could’ve been solved much more elegantly.
If the caculation began with dividng the i with n, and adding the 1 later on, the possible outcome for the player never was 0, but only 1 through n. So this can be reduced to a single case, unlike my original code.