package fr.ynerant.tarot; import android.annotation.SuppressLint; import android.preference.PreferenceManager; import androidx.annotation.NonNull; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Executors; import fr.ynerant.tarot.ui.games.GameInfoFragment; public class Game { private static final Gson GSON; @SuppressLint("UseSparseArrays") private static final Map GAMES = new HashMap<>(); @SuppressWarnings("unused") private int id; @SuppressWarnings("unused") private Date date; private GameType gameType; @SuppressWarnings("unused") private Player player1, player2, player3, player4, player5, player6; private List players; @SuppressWarnings("unused") private int nb_players; private Bet bet; private Player attacker; private Player follower; private int attack_score; // private boolean little_end, twenty_one, excuse; private int ends; @SuppressWarnings("unused") private int handle1, handle2, handle3, handle4, handle5, handle6; private List handles; @SuppressWarnings("unused") private boolean misery1, misery2, misery3, misery4, misery5, misery6; private List miseries; private int little_end; private boolean chelem_announced, chelem_realized; @SuppressWarnings("unused") private int score1, score2, score3, score4, score5, score6; private List points; static { GSON = new GsonBuilder().registerTypeAdapter(Player.class, new TypeAdapter() { @Override public void write(JsonWriter out, Player value) throws IOException { if (value == null) out.nullValue(); else out.value(value.getId()); } @Override public Player read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { in.nextNull(); return null; } int id = in.nextInt(); if (id == 0) return null; return Player.getPlayerById(id); } }).registerTypeAdapter(Game.GameType.class, new TypeAdapter() { @Override public void write(JsonWriter out, GameType value) throws IOException { if (value == null) out.nullValue(); else out.value(value.getNbPlayers()); } @Override public GameType read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { in.nextNull(); return null; } return Game.GameType.values()[3 + in.nextInt()]; } }).registerTypeAdapter(Date.class, new TypeAdapter() { @SuppressLint("SimpleDateFormat") final DateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override public void write(JsonWriter out, Date value) throws IOException { if (value == null) out.nullValue(); else out.value(FORMAT.format(value)); } @Override public Date read(JsonReader in) throws IOException { try { return FORMAT.parse(in.nextString()); } catch (ParseException e) { e.printStackTrace(); return null; } } }).create(); } public int getId() { return id; } public Date getDate() { return date; } public GameType getGameType() { return gameType; } public void setGameType(GameType gameType) { this.gameType = gameType; } public List getPlayers() { return players; } public void setPlayers(List players) { this.players = players; } public Bet getBet() { return bet; } public void setBet(Bet bet) { this.bet = bet; } public Player getAttacker() { return attacker; } public void setAttacker(Player attacker) { this.attacker = attacker; } public Player getFollower() { return follower; } public void setFollower(Player follower) { this.follower = follower; } public int getAttackScore() { return attack_score; } public void setAttackScore(int attack_score) { this.attack_score = attack_score; } public int getEnds() { return ends; } public void setEnds(int ends) { this.ends = ends; } public int getHandle(Player player) { return handles.get(players.indexOf(player)); } public List getHandles() { return handles; } public void setHandles(List handles) { this.handles = handles; } public List getMiseries() { return miseries; } public void setMiseries(List miseries) { this.miseries = miseries; } public int getLittleEnd() { return little_end; } public void setLittleEnd(int little_end) { this.little_end = little_end; } public boolean isChelemAnnounced() { return chelem_announced; } public void setChelemAnnounced(boolean chelem_announced) { this.chelem_announced = chelem_announced; } public boolean isChelemRealized() { return chelem_realized; } public void setChelemRealized(boolean chelem_realized) { this.chelem_realized = chelem_realized; } public int getPoints(Player player) { return points.get(players.indexOf(player)); } public int getPoints(int i) { return points.get(i); } public void calculateScores() { // int ends = (little_end ? 1 : 0) + (twenty_one ? 1 : 0) + (excuse ? 1 : 0); int bound = ends == 0 ? 56 : ends == 1 ? 51 : ends == 2 ? 41 : 36; boolean win = attack_score >= bound; int gain = Math.abs(attack_score - bound); int score = 25; score += gain; score *= bet.getMultiplier(); for (int i = 0; i < getGameType().getNbPlayers(); ++i) { Player player = getPlayers().get(i); if (getHandle(player) > 0) score += 10 * (getHandle(player) + 1); } if (!win) score = -score; if (little_end != 0 && (players.get(little_end - 1) == attacker || players.get(little_end - 1) == follower)) score += 10; else if (little_end != 0) score -= 10; if (chelem_announced) { if (chelem_realized) score += 400; else score -= 200; } else if (chelem_realized) score += 200; Map scores = new HashMap<>(); for (int i = 0; i < getGameType().getNbPlayers(); ++i) { Player p = players.get(i); int playerScore = 0; if (p != attacker && p != follower) playerScore = -score; else { if (p == attacker && p == follower) playerScore += (getGameType().getNbPlayers() - 1) * score; else if (p == attacker) playerScore += (getGameType().getNbPlayers() - 1 - (follower == null ? 0 : 2)) * score; else playerScore += score; } scores.put(p, playerScore); } for (int i = 0; i < getGameType().getNbPlayers(); ++i) { if (getMiseries().get(i)) { //noinspection ConstantConditions scores.put(players.get(i), scores.get(players.get(i)) + 10 * (getGameType().getNbPlayers() - 1)); for (int j = 0; j < getGameType().getNbPlayers(); ++j) { if (i == j) continue; //noinspection ConstantConditions scores.put(players.get(j), scores.get(players.get(j)) - 10); } } } points = new ArrayList<>(); for (int i = 0; i < getGameType().getNbPlayers(); ++i) { points.add(scores.get(players.get(i))); } } public String toJson() { return GSON.toJson(this); } @NonNull @Override public String toString() { SimpleDateFormat format = new SimpleDateFormat("dd MMMM yyyy HH:mm:ss"); String str = "Partie à " + getGameType().getNbPlayers() + " joueurs : "; for (Player player : getPlayers()) str += player.getName() + ", "; str += getBet().toString() + " de " + getAttacker().getName() + " " + (getAttackScore() >= (ends == 0 ? 56 : ends == 1 ? 51 : ends == 2 ? 41 : 36) ? "gagnée" : "chutée") + ", "; str += format.format(getDate()); return str; } public static Game getGameById(int id) { return GAMES.get(id); } public static List getAllGames() { List list = new ArrayList<>(GAMES.values()); list.sort(new Comparator() { @Override public int compare(Game o1, Game o2) { return o2.getDate().compareTo(o1.getDate()); } }); return list; } public static void updateGames() { Executors.newSingleThreadExecutor().execute(new Runnable() { @Override public void run() { try { URL url = new URL("https://ynerant.fr/tarot/game.php"); final HttpURLConnection co = (HttpURLConnection) url.openConnection(); co.setRequestMethod("POST"); co.setRequestProperty("token", PreferenceManager.getDefaultSharedPreferences(MainActivity.INSTANCE).getString("token", null)); co.connect(); final List games = GSON.fromJson(new InputStreamReader(co.getInputStream()), new TypeToken>(){}.getType()); GAMES.clear(); for (Player p : Player.getAllPlayers()) { for (GameType type : GameType.values()) p.setScore(type, 0); } for (Game g : games) { GAMES.put(g.getId(), g); g.setGameType(GameType.values()[g.nb_players - 3]); g.players = new ArrayList<>(); g.getPlayers().add(g.player1); g.getPlayers().add(g.player2); g.getPlayers().add(g.player3); if (g.player4 != null) g.getPlayers().add(g.player4); if (g.player5 != null) g.getPlayers().add(g.player5); if (g.player6 != null) g.getPlayers().add(g.player6); g.handles = new ArrayList<>(); g.getHandles().add(g.handle1); g.getHandles().add(g.handle2); g.getHandles().add(g.handle3); if (g.player4 != null) g.getHandles().add(g.handle4); if (g.player5 != null) g.getHandles().add(g.handle5); if (g.player6 != null) g.getHandles().add(g.handle6); g.miseries = new ArrayList<>(); g.getMiseries().add(g.misery1); g.getMiseries().add(g.misery2); g.getMiseries().add(g.misery3); if (g.player4 != null) g.getMiseries().add(g.misery4); if (g.player5 != null) g.getMiseries().add(g.misery5); if (g.player6 != null) g.getMiseries().add(g.misery6); g.calculateScores(); for (Player p : g.getPlayers()) p.addScore(g.getGameType(), g.getPoints(p)); } } catch (IOException ex) { ex.printStackTrace(); } } }); } public enum GameType { THREE_PLAYERS, FOUR_PLAYERS, FIVE_PLAYERS, SIX_PLAYERS; public int getNbPlayers() { return ordinal() + 3; } public static GameType getGameType(int players) { switch (players) { case 3: return THREE_PLAYERS; case 4: return FOUR_PLAYERS; case 5: return FIVE_PLAYERS; case 6: return SIX_PLAYERS; default: throw new IllegalArgumentException("A game must have between 3 and 6 players"); } } } public enum Bet { SMALL(1), GUARD(2), GUARD_WITHOUT(4), GUARD_AGAINST(6); private final int multiplier; Bet(int multiplier) { this.multiplier = multiplier; } public int getMultiplier() { return multiplier; } @NonNull @Override public String toString() { switch (this) { case SMALL: return "Petite"; case GUARD: return "Garde"; case GUARD_WITHOUT: return "Garde sans"; case GUARD_AGAINST: return "Garde contre"; default: return "null"; } } } }