Skip to content
Snippets Groups Projects
Commit d13b0dae authored by Ben Eltschig's avatar Ben Eltschig
Browse files

Merge branch 'some-changes' into 'custom-server'

Some changes

See merge request !4
parents ee35acb2 6a25ea2c
Branches
1 merge request!4Some changes
...@@ -29,6 +29,7 @@ export class SkribblWord extends HTMLElement { ...@@ -29,6 +29,7 @@ export class SkribblWord extends HTMLElement {
/** @type {AttachedLink} */ /** @type {AttachedLink} */
this._link = this.shadowRoot.querySelector("attached-link"); this._link = this.shadowRoot.querySelector("attached-link");
this._description = new LatexJS(description,{delay:true,macros}); this._description = new LatexJS(description,{delay:true,macros});
//btw it shows me an error here, but neither do i understand, why its there, what the error means, what macros is doing nor what i could do about it
this.shadowRoot.appendChild(this._description); this.shadowRoot.appendChild(this._description);
this.word = word; this.word = word;
this.synonyms = synonyms; this.synonyms = synonyms;
......
...@@ -270,7 +270,7 @@ export default class SkribblServer { ...@@ -270,7 +270,7 @@ export default class SkribblServer {
if (this._hasGameStarted){ if (this._hasGameStarted){
if (player.guessedWord||playerIndex==this._drawingPlayer){ if (player.guessedWord||playerIndex==this._drawingPlayer){
// TODO let people who already know the word send ghost messages to others who already know it too // TODO let people who already know the word send ghost messages to others who already know it too
}else if (typeof this._word=="string"&&SkribblServer._isCorrect(word,this._word)){ }else if (typeof this._word=="string"&&SkribblWords._isCorrect(word,this._word)){
player.guessedWord = true; player.guessedWord = true;
player.guessedIndex = Math.max(...this._clients.map(client=>client.guessedIndex))+1; player.guessedIndex = Math.max(...this._clients.map(client=>client.guessedIndex))+1;
this._clients.forEach((client,index)=>{ this._clients.forEach((client,index)=>{
...@@ -283,7 +283,7 @@ export default class SkribblServer { ...@@ -283,7 +283,7 @@ export default class SkribblServer {
this._allGuessedPromise.checkCondition(); this._allGuessedPromise.checkCondition();
}else{ }else{
this._clients.forEach((client,index)=>{ this._clients.forEach((client,index)=>{
let close = typeof this._word=="string"?SkribblServer._isClose(word,this._word):false; let close = typeof this._word=="string"?SkribblWords._isClose(word,this._word):false;
if (index==playerIndex){ if (index==playerIndex){
client.dataChannel.send({action:"guessedWord",player:playerIndex,correct:false,word,close}); client.dataChannel.send({action:"guessedWord",player:playerIndex,correct:false,word,close});
}else{ }else{
...@@ -318,87 +318,4 @@ export default class SkribblServer { ...@@ -318,87 +318,4 @@ export default class SkribblServer {
}); });
return points; return points;
} }
/**
* Checks whether a given guess is close to the given word. A guess counts as close, if one letter is wrong,
* two letters are swapped or the guess has one letter too much or too little.
* @param {string} guess
* @param {string} word
*/
static _isClose(guess,word) {
guess = guess.toLowerCase().replace(/-/g," ");
word = word.toLowerCase().replace(/-/g," ");
const wordArray = Array.from(word);
const guessArray = Array.from(guess);
//if equal
if (guess == word) {
return true;
}
//either one letter wrong or two letters swapped
if (guess.length == word.length) {
//Counts the mistakes and their position
let errorCounter = 0;
let errorPos = 0;
for (var i = 0; i < wordArray.length; i++) {
if (wordArray[i] != guessArray[i]) {
if (errorCounter == 0) {
errorPos = i;
} if (errorCounter == 1) { //if a second mistake occurs, either the letters are swapped or it is not correct
//but there could be a third mistake, so in the case of a swap, true is not directly returned.
if ((wordArray[i] != guessArray[errorPos]) || (wordArray[errorPos] != guessArray[i])) {
return false;
}
} if (errorCounter >= 2) { //with two or more mistakes, the word is not close
return false;
}
errorCounter++;
}
}
//if it hasnt returned false by now, the guess is close
return true;
}
//if one letter too much
if (guess.length - 1 == word.length) {
let errorCounter = 0; //also the offset
for (var i = 0; i < wordArray.length; i++) {
if (wordArray[i] != guessArray[i + errorCounter]) {
errorCounter++;
if (errorCounter >= 2) {
return false;
}
}
}
return true;
}
//if one letter too little
if (guess.length + 1 == word.length) {
let errorCounter = 0; //also the offset
for (var i = 0; i < guessArray.length; i++) {
if (wordArray[i + errorCounter] != guessArray[i]) {
errorCounter++;
if (errorCounter >= 2) {
return false;
}
}
}
return true;
}
return false;
}
/**
* Checks if the guess is correct. It is not case-sensitive.
* @param {string} guess
* @param {string} word
*/
static _isCorrect(guess, word) {
guess = guess.toLowerCase().replace(/-/g," ");
word = word.toLowerCase().replace(/-/g," ");
return guess==word;
}
} }
\ No newline at end of file
...@@ -47,4 +47,85 @@ export default class SkribblWords { ...@@ -47,4 +47,85 @@ export default class SkribblWords {
return (await json).macros; return (await json).macros;
})(); })();
} }
/**
* Checks whether a given guess is close to the given word. A guess counts as close, if one letter is wrong,
* two letters are swapped or the guess has one letter too much or too little.
* @param {string} guess
* @param {string} word
*/
static _isClose(guess,word) {
guess = guess.toLowerCase().replace(/-/g," ").replace(/'/g,'').normalize("NFD").replace(/[\u0300-\u0307\u0309-\u036f]/g, "");
word = word.toLowerCase().replace(/-/g," ").replace(/'/g,'').normalize("NFD").replace(/[\u0300-\u0307\u0309-\u036f]/g, "");
//if equal
if (guess == word) {
return true;
}
//either one letter wrong or two letters swapped
if (guess.length == word.length) {
//Counts the mistakes and their position
let errorCounter = 0;
let errorPos = 0;
for (var i = 0; i < word.length; i++) {
if (word[i] != guess[i]) {
if (errorCounter == 0) {
errorPos = i;
} if (errorCounter == 1) { //if a second mistake occurs, either the letters are swapped or it is not correct
//but there could be a third mistake, so in the case of a swap, true is not directly returned.
if ((word[i] != guess[errorPos]) || (word[errorPos] != guess[i])) {
return false;
}
} if (errorCounter >= 2) { //with two or more mistakes, the word is not close
return false;
}
errorCounter++;
}
}
//if it hasnt returned false by now, the guess is close
return true;
}
//if one letter too much
if (guess.length - 1 == word.length) {
let errorCounter = 0; //also the offset
for (var i = 0; i < guess.length; i++) {
if (word[i - errorCounter] != guess[i]) {
errorCounter++;
if (errorCounter >= 2) {
return false;
}
}
}
return true;
}
//if one letter too little
if (guess.length + 1 == word.length) {
let errorCounter = 0; //also the offset
for (var i = 0; i < word.length; i++) {
if (word[i] != guess[i - errorCounter]) {
errorCounter++;
if (errorCounter >= 2) {
return false;
}
}
}
return true;
}
return false;
}
/**
* Checks if the guess is correct. It is not case-sensitive.
* @param {string} guess
* @param {string} word
*/
static _isCorrect(guess, word) {
guess = guess.toLowerCase().replace(/-/g," ").replace(/'/g,'').normalize("NFD").replace(/[\u0300-\u0307\u0309-\u036f]/g, "");
word = word.toLowerCase().replace(/-/g," ").replace(/'/g,'').normalize("NFD").replace(/[\u0300-\u0307\u0309-\u036f]/g, "");
return guess==word;
}
} }
\ No newline at end of file
...@@ -3,9 +3,6 @@ import {CustomElement} from "../util/Util.js"; ...@@ -3,9 +3,6 @@ import {CustomElement} from "../util/Util.js";
/** /**
* Custom element `<skribbl-chat>` for the chat used to guess words and see others guesses. * Custom element `<skribbl-chat>` for the chat used to guess words and see others guesses.
* @todo better scroll functionality (stay stickied to bottom unless specifically scrolled up, subtle css effects where stuff is hidden from view)
* @todo allow cycling through previous guesses using the arrow keys, like in a terminal
* @todo write to the chat which player is drawing now
*/ */
export default class SkribblChat extends CustomElement { export default class SkribblChat extends CustomElement {
/** /**
...@@ -13,6 +10,12 @@ export default class SkribblChat extends CustomElement { ...@@ -13,6 +10,12 @@ export default class SkribblChat extends CustomElement {
*/ */
constructor(client){ constructor(client){
super(); super();
/** @type {string[]} */
this._guesses = []; //Guesses and the current Position in the GuessList are stored locally
this._guessListPosition = 0;
this._oldDrawer = -1;
this._oldPlayerCount = client.state.value.players.length;
this._client = client;
this.attachShadow({mode:"open"}); this.attachShadow({mode:"open"});
this.shadowRoot.innerHTML = ` this.shadowRoot.innerHTML = `
<style> <style>
...@@ -61,36 +64,97 @@ export default class SkribblChat extends CustomElement { ...@@ -61,36 +64,97 @@ export default class SkribblChat extends CustomElement {
<input id="input" type="text" placeholder="your guess here!"> <input id="input" type="text" placeholder="your guess here!">
</div> </div>
`; `;
this._client = client;
this._messageDiv = this.shadowRoot.getElementById("messages-inner-container");
/** @type {HTMLInputElement} */// @ts-ignore /** @type {HTMLInputElement} */// @ts-ignore
this._input = this.shadowRoot.getElementById("input"); this._input = this.shadowRoot.getElementById("input");
this._messageDiv = this.shadowRoot.getElementById("messages-inner-container");
//Player sends guess
this._input.addEventListener("keydown",e=>{ this._input.addEventListener("keydown",e=>{
if (e.key=="Enter"&&this._input.value!==""){ if (e.key=="Enter"&&this._input.value!==""){
this._client.sendGuess(this._input.value); //add guess to the guesslist
this._guesses[this._guesses.length] = this._input.value;
this._guessListPosition = this._guesses.length;
//send guess to the server
this._client.sendGuess(this._input.value);
this._input.value = ""; this._input.value = "";
} else if (e.key=="ArrowUp"&&this._guessListPosition>0){ //cycle through previous guesses
this._input.value = this._guesses[--this._guessListPosition];
} else if (e.key=="ArrowDown"&&this._guessListPosition<this._guesses.length){
this._input.value = this._guesses[++this._guessListPosition]||"";
} }
}); });
//Player receives messages from other players
client.onGuess(guessData=>{ client.onGuess(guessData=>{
let playerName = this._client.players.value[guessData.player].name; let playerName = this._client.players.value[guessData.player].name;
this._messageDiv.appendChild(new SkribblGuess(playerName,guessData)); let shouldScroll = this._messageDiv.scrollHeight <= this._messageDiv.scrollTop + this._messageDiv.clientHeight + 10;
//The 10 is important because the scrolling doesnt work properly without it
if (guessData.correct==true) {
let isCorrectPlayer = guessData.player == client.state.value.playerIndex;
//isCorrectPlayer determines if the message will show "You guessed" or "PLAYERNAME guessed"
this._messageDiv.appendChild(_SkribblMessage.createSkribblCorrect(playerName,isCorrectPlayer));
} else if (guessData.close==true) { //when it is close, the word will be sent
this._messageDiv.appendChild(_SkribblMessage.createSkribblTextMessage(playerName,guessData.word));
//and only to the player that was close will get an additional message telling them they were close
this._messageDiv.appendChild(_SkribblMessage.createSkribblClose(guessData.word));
} else {
this._messageDiv.appendChild(_SkribblMessage.createSkribblTextMessage(playerName,guessData.word));
}
if (shouldScroll) {
this._messageDiv.scrollTop = this._messageDiv.scrollHeight - this._messageDiv.clientHeight;
}
},{onlyWhen:this.connected}); },{onlyWhen:this.connected});
//Word is revealed
client.onWordReveal(message=>{ client.onWordReveal(message=>{
// TODO reveal the word in the chat let shouldScroll = this._messageDiv.scrollHeight <= this._messageDiv.scrollTop + this._messageDiv.clientHeight + 10;
//The 10 is important because the scrolling doesnt work properly without it
this._messageDiv.appendChild(_SkribblMessage.createSkribblReveal(message.word));
if (shouldScroll) {
this._messageDiv.scrollTop = this._messageDiv.scrollHeight - this._messageDiv.clientHeight;
}
},{onlyWhen:this.connected});
//There is a new drawer
client._state.onChange(state=>{
let shouldScroll = this._messageDiv.scrollHeight <= this._messageDiv.scrollTop + this._messageDiv.clientHeight + 10;
//The 10 is important because the scrolling doesnt work properly without it
if (state.hasGameStarted&&typeof state.word=="string"&&state.drawingPlayer!=this._oldDrawer) {
this._oldDrawer = state.drawingPlayer;
this._messageDiv.appendChild(_SkribblMessage.createSkribblNewDrawer(state.players[state.drawingPlayer].name));
}
if (shouldScroll) {
this._messageDiv.scrollTop = this._messageDiv.scrollHeight - this._messageDiv.clientHeight;
}
},{onlyWhen:this.connected});
//A Player joint/left
client._state.onChange(state=>{
let shouldScroll = this._messageDiv.scrollHeight <= this._messageDiv.scrollTop + this._messageDiv.clientHeight + 10;
//The 10 is important because the scrolling doesnt work properly without it)
if (state.hasGameStarted) {
if (state.players.length > this._oldPlayerCount) { //Player joined
this._messageDiv.appendChild(_SkribblMessage.createSkribblJoin(state.players[state.players.length - 1].name));
this._oldPlayerCount = state.players.length;
} else if (state.players.length < this._oldPlayerCount) { //Player left
this._messageDiv.appendChild(_SkribblMessage.createSkribblLeave("WIP"));
this._oldPlayerCount = state.players.length;
//TODO this can only be implemented when players that leave are removed from state.players
}
}
if (shouldScroll) {
this._messageDiv.scrollTop = this._messageDiv.scrollHeight - this._messageDiv.clientHeight;
}
},{onlyWhen:this.connected}); },{onlyWhen:this.connected});
} }
} }
/** /**
* Custom element `<skribbl-guess>` that appears in the chat whenever someone tries to guess the word. * Custom element that generates messages for the chat
* @todo display message when the word was close
* @todo refer to the player with "you" when he guesses the word, not using his name
*/ */
export class SkribblGuess extends HTMLElement { class _SkribblMessage extends HTMLElement {
/** /**
* @param {string} playerName * The constructor is not supposed to be called by anything outside the methods of _SkribblMessage
* @param {import("../logic/SkribblClient.js").GuessResponse} guess * @param {string} innerHTML
* @param {string} color
* @param {string} backgroundColor
*/ */
constructor(playerName,guess){ constructor(innerHTML,color="#000000",backgroundColor="#ffffff") {
super(); super();
this.attachShadow({mode:"open"}); this.attachShadow({mode:"open"});
this.shadowRoot.innerHTML = ` this.shadowRoot.innerHTML = `
...@@ -99,29 +163,107 @@ export class SkribblGuess extends HTMLElement { ...@@ -99,29 +163,107 @@ export class SkribblGuess extends HTMLElement {
display: block; display: block;
} }
</style> </style>
<b></b><span></span> <span></span>
`; `;
this._playerName = playerName; this.shadowRoot.querySelector("span").innerHTML = innerHTML;
this._guess = guess; this.style.color = color;
this.shadowRoot.querySelector("b").textContent = playerName; this.style.backgroundColor = backgroundColor;
// seems unnecessary, I know. but for some reason IntelliSense won't correctly infer the type in the else block without the `==true` }
if (guess.correct==true){
this.shadowRoot.querySelector("span").textContent = " has guessed the word!"; /**
this.style.color = "#00bf00"; * Creates a chat-message that will be displayed in the format "playerName: message"
}else{ * @param {string} playerName
this.shadowRoot.querySelector("span").textContent = `: ${guess.word}`; * @param {string} message
} */
static createSkribblTextMessage(playerName,message) {
let innerHTML = "<b>" + playerName + ":</b> " + message;
let element = new _SkribblMessage(innerHTML);
return element;
}
/**
* Creates a ghost-message that will be displayed in the format "playerName: message"
* ghost-message means that only the drawer and the ones who already guessed correct can see it
* @param {string} playerName
* @param {string} message
*/
static createSkribblGhostMessage(playerName,message) {
let innerHTML = "<b>" + playerName + ":</b> " + message;
let color = "#908070";
let element = new _SkribblMessage(innerHTML,color);
return element;
}
/**
* Creates a chat-message that reveals the word
* @param {string} word
*/
static createSkribblReveal(word) {
let innerHTML = "The word was: <b>" + word + "</b>";
let color = "#00bf00";
let element = new _SkribblMessage(innerHTML,color);
return element;
}
/**
* Creates a chat-message that will be sent to only the player who was close and will tell them so
* @param {string} guess
*/
static createSkribblClose(guess) {
let innerHTML = "<b>'" + guess + "'</b> is close!";
let color = "#7f7f21";
let backgroundColor = "#e8e890";
let element = new _SkribblMessage(innerHTML,color,backgroundColor);
return element;
}
/**
* Creates a chat-message that will tell everyone when someone guessed the word
* isCorrectPlayer determines if the message will show "You guessed" or "PLAYERNAME guessed"
* @param {string} playerName
* @param {boolean} isCorrectPlayer
*/
static createSkribblCorrect(playerName,isCorrectPlayer) {
let name = (isCorrectPlayer) ? "You have" : "<b>" + playerName + "</b> has" ;
let innerHTML = name + " guessed the word!";
let color = "#00bf00";
let element = new _SkribblMessage(innerHTML,color);
return element;
} }
/** @readonly */ /**
get playerName(){ * Creates a chat-message that will tell everyone when there is a new drawer
return this._playerName; * @param {string} playerName
*/
static createSkribblNewDrawer(playerName) {
let innerHTML = "<b>'" + playerName + "'</b> is drawing now!";
let color = "#00bf00";
let element = new _SkribblMessage(innerHTML,color);
return element;
}
/**
* Creates a chat-message that will tell everyone when someone joined
* @param {string} playerName
*/
static createSkribblJoin(playerName) {
let innerHTML = "<b>'" + playerName + "'</b> joined!";
let color = "#008000";
let element = new _SkribblMessage(innerHTML,color);
return element;
} }
/** @readonly */ /**
get word(){ * Creates a chat-message that will tell everyone when someone left
return this._guess.word; * @param {string} playerName
*/
static createSkribblLeave(playerName) {
let innerHTML = "<b>'" + playerName + "'</b> left!";
let color = "#800000";
let element = new _SkribblMessage(innerHTML,color);
return element;
} }
} }
customElements.define("skribbl-chat",SkribblChat); customElements.define("skribbl-chat",SkribblChat);
customElements.define("skribbl-guess",SkribblGuess); customElements.define("skribbl-messaage",_SkribblMessage);
\ No newline at end of file \ No newline at end of file
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment