Skip to content

Instantly share code, notes, and snippets.

@caotic123
Last active September 30, 2019 21:52
Show Gist options
  • Save caotic123/0e033aa597ef93c1000a4e5094a792af to your computer and use it in GitHub Desktop.
Save caotic123/0e033aa597ef93c1000a4e5094a792af to your computer and use it in GitHub Desktop.
A *super simply* multiplayer jokenpo oriented by sockets
import java.net.*;
import java.io.*;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.function.*;
import javafx.util.Callback;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.HashMap;
public class Server {
public class Pair<T1, T2> {
Pair(T1 t1, T2 t2) {
this.t1 = t1;
this.t2 = t2;
}
T1 first() {return t1;}
T2 second() {return t2;}
void setFirst(T1 n) {
t1 = n;
}
void setSecond(T2 n) {
t2 = n;
}
T1 t1;
T2 t2;
}
public class Tuple<T, T1, T2> {
Tuple(T t0, T1 t1, T2 t2) {
this.t0 = t0;
this.t1 = t1;
this.t2 = t2;
}
T first() {return t0;}
T1 second() {return t1;}
T2 three() {return t2;}
//and so and so... :0
T t0;
T1 t1;
T2 t2;
}
public static enum Protocols_Values {
AUTHORIZED_Player(0x0),
MATCH_GAME(0x1),
SIMPLY_MSG(0x2),
REQUEST_PLAY(0x3),
CHECK_PING(0x4)
;
private int id;
Protocols_Values (int x) {
id = x;
}
int getProtocolID() {
return id;
}
}
public static enum authority {
ANON,GAMER;
}
public class abstract_package {
abstract_package(authority p, String id) {
owner = p;
ID = id;
}
public authority owner;
public String ID;
}
public class Gamer {
Gamer(int id, String name, Tuple<Socket, BufferedReader, PrintWriter> T) {
ID = id;
conex0 = T;
this.name = name;
pontuation = 0;
}
int getID() {
return ID;
}
public void incrPontuation() {
++pontuation;
}
public int getPontuation() {
return pontuation;
}
public String getName() {
return name;
}
public Tuple<Socket, BufferedReader, PrintWriter> getConnection() {
return conex0;
}
private int ID;
private String name;
public int pontuation;
Tuple<Socket, BufferedReader, PrintWriter> conex0;
}
class State {
State() {
gamers = new LinkedList<>();
game_g = new HashMap<>();
waiting_gamers = new LinkedList<>();
IDs = 0;
}
State push_player(int id, Gamer T) {
gamers.add(T);
game_g.put(Integer.valueOf(id), T);
waiting_gamers.add(T);
return this;
}
public int getID() {return IDs;}
public int pushID() {return ++IDs;}
private Queue<Gamer> gamers = new LinkedList<>();
private Queue<Gamer> waiting_gamers = new LinkedList<>();
private HashMap<Integer, Gamer> game_g;
private int IDs;
}
private ServerSocket serverSocket;
private State state;
public void autorizePlayer(int id, Tuple<Socket, BufferedReader, PrintWriter> T) {
(T.three()).println(Protocols_Values.AUTHORIZED_Player.getProtocolID());
(T.three()).println(id);
}
public void sendMsg(Gamer g, String msg) {
((g.getConnection()).three()).println(Protocols_Values.SIMPLY_MSG.getProtocolID());
((g.getConnection()).three()).println(g.getID());
((g.getConnection()).three()).println(msg);
}
public void requestPing(Gamer g) {
((g.getConnection()).three()).println(Protocols_Values.CHECK_PING.getProtocolID());
((g.getConnection()).three()).println(g.getID());
}
public void requestPlayer(Gamer g) {
((g.getConnection()).three()).println(Protocols_Values.REQUEST_PLAY.getProtocolID());
((g.getConnection()).three()).println(g.getID());
}
public Boolean hasNewMsg(Gamer g) throws IOException {
return g.getConnection().second().ready();
}
public Integer getPlay(Gamer g) throws Exception {
return Integer.valueOf(Integer.parseInt(g.getConnection().second().readLine()));
}
public Gamer insert_player(Tuple<Socket, BufferedReader, PrintWriter> T, String name) {
int id = state.pushID();
Gamer _x = new Gamer(id, name, T);
state.push_player(id, _x);
autorizePlayer(id, T);
return _x;
}
private Future<Boolean> getPlayerResponsePing(Gamer g) {
return executor.submit(() -> {
requestPing(g);
try {
return Integer.parseInt(g.getConnection().second().readLine()) == g.getID();
}
catch(Exception e) {
return false;
}
});
}
public void checkIfOn(Gamer g, Callable<Void> f, Callable<Void> f1) throws Exception { // a simulation of a *javascriptzado* function promise
final Future<Void> time_logout;
time_logout = getPlayFutureFunction(); // 10 seconds to try a new response of the client
final Future<Boolean> ping = getPlayerResponsePing(g);
while (true) {
try {
if (ping.isDone() && ping.get()) {
f.call(); return;}
if (time_logout.isDone()) {f1.call(); return;}
}
catch(Exception e) {
f1.call();
return;
}
}
}
ExecutorService executor = Executors.newCachedThreadPool(); //
// (caso o Vivas pergunte e eu posteriomente esqueça a definição pela lib)
// Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available.
public Future<Void> stand_by() throws IOException {
return executor.submit(() ->
{
while (true) {
Function<Socket, Void> f = (final Socket clientSocket) -> {
try {
final BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
final PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
new Thread(() -> {
try {
try_gamer(new Tuple<Socket, BufferedReader, PrintWriter>(clientSocket, in, out));
}
catch(Exception e) {
System.out.println("Trying get information of a gamer and result a unexpected expection");
}
}).start();
}
catch(Exception e) {
System.out.println("Impossible of get a output Stream");
}
return null;
};
f.apply(serverSocket.accept());
}
});
}
void backPlayerToWaiting(Gamer g) throws Exception {
checkIfOn(g, () -> {
state.waiting_gamers.add(g);
try_match_with_someone(g);
return null;
},
() -> {
sendMsg(g, "Conextion Lost, Bye :3");
System.out.println("O player " + g.getID() + " foi desconectado");
return null;
});
}
public void checkGamerIsAvaliable(Gamer g, Callable<Void> f) {
try {
f.call();
}
catch(Exception e) {
System.out.println("O player " + g.getID() + " foi desconectado");
}
}
public void make_gamer_lost(Gamer gamer1, Gamer gamer2) {
sendMsg(gamer1, "Infelizmente você perdeu tente na proxima vez :)");
sendMsg(gamer2, "Parabéns você ganhou :0 :)");
gamer2.incrPontuation();
executor.submit(() -> {
try {
sendMsg(gamer1, "Você retornará na fila em 11 segundos");
Thread.sleep(11000);
backPlayerToWaiting(gamer1);
}
catch(Exception e) {
System.out.println("Algo deu errado com o player " + gamer1.getID());
}
});
executor.submit(() -> {
try {
sendMsg(gamer2, "Você retornará na fila em 10 segundos");
Thread.sleep(10000);
backPlayerToWaiting(gamer2);
}
catch(Exception e) {
System.out.println("Algo deu errado com o player " + gamer2.getID());
}
});
}
private Future<Void> getPlayFutureFunction() {
Callable<Void> fx = (() ->
{
Thread.sleep(10*1000);
return null;
});
return executor.submit(fx);
}
private Pair<Future<Pair<Integer, Long>>, Future<Pair<Integer, Long>>> getPlayersInput(Gamer g1, Gamer g2) {
Function<Gamer, Callable<Pair<Integer, Long>>> fx = g -> (() ->
{
final Integer play = getPlay(g);
return new Pair<Integer, Long>(play, Long.valueOf(System.nanoTime()));
});
return new Pair<Future<Pair<Integer, Long>>, Future<Pair<Integer, Long>>>(executor.submit(fx.apply(g1)),
executor.submit(fx.apply(g2)));
}
public void startMove(final Gamer gamer1, final Gamer gamer2) {
sendMsg(gamer1, "Gamer " + gamer1.getName() + ", você esta jogando com " + gamer2.getName() + " faça sua sua jogada! Você tem 10 segundos");
sendMsg(gamer2, "Gamer " + gamer2.getName() + ", você esta jogando com " + gamer1.getName() + " faça a sua jogada! Você tem 10 segundos" );
HashMap<Integer, String> plays = new HashMap<>();
plays.put(1, "pedra");
plays.put(2, "papel");
plays.put(3, "tesoura");
final Long actual_time = Long.valueOf(System.nanoTime());
executor.submit(() ->
{
final Function<Future<Pair<Integer, Long>>, Boolean> has_input = x -> x.isDone();
final Function<Function<Pair<Future<Pair<Integer, Long>>, Future<Pair<Integer, Long>>>, Future<Pair<Integer, Long>>>,
Function<Pair<Future<Pair<Integer, Long>>, Future<Pair<Integer, Long>>>, Optional<Integer>>>
getSomeGamerInput = f -> x -> {
try
{
return has_input.apply(f.apply(x)) ? Optional.of(f.apply(x).get().first()) : Optional.empty();
}
catch(Exception e) {
return Optional.empty();
}
};
final Function<Pair<Future<Pair<Integer, Long>>, Future<Pair<Integer, Long>>>,
Future<Pair<Integer, Long>>> first_lambda = x -> x.first();
final Function<Pair<Future<Pair<Integer, Long>>, Future<Pair<Integer, Long>>>,
Future<Pair<Integer, Long>>> second_lambda = x -> x.second();
Future<Void> play_time = getPlayFutureFunction();
Pair<Future<Pair<Integer, Long>>, Future<Pair<Integer, Long>>> inputs_plays = getPlayersInput(gamer1, gamer2);
Pair<Integer, Integer> pontuation = new Pair<Integer, Integer>(0, 0);
int _l=1;
Function<Integer, Void> sendRoundsForGamers = (x) -> {sendMsg(gamer1, "Rodada " + x); sendMsg(gamer2, "Rodada " + x); return null;};
sendRoundsForGamers.apply(_l);
requestPlayer(gamer1);
requestPlayer(gamer2);
Optional<Integer> player1_input;
Optional<Integer> player2_input;
while (true) {
player1_input = getSomeGamerInput.apply(first_lambda).apply(inputs_plays);
player2_input = getSomeGamerInput.apply(second_lambda).apply(inputs_plays);
if (play_time.isDone() && !player1_input.isPresent()) {
checkGamerIsAvaliable(gamer1, () -> {
sendMsg(gamer1, "Ops! Você perdeu a chance de jogar deviado ao tempo :#");
make_gamer_lost(gamer1, gamer2);
return null;
});
break;
}
if (play_time.isDone() && !player2_input.isPresent()) {
checkGamerIsAvaliable(gamer2, () -> {
sendMsg(gamer2, "Ops! Você perdeu a chance de jogar deviado ao tempo :#");
make_gamer_lost(gamer2, gamer1);
return null;
});
break;}
if (player1_input.isPresent() && player2_input.isPresent()) {
sendMsg(gamer1, "Seu adversario fez a jogada com uma " + plays.get(player2_input.get()));
sendMsg(gamer2, "Seu adversario fez a jogada com uma " + plays.get(player1_input.get()));
if (player1_input.get() - player2_input.get() == 0) {
if (inputs_plays.first().get().second() - actual_time > inputs_plays.second().get().second() - actual_time) {
pontuation.setSecond(pontuation.second()+1);
sendMsg(gamer2, "Parabéns vc ganhou pq foi mais agíl você tem agora " + pontuation.second() + " pontos");
}
else {
pontuation.setFirst(pontuation.first()+1);
sendMsg(gamer1, "Parabéns vc ganhou pq foi mais agíl você tem agora " + pontuation.first() + " pontos");
}
}
else if (player1_input.get() - player2_input.get() == -2 || player1_input.get() - player2_input.get() == 1) {
pontuation.setFirst(pontuation.first()+1);
sendMsg(gamer1, "Parabéns você esta com " + pontuation.first() + " pontos");
}
else {
pontuation.setSecond(pontuation.second()+1);
sendMsg(gamer2, "Parabéns você esta com " + pontuation.second() + " pontos");
}
if (pontuation.first() >= 3) {make_gamer_lost(gamer2, gamer1); break;}
if (pontuation.second() >= 3) {make_gamer_lost(gamer1, gamer2); break;}
sendRoundsForGamers.apply(++_l);
requestPlayer(gamer1);
requestPlayer(gamer2);
play_time = getPlayFutureFunction();
inputs_plays = getPlayersInput(gamer1, gamer2);
player1_input = getSomeGamerInput.apply(first_lambda).apply(inputs_plays);
player2_input = getSomeGamerInput.apply(second_lambda).apply(inputs_plays);
}
}
// requestPlayer(gamer1);
// requestPlayer(gamer2);
return null;
});
}
public void try_match_with_someone(Gamer t1) {
Gamer g;
sendMsg(t1, t1.getName() + ", você tem " + t1.getPontuation() + " pontos, aguarde enquanto procuramos um oponente para você jogar");
if (state.waiting_gamers.size() > 1) {
g = state.waiting_gamers.poll();
System.out.println(g.toString());
if (g != null) {
startMove(t1, g);
state.waiting_gamers.remove(t1);
}
}
}
public void try_gamer(Tuple<Socket, BufferedReader, PrintWriter> T) throws IOException, InterruptedException {
while (true) {
if ((T.second()).ready() && "Enter".equals((T.second()).readLine())) {
try_match_with_someone(insert_player(T, (T.second()).readLine()));
System.out.println("Player " + state.getID() + " entrou\n");
}
Thread.sleep(1);
}
}
public void init() throws IOException {
serverSocket = new ServerSocket(6666);
state = new State();
}
public static void main(String[] args) throws IOException {
Server server = new Server();
server.init();
server.stand_by();
}
}
import java.net.*;
import java.io.*;
import java.util.Optional;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Callable;
import java.util.function.Function;
import java.util.HashMap;
public class Client {
private Socket clientSocket;
private PrintWriter out;
private BufferedReader in;
static int tolerance = 4;
Timer timer;
private BufferedReader reader;
public class State {
State(int id) {
ID = id;
}
public int getID() {
return ID;
}
private int ID;
}
public class Player {
public Player() {
estado = Optional.empty();
}
public Boolean connected() {
return jogador.estado.isPresent();
}
public Optional<State> estado;
}
//private Function<BufferedReader, Optional<State>> continuation;
private Player jogador = new Player ();
public void startConnection(String ip, int port) throws IOException {
clientSocket = new Socket(ip, port);
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
reader = new BufferedReader(new InputStreamReader(System.in)); // apenas alguns detalhes
}
public void solicitEnter(String msg, String name) throws IOException, InterruptedException {
timer = new Timer();
int buffer;
// System.out.print(in.readLine());
synchronized (jogador) {
out.println(msg);
out.println(name);
jogador.wait(1000*4);
try {
if (in.ready()) {
buffer = Integer.parseInt(in.readLine());
if (buffer == 0x0) {
buffer = Integer.parseInt(in.readLine());
jogador.estado = Optional.of(new State(buffer));
}
}
}
catch(Exception e) {}
}
}
public void stopConnection() throws IOException {
in.close();
out.close();
clientSocket.close();
}
void doIfYourPackageID(int d, Callable<Void> f) throws Exception {
if (d == jogador.estado.get().getID()) {
f.call();
}
}
public void StartGame() throws IOException {
HashMap<String, Integer> plays = new HashMap<>();
plays.put("pedra", 1);
plays.put("papel", 2);
plays.put("tesoura", 3);
if (jogador.connected()) {
new Thread(() ->
{
while (true) {
try {
final String buffer = in.readLine();
final int id = Integer.parseInt(in.readLine());
switch(Integer.parseInt(buffer)) {
case 0x1 :
doIfYourPackageID(id,
() -> {System.out.println("Foi encontrado um adversario para você"); return null;});
break;
case 0x2 :
doIfYourPackageID(id,
() -> {System.out.println(in.readLine()); return null;});
break;
case 0x3 :
doIfYourPackageID(id,
() -> {
System.out.println("Pedra, Papel ou Tesoura?");
do {
final String play = reader.readLine();
if (plays.containsKey(play.toLowerCase())) {
out.println(plays.get(play.toLowerCase()));
break;
}
else {
System.out.println("É pedra, papel ou tesoura. Não elefante! Por favor informe corretamente!");
}
} while (true);
return null;});
break;
case 0x4 :
doIfYourPackageID(id,
() -> {out.println(id); return null;});
break;
default :
Thread.sleep(1);
}
}
catch(Exception e) {
// System.out.println(e);
}
}
}
).start(); //wait a response of the Server
}
else {
/// System.out.println("O servidor recusou sua entrada");
}
}
public static void main (String[] args) throws IOException, InterruptedException {
Client client = new Client();
final String name;
System.out.println("Antes de entrar, me informe seu nome!");
client.startConnection("127.0.0.1", 6666);
name = client.reader.readLine();
client.solicitEnter("Enter", name);
client.StartGame();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment