Last active
September 30, 2019 21:52
-
-
Save caotic123/0e033aa597ef93c1000a4e5094a792af to your computer and use it in GitHub Desktop.
A *super simply* multiplayer jokenpo oriented by sockets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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