Compare commits

..

No commits in common. "0fcd12d8857904068859a37a96b5cafc65ccbc02" and "5d769c39899eb54b85aff6c88c5cda8f6875fe0f" have entirely different histories.

50 changed files with 259 additions and 320 deletions

View File

@ -1,11 +1,11 @@
image: debian/unstable
image: ubuntu/lts
packages:
- openjdk-19-jdk
- openjdk-11-jre-headless
- maven
sources:
- https://git.sr.ht/~crg/lingo
artifacts:
- lingo/server/target/lingo.jar
- lingo/server/target/lingo-server.jar
tasks:
- build: |
cd lingo

View File

@ -1 +1 @@
web: java -jar server/target/lingo.jar
web: java -jar server/target/lingo-server.jar

View File

@ -1,19 +1,17 @@
## Lingo
[![builds.sr.ht status](https://builds.sr.ht/~crg.svg)](https://builds.sr.ht/~crg?)
A word guessing game based on the [game show](https://en.wikipedia.org/wiki/Lingo_(American_game_show)).
[Screenshots](screenshots/)
#### Browser client
- Practice: https://lingo.gould.dev/practice.html
- Competitive: https://lingo.gould.dev
- Practice: https://lingo.charego.com/practice.html
- Competitive: https://lingo.charego.com
#### JavaFX client
- Requirements: Java 19, Maven 3
- Requirements: Java 11, Maven 3
- Build: `mvn clean install`
- Start client: `mvn -f client javafx:run`
@ -21,8 +19,8 @@ A word guessing game based on the [game show](https://en.wikipedia.org/wiki/Ling
- Build: `mvn clean install`
- Start server
* Default port (8080): `java -jar server/target/lingo.jar`
* Custom port: `java -jar server/target/lingo.jar --server.port=<port>`
* Default port (8080): `java -jar server/target/lingo-server.jar`
* Custom port: `java -jar server/target/lingo-server.jar --server.port=<port>`
- Start client
* Browser: `open http://localhost:<port>`
* JavaFX: `mvn -f client javafx:run -Dlingo-url=http://localhost:<port>`

View File

@ -3,8 +3,8 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.gould</groupId>
<artifactId>lingo</artifactId>
<groupId>com.charego</groupId>
<artifactId>lingo-parent</artifactId>
<version>1.0</version>
</parent>

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.api;
package com.charego.lingo.api;
public class Destinations {

View File

@ -1,3 +1,3 @@
module dev.gould.lingo.api {
exports dev.gould.lingo.api;
module com.charego.lingo.api {
exports com.charego.lingo.api;
}

View File

@ -3,8 +3,8 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.gould</groupId>
<artifactId>lingo</artifactId>
<groupId>com.charego</groupId>
<artifactId>lingo-parent</artifactId>
<version>1.0</version>
</parent>
@ -12,8 +12,8 @@
<name>Lingo :: Client</name>
<properties>
<javafx.version>19</javafx.version>
<lingo.url>https://lingo.gould.dev</lingo.url>
<javafx.version>11.0.2</javafx.version>
<lingo.url>https://lingo.charego.com</lingo.url>
</properties>
<dependencies>
@ -52,14 +52,22 @@
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<version>0.0.4</version>
<configuration>
<mainClass>dev.gould.lingo.client/dev.gould.lingo.client.bootstrap.LingoClient</mainClass>
<mainClass>com.charego.lingo.client.bootstrap.LingoClient</mainClass>
<options>
<option>-Dlingo.url=${lingo.url}</option>
</options>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
<mainClass>com.charego.lingo.client.bootstrap.LingoClient</mainClass>
<addResourcesToClasspath>true</addResourcesToClasspath>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.client.bootstrap;
package com.charego.lingo.client.bootstrap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

View File

@ -1,12 +1,12 @@
package dev.gould.lingo.client.bootstrap;
package com.charego.lingo.client.bootstrap;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import dev.gould.lingo.client.multiplayer.MultiplayerConfig;
import dev.gould.lingo.client.multiplayer.MultiplayerPresenter;
import dev.gould.lingo.client.singleplayer.SinglePlayerPresenter;
import dev.gould.lingo.client.util.FxmlController;
import com.charego.lingo.client.multiplayer.MultiplayerConfig;
import com.charego.lingo.client.multiplayer.MultiplayerPresenter;
import com.charego.lingo.client.singleplayer.SinglePlayerPresenter;
import com.charego.lingo.client.util.FxmlController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.client.bootstrap;
package com.charego.lingo.client.bootstrap;
import java.io.IOException;
import java.util.ArrayList;
@ -10,9 +10,9 @@ import java.util.Set;
import org.springframework.stereotype.Component;
import dev.gould.lingo.common.WordReader;
import com.charego.lingo.common.WordReader;
import jakarta.annotation.PostConstruct;
import javax.annotation.PostConstruct;
@Component
public class WordRepository {

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.client.multiplayer;
package com.charego.lingo.client.multiplayer;
import java.util.ArrayList;
import java.util.List;

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.client.multiplayer;
package com.charego.lingo.client.multiplayer;
import java.lang.reflect.Type;
import java.util.Arrays;
@ -6,9 +6,9 @@ import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer;
import jakarta.annotation.PostConstruct;
import javax.annotation.PostConstruct;
import dev.gould.lingo.common.LobbyData;
import com.charego.lingo.common.LobbyData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -34,14 +34,14 @@ import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.TextAlignment;
import javafx.scene.web.WebView;
import dev.gould.lingo.api.Destinations;
import dev.gould.lingo.client.util.FxmlController;
import dev.gould.lingo.client.view.Board;
import dev.gould.lingo.client.view.OpponentBoard;
import dev.gould.lingo.client.view.PlayerBoard;
import dev.gould.lingo.common.Game;
import dev.gould.lingo.common.GameLeftMessage;
import dev.gould.lingo.common.Report;
import com.charego.lingo.api.Destinations;
import com.charego.lingo.client.util.FxmlController;
import com.charego.lingo.client.view.Board;
import com.charego.lingo.client.view.OpponentBoard;
import com.charego.lingo.client.view.PlayerBoard;
import com.charego.lingo.common.Game;
import com.charego.lingo.common.GameLeftMessage;
import com.charego.lingo.common.Report;
@Component
public class MultiplayerPresenter implements FxmlController {

View File

@ -1,11 +1,11 @@
package dev.gould.lingo.client.multiplayer;
package com.charego.lingo.client.multiplayer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.function.Consumer;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -1,8 +1,8 @@
package dev.gould.lingo.client.singleplayer;
package com.charego.lingo.client.singleplayer;
import java.util.Arrays;
import dev.gould.lingo.client.bootstrap.WordRepository;
import com.charego.lingo.client.bootstrap.WordRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -21,10 +21,10 @@ import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Font;
import javafx.scene.text.TextAlignment;
import dev.gould.lingo.client.view.PlayerBoard;
import dev.gould.lingo.common.Game;
import dev.gould.lingo.common.Player;
import dev.gould.lingo.common.Report;
import com.charego.lingo.client.view.PlayerBoard;
import com.charego.lingo.common.Game;
import com.charego.lingo.common.Player;
import com.charego.lingo.common.Report;
public class SinglePlayerPresenter {

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.client.util;
package com.charego.lingo.client.util;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.client.view;
package com.charego.lingo.client.view;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.client.view;
package com.charego.lingo.client.view;
import java.util.ArrayList;
import java.util.List;

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.client.view;
package com.charego.lingo.client.view;
import javafx.scene.canvas.Canvas;

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.client.view;
package com.charego.lingo.client.view;
import java.util.ArrayList;
import java.util.HashMap;

View File

@ -1,7 +1,7 @@
module dev.gould.lingo.client {
requires dev.gould.lingo.common;
requires dev.gould.lingo.api;
requires jakarta.annotation;
module com.charego.lingo.client {
requires com.charego.lingo.common;
requires com.charego.lingo.api;
requires java.annotation;
requires javafx.controls;
requires javafx.fxml;
requires javafx.graphics;
@ -15,8 +15,8 @@ module dev.gould.lingo.client {
requires spring.messaging;
requires spring.web;
requires spring.websocket;
exports dev.gould.lingo.client.bootstrap;
exports dev.gould.lingo.client.multiplayer;
opens dev.gould.lingo.client.bootstrap to javafx.fxml, spring.core;
opens dev.gould.lingo.client.multiplayer to javafx.fxml, spring.core;
exports com.charego.lingo.client.bootstrap;
exports com.charego.lingo.client.multiplayer;
opens com.charego.lingo.client.bootstrap to javafx.fxml, spring.core;
opens com.charego.lingo.client.multiplayer to javafx.fxml, spring.core;
}

View File

@ -1,2 +1,2 @@
# https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html
logging.level.dev.gould.lingo = DEBUG
logging.level.com.charego.lingo = DEBUG

View File

@ -8,7 +8,7 @@
<?import javafx.scene.layout.VBox?>
<BorderPane xmlns:fx="http://javafx.com/fxml"
fx:controller="dev.gould.lingo.client.bootstrap.LingoPresenter"
fx:controller="com.charego.lingo.client.bootstrap.LingoPresenter"
fx:id="content"
prefWidth="650"
prefHeight="420">

View File

@ -8,7 +8,7 @@
<?import javafx.scene.web.WebView?>
<StackPane xmlns:fx="http://javafx.com/fxml"
fx:controller="dev.gould.lingo.client.multiplayer.MultiplayerPresenter"
fx:controller="com.charego.lingo.client.multiplayer.MultiplayerPresenter"
fx:id="contentPane">
<children>

View File

@ -3,8 +3,8 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.gould</groupId>
<artifactId>lingo</artifactId>
<groupId>com.charego</groupId>
<artifactId>lingo-parent</artifactId>
<version>1.0</version>
</parent>

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.common;
package com.charego.lingo.common;
public class ChatMessage {

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.common;
package com.charego.lingo.common;
import java.util.Arrays;
import java.util.Collections;

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.common;
package com.charego.lingo.common;
public class GameLeftMessage {

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.common;
package com.charego.lingo.common;
import java.util.Collection;

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.common;
package com.charego.lingo.common;
import com.fasterxml.jackson.annotation.JsonIgnore;

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.common;
package com.charego.lingo.common;
public class Report {

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.common;
package com.charego.lingo.common;
public class SetUsernameMessage {

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.common;
package com.charego.lingo.common;
import java.io.BufferedReader;
import java.io.IOException;

View File

@ -1,4 +1,4 @@
module dev.gould.lingo.common {
module com.charego.lingo.common {
requires com.fasterxml.jackson.annotation;
exports dev.gould.lingo.common;
exports com.charego.lingo.common;
}

View File

@ -5,11 +5,11 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.0</version>
<version>2.3.0.RELEASE</version>
</parent>
<groupId>dev.gould</groupId>
<artifactId>lingo</artifactId>
<groupId>com.charego</groupId>
<artifactId>lingo-parent</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
@ -17,7 +17,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>19</java.version>
<java.version>11</java.version>
</properties>
<modules>

View File

@ -3,8 +3,8 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.gould</groupId>
<artifactId>lingo</artifactId>
<groupId>com.charego</groupId>
<artifactId>lingo-parent</artifactId>
<version>1.0</version>
</parent>
@ -17,46 +17,56 @@
<version>${project.version}</version>
<artifactId>lingo-api</artifactId>
</dependency>
<!-- Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- Development Tools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<!-- Prevent transitive application to other modules -->
<optional>true</optional>
</dependency>
</dependencies>
<build>
<finalName>lingo</finalName>
<plugins>
<!-- Repackage as executable JAR (java -jar) -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- Enable hot refreshing of resources -->
<!-- Add src/main/resources to the classpath -->
<!-- Remove duplicate resources from target/classes -->
<addResources>true</addResources>
<image>
<name>docker.io/charego/lingo</name>
</image>
<finalName>${project.artifactId}</finalName>
</configuration>
<executions>
<!-- Repackage as executable JAR (java -jar) -->
<execution>
<id>repackage</id>
</execution>
</executions>
</plugin>
<!-- How to build image directly to Docker daemon: -->
<!-- $ mvn jib:dockerBuild -->
<!-- How to build image and publish to Docker registry: -->
<!-- $ mvn jib:build -->
<!-- $ mvn jib:build -Djib.to.image=<myregistry>/<myimage>:latest -->
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>3.3.1</version>
<version>2.2.0</version>
<configuration>
<!-- Enable this setting to allow pushes to local Docker registry -->
<!--<allowInsecureRegistries>true</allowInsecureRegistries>-->
<from>
<image>eclipse-temurin:19-jre</image>
<image>adoptopenjdk:11-jre-openj9</image>
</from>
<to>
<image>docker.io/charego/lingo</image>
</to>
<container>
<mainClass>dev.gould.lingo.server.LingoServer</mainClass>
<ports>
<port>8080</port>
</ports>

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.server;
package com.charego.lingo.server;
import static org.springframework.messaging.simp.SimpMessageHeaderAccessor.SESSION_ID_HEADER;
@ -8,10 +8,10 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import jakarta.annotation.PostConstruct;
import javax.annotation.PostConstruct;
import dev.gould.lingo.api.Destinations;
import dev.gould.lingo.common.*;
import com.charego.lingo.api.Destinations;
import com.charego.lingo.common.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -30,20 +30,20 @@ public class LingoController {
private static final Logger log = LoggerFactory.getLogger(LingoController.class);
private final SimpMessagingTemplate messagingTemplate;
private final SessionManager sessionManager;
private final WordRepository wordRepo;
private final Map<Integer, Game> gameById = new TreeMap<>();
private final Map<Player, Game> gameByPlayer = new HashMap<>();
private final Set<String> usernames = new HashSet<>();
@Autowired
private SimpMessagingTemplate messagingTemplate;
@Autowired
public LingoController(SimpMessagingTemplate messagingTemplate, SessionManager sessionManager, WordRepository wordRepo) {
this.messagingTemplate = messagingTemplate;
this.sessionManager = sessionManager;
this.wordRepo = wordRepo;
}
private SessionManager sessionManager;
@Autowired
private WordRepository wordRepo;
private final Map<Integer, Game> gameById = new TreeMap<>();
private final Map<Player, Game> gameByPlayer = new HashMap<>();
private final Set<String> usernames = new HashSet<>();
@MessageMapping("/chat")
public ChatMessage chat(String message, @Header(SESSION_ID_HEADER) String sessionId) {

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.server;
package com.charego.lingo.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.server;
package com.charego.lingo.server;
import static org.springframework.messaging.simp.SimpMessageHeaderAccessor.SESSION_ID_HEADER;
@ -16,28 +16,26 @@ import org.springframework.messaging.simp.SimpMessageType;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.web.bind.annotation.RestController;
import dev.gould.lingo.api.Destinations;
import dev.gould.lingo.common.Game;
import dev.gould.lingo.common.Player;
import dev.gould.lingo.common.Report;
import com.charego.lingo.api.Destinations;
import com.charego.lingo.common.Game;
import com.charego.lingo.common.Player;
import com.charego.lingo.common.Report;
@RestController
public class PracticeController {
private static final Logger log = LoggerFactory.getLogger(PracticeController.class);
private final SimpMessagingTemplate messagingTemplate;
private final SessionManager sessionManager;
private final WordRepository wordRepo;
private final Map<Player, Game> practiceByPlayer = new HashMap<>();
@Autowired
private SimpMessagingTemplate messagingTemplate;
@Autowired
public PracticeController(SimpMessagingTemplate messagingTemplate, SessionManager sessionManager, WordRepository wordRepo) {
this.messagingTemplate = messagingTemplate;
this.sessionManager = sessionManager;
this.wordRepo = wordRepo;
}
private SessionManager sessionManager;
@Autowired
private WordRepository wordRepo;
private final Map<Player, Game> practiceByPlayer = new HashMap<>();
@MessageMapping("/practiceGame")
public void practiceGame(@Header(SESSION_ID_HEADER) String sessionId) {

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.server;
package com.charego.lingo.server;
import java.util.Collection;
import java.util.HashMap;
@ -15,7 +15,7 @@ import org.springframework.web.socket.messaging.AbstractSubProtocolEvent;
import org.springframework.web.socket.messaging.SessionConnectedEvent;
import org.springframework.web.socket.messaging.SessionDisconnectEvent;
import dev.gould.lingo.common.Player;
import com.charego.lingo.common.Player;
@Component
public class SessionManager implements ApplicationListener<AbstractSubProtocolEvent> {

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.server;
package com.charego.lingo.server;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;

View File

@ -1,4 +1,4 @@
package dev.gould.lingo.server;
package com.charego.lingo.server;
import java.io.IOException;
import java.util.ArrayList;
@ -10,9 +10,9 @@ import java.util.Set;
import org.springframework.stereotype.Component;
import dev.gould.lingo.common.WordReader;
import com.charego.lingo.common.WordReader;
import jakarta.annotation.PostConstruct;
import javax.annotation.PostConstruct;
@Component
public class WordRepository {

View File

@ -1,7 +1,7 @@
module dev.gould.lingo.server {
requires dev.gould.lingo.common;
requires dev.gould.lingo.api;
requires jakarta.annotation;
module com.charego.lingo.server {
requires com.charego.lingo.common;
requires com.charego.lingo.api;
requires java.annotation;
requires org.slf4j;
requires spring.beans;
requires spring.boot;

View File

@ -1,2 +1,2 @@
# https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html
logging.level.dev.gould.lingo = DEBUG
logging.level.com.charego.lingo = DEBUG

View File

@ -7,9 +7,9 @@ const MARGIN_BOTTOM = 75;
let client = null;
let sessionId = null;
const app = Vue.createApp({
data() {
return {
const vm = new Vue({
el: '#vue-app',
data: {
players: [],
games: [],
messages: [],
@ -25,7 +25,6 @@ const app = Vue.createApp({
opponentResults: [],
opponentUsername: null,
lastWord: null
}
},
computed: {
inGame: function() {
@ -276,8 +275,11 @@ const app = Vue.createApp({
this.opponentScore = 0;
}
}
},
mounted: function() {
document.getElementById('nicknameInput').focus();
}
}).mount('#app');
});
function afterConnected(stompConnectedFrame) {
console.log('Connected to STOMP endpoint')
@ -314,7 +316,7 @@ function main() {
// Will be invoked in case of error encountered at broker.
// Bad login/passcode typically will cause an error.
// Compliant brokers will set `message` header with a brief message. Body may contain details.
// Complaint brokers will set `message` header with a brief message. Body may contain details.
// Compliant brokers will terminate the connection after any error.
client.onStompError = function(frame) {
console.log('Broker reported error: ' + frame.headers['message']);
@ -345,10 +347,10 @@ function main() {
const response = JSON.parse(message.body);
if (response.success === true) {
console.log('Username: ' + response.username);
app.username = response.username;
vm.username = response.username;
start();
} else {
app.usernameError = response.errorMessage;
vm.usernameError = response.errorMessage;
}
};
@ -356,12 +358,12 @@ function main() {
if (e.key === 'Enter') {
e.preventDefault();
if (sessionId === null) {
app.usernameError = 'Not connected to server';
vm.usernameError = 'Not connected to server';
return;
}
const usernameValue = usernameInput.value.trim();
if (usernameValue.length === 0) {
app.usernameError = 'Name cannot be empty';
vm.usernameError = 'Name cannot be empty';
return;
}
if (usernameSubscription === null) {
@ -377,7 +379,7 @@ function main() {
}
const usernameValue = usernameInput.value.trim();
if (usernameValue.length !== 0) {
app.usernameError = '';
vm.usernameError = '';
}
});
}
@ -407,7 +409,7 @@ function start() {
const games = data.games;
for (let i = 0; i < games.length; i++) {
const game = games[i];
app.games.push({
vm.games.push({
id: game.id,
playerOne: game.playerOne.username,
playerTwo: game.playerTwo ? game.playerTwo.username : null,
@ -417,7 +419,7 @@ function start() {
}
for (let i = 0; i < players.length; i++) {
const player = players[i];
app.players.push({
vm.players.push({
username: player.username
});
}
@ -436,14 +438,14 @@ function start() {
}
function addChatAnnouncement(body) {
app.messages.push({
vm.messages.push({
body: body
});
showNotification('Announcement', body);
}
function addChatMessage(sender, body) {
app.messages.push({
vm.messages.push({
sender: sender,
body: body
});
@ -472,7 +474,7 @@ function onChat(message) {
const messageBody = chatMessage.message;
if (messageSender === null) {
addChatAnnouncement(messageBody);
} else if (messageSender === app.username) {
} else if (messageSender === vm.username) {
// Ignore messages sent by yourself
} else {
console.log('Message from ' + messageSender + ': ' + messageBody);
@ -485,10 +487,10 @@ function onGameClosed(message) {
const gameId = game.id;
const playerOne = game.playerOne.username;
console.log(playerOne + ' closed Game ' + gameId);
if (playerOne === app.username) {
app.myGame = null;
if (playerOne === vm.username) {
vm.myGame = null;
}
app.removeGame(gameId);
vm.removeGame(gameId);
}
function onGameHosted(message) {
@ -503,9 +505,9 @@ function onGameHosted(message) {
wordLength: wordLength,
started: false
};
app.games.push(vueGame);
if (playerOne === app.username) {
app.myGame = vueGame;
vm.games.push(vueGame);
if (playerOne === vm.username) {
vm.myGame = vueGame;
}
}
@ -519,18 +521,18 @@ function onGameJoined(message) {
console.log(playerTwo + ' joined ' + playerOne + "'s game");
let vueGame = null;
for (let i = 0; i < app.games.length; i++) {
if (app.games[i].id === gameId) {
app.games[i].playerTwo = playerTwo;
app.games[i].wordLength = wordLength;
app.games[i].started = true;
vueGame = app.games[i];
for (let i = 0; i < vm.games.length; i++) {
if (vm.games[i].id === gameId) {
vm.games[i].playerTwo = playerTwo;
vm.games[i].wordLength = wordLength;
vm.games[i].started = true;
vueGame = vm.games[i];
break;
}
}
if (playerTwo === app.username) {
app.myGame = vueGame;
if (playerTwo === vm.username) {
vm.myGame = vueGame;
}
}
@ -542,33 +544,33 @@ function onGameLeft(message) {
const gameLeaver = report.gameLeaver.username;
console.log(gameLeaver + ' left ' + playerOne + "'s game");
const previousPlayers = [];
for (let i = 0; i < app.games.length; i++) {
if (app.games[i].id === gameId) {
previousPlayers.push(app.games[i].playerOne);
previousPlayers.push(app.games[i].playerTwo);
app.games[i].playerOne = playerOne;
app.games[i].playerTwo = game.playerTwo ? game.playerTwo.username : null;
app.games[i].started = false;
for (let i = 0; i < vm.games.length; i++) {
if (vm.games[i].id === gameId) {
previousPlayers.push(vm.games[i].playerOne);
previousPlayers.push(vm.games[i].playerTwo);
vm.games[i].playerOne = playerOne;
vm.games[i].playerTwo = game.playerTwo ? game.playerTwo.username : null;
vm.games[i].started = false;
break;
}
}
if (gameLeaver === app.username) {
app.myGame = null;
if (gameLeaver === vm.username) {
vm.myGame = null;
}
if (previousPlayers.indexOf(app.username) !== -1) {
app.opponentUsername = null;
app.lastWord = null;
app.repaint();
if (previousPlayers.indexOf(vm.username) !== -1) {
vm.opponentUsername = null;
vm.lastWord = null;
vm.repaint();
}
}
function onOpponentJoined(message) {
const report = JSON.parse(message.body);
const firstLetter = report[0];
app.opponentUsername = report[1];
console.log('Opponent username: ' + app.opponentUsername);
app.reset(firstLetter, true);
app.repaint();
vm.opponentUsername = report[1];
console.log('Opponent username: ' + vm.opponentUsername);
vm.reset(firstLetter, true);
vm.repaint();
}
function onOpponentReport(message) {
@ -577,14 +579,14 @@ function onOpponentReport(message) {
if (report.correct === true) {
const guess = report.guess;
const firstLetter = report.firstLetter;
app.opponentScore = app.opponentScore + 100;
app.lastWord = guess;
app.reset(firstLetter, false);
app.repaint();
vm.opponentScore = vm.opponentScore + 100;
vm.lastWord = guess;
vm.reset(firstLetter, false);
vm.repaint();
} else {
const result = report.result;
app.opponentResults.push(result);
app.repaint();
vm.opponentResults.push(result);
vm.repaint();
}
}
@ -594,26 +596,26 @@ function onPlayerReport(message) {
if (report.correct === true) {
const guess = report.guess;
const firstLetter = report.firstLetter;
app.myScore = app.myScore + 100;
app.lastWord = guess;
app.reset(firstLetter, false);
app.repaint();
vm.myScore = vm.myScore + 100;
vm.lastWord = guess;
vm.reset(firstLetter, false);
vm.repaint();
} else {
const guess = report.guess;
const result = report.result;
if (result[0] === 9) {
const invalidGuess = '-'.repeat(app.wordLength);
app.myGuesses.push(invalidGuess);
const invalidGuess = '-'.repeat(vm.wordLength);
vm.myGuesses.push(invalidGuess);
} else {
for (let i = 0; i < app.wordLength; i++) {
for (let i = 0; i < vm.wordLength; i++) {
if (result[i] === 2) {
app.myProgress[i] = guess[i];
vm.myProgress[i] = guess[i];
}
}
app.myGuesses.push(guess);
vm.myGuesses.push(guess);
}
app.myResults.push(result);
app.repaint();
vm.myResults.push(result);
vm.repaint();
}
}
@ -621,7 +623,7 @@ function onPlayerJoined(message) {
const report = JSON.parse(message.body);
const username = report[0];
const numUsers = report[1];
if (username === app.username) {
if (username === vm.username) {
addChatAnnouncement('Welcome to Lingo!');
if (numUsers === 1) {
addChatAnnouncement('You are the only player online');
@ -630,7 +632,7 @@ function onPlayerJoined(message) {
}
} else {
addChatAnnouncement(username + ' joined');
app.players.push({
vm.players.push({
username: username
});
}
@ -639,7 +641,7 @@ function onPlayerJoined(message) {
function onPlayerLeft(message) {
const username = message.body;
addChatAnnouncement(username + ' left');
app.removePlayer(username);
vm.removePlayer(username);
}
function canShowNotification() {

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

View File

@ -1,76 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0 (4035a4f, 2020-05-01)"
sodipodi:docname="logo.svg"
id="svg8"
version="1.1"
viewBox="0 0 64 64"
height="64mm"
width="64mm">
<defs
id="defs2" />
<sodipodi:namedview
inkscape:window-maximized="0"
inkscape:window-y="23"
inkscape:window-x="0"
inkscape:window-height="791"
inkscape:window-width="1252"
showgrid="false"
inkscape:document-rotation="0"
inkscape:current-layer="layer1"
inkscape:document-units="mm"
inkscape:cy="291.42857"
inkscape:cx="297.14282"
inkscape:zoom="0.35"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(-13.607147,-35.529762)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<circle
r="32"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
cy="67.529762"
cx="45.607147"
id="path16"
style="fill:#000000;stroke-width:0.260465" />
<text
transform="scale(1.0355499,0.96567047)"
id="text30"
y="87.83168"
x="22.764704"
style="font-style:normal;font-weight:normal;font-size:52.1622px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.271678"
xml:space="preserve"><tspan
style="font-size:52.1622px;fill:#ffffff;stroke-width:0.271678"
y="87.83168"
x="22.764704"
id="tspan28"
sodipodi:role="line">G</tspan></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -3,20 +3,19 @@
<head>
<meta charset="UTF-8">
<title>Lingo</title>
<link rel="icon" href="favicon.svg" sizes="any" type="image/svg+xml">
<link rel="stylesheet" href="layout.css">
<link rel="stylesheet" href="style.css">
<script src="//cdn.jsdelivr.net/npm/vue@3.0.7/dist/vue.global.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/@stomp/stompjs@6.1.0/bundles/stomp.umd.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/@stomp/stompjs@5.4.4/bundles/stomp.umd.min.js"></script>
</head>
<body>
<div id="app" v-cloak>
<div id="vue-app" v-cloak>
<div class="main column">
<div class="header row">Lingo</div>
<div class="body row nofooter">
<div v-show="!username" class="form">
<h2>What is your name?</h2>
<input id="nicknameInput" type="text" class="form-control" maxlength="16" v-bind:autofocus="'autofocus'">
<input id="nicknameInput" type="text" class="form-control" maxlength="16">
<p class="error-message">{{ usernameError }}</p>
</div>
<div v-show="username">

View File

@ -11,7 +11,7 @@
<button id="skipButton" type="button">Skip Word</button>
</div>
<script src="//cdn.jsdelivr.net/npm/@stomp/stompjs@6.0.0/bundles/stomp.umd.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/@stomp/stompjs@5.2.0/bundles/stomp.umd.min.js"></script>
<script src="practice.js"></script>
</body>
</html>

View File

@ -1,6 +1,6 @@
const HEIGHT = 300;
const WIDTH = 250;
const CHARACTER_HEIGHT = 50;
const SIDE = 50;
const MARGIN_TOP = 50;
const MARGIN_BOTTOM = 25;
@ -122,11 +122,11 @@ function drawScore(x, y, score) {
function drawGrid(xOrigin, yOrigin) {
ctx.beginPath();
for (let x = 0; x <= WIDTH; x += CHARACTER_HEIGHT) {
for (let x = 0; x <= WIDTH; x += SIDE) {
ctx.moveTo(xOrigin + x, yOrigin);
ctx.lineTo(xOrigin + x, yOrigin + HEIGHT);
}
for (let y = 0; y <= HEIGHT; y += CHARACTER_HEIGHT) {
for (let y = 0; y <= HEIGHT; y += SIDE) {
ctx.moveTo(xOrigin, yOrigin + y);
ctx.lineTo(xOrigin + WIDTH, yOrigin + y);
}
@ -136,43 +136,43 @@ function drawGrid(xOrigin, yOrigin) {
function drawInput(xOrigin, yOrigin, input) {
ctx.fillStyle = 'green';
let x = xOrigin + CHARACTER_HEIGHT * 0.5;
const y = yOrigin + CHARACTER_HEIGHT * 0.5;
let x = xOrigin + SIDE * 0.5;
const y = yOrigin + SIDE * 0.5;
for (let i = 0; i < myGuess.length; i++) {
ctx.fillText(myGuess[i], x, y);
x += CHARACTER_HEIGHT;
x += SIDE;
}
}
function drawGuesses(xOrigin, yOrigin, guesses, results) {
let y = yOrigin + CHARACTER_HEIGHT * 1.5;
let y = yOrigin + SIDE * 1.5;
const numGuesses = Math.min(4, guesses.length);
for (let i = 0; i < numGuesses; i++) {
let x = xOrigin + CHARACTER_HEIGHT * 0.5;
let x = xOrigin + SIDE * 0.5;
const guess = guesses[guesses.length - numGuesses + i];
const result = results[results.length - numGuesses + i];
for (let j = 0; j < 5; j++) {
if (result[j] === 1) {
ctx.fillStyle = 'yellow';
ctx.fillRect(x - CHARACTER_HEIGHT * 0.5, y - CHARACTER_HEIGHT * 0.5, CHARACTER_HEIGHT, CHARACTER_HEIGHT);
ctx.fillRect(x - SIDE * 0.5, y - SIDE * 0.5, SIDE, SIDE);
} else if (result[j] === 2) {
ctx.fillStyle = 'orange';
ctx.fillRect(x - CHARACTER_HEIGHT * 0.5, y - CHARACTER_HEIGHT * 0.5, CHARACTER_HEIGHT, CHARACTER_HEIGHT);
ctx.fillRect(x - SIDE * 0.5, y - SIDE * 0.5, SIDE, SIDE);
}
ctx.fillStyle = 'green';
ctx.fillText(guess[j], x, y);
x += CHARACTER_HEIGHT;
x += SIDE;
}
y += CHARACTER_HEIGHT;
y += SIDE;
}
return y;
}
function drawHint(xOrigin, yOrigin, progress) {
let x = xOrigin + CHARACTER_HEIGHT * 0.5;
let x = xOrigin + SIDE * 0.5;
for (let i = 0; i < 5; i++) {
ctx.fillText(progress[i], x, yOrigin);
x += CHARACTER_HEIGHT;
x += SIDE;
}
}

View File

@ -1 +1 @@
java.runtime.version=17
java.runtime.version=11