Untitled

mail@pastecode.io avatar
unknown
plain_text
7 months ago
6.5 kB
1
Indexable
Never
package sezione15.javaCollections.esercitazione3.cardChallenge.model;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Random;

import sezione15.javaCollections.esercitazione3.cardChallenge.exception.InvalidFaceException;

/**
 * Represent a poker card
 * 
 * @author Nicola Colasanto
 *
 */
public class Card implements Comparable<Card> {

	/**
	 * The suit of a poker card
	 * 
	 * @author Nicola Colasanto
	 *
	 */
	public enum Suit {
		CLUB, DIAMOND, HEART, SPADE;

		/**
		 * @return the relative image
		 */
		public char getImage() {
			return switch (this) {
			case DIAMOND -> (char) 9830;
			case HEART -> (char) 9829;
			case SPADE -> (char) 9824;
			default -> (char) 9827;
			};
		}
	}

	/**
	 * The valid letter of a poker card
	 * 
	 * @author Nicola Colasanto
	 *
	 */
	private enum Letter {
		A, Q, J, K;

		/**
		 * @return the relative value
		 */
		public int getRank() {
			return switch (this) {
			case J -> 9;
			case Q -> 10;
			case K -> 11;
			case A -> 12;
			default -> 0;
			};
		}
	}

	// The char that represent the suit of the card
	private char suit;
	// The face of the card
	private String face;
	// The value of the card
	private int rank;

	/**
	 * Create a poker card
	 * 
	 * @param suit
	 * @param face it must be between 2 and 10 or J, Q, K, A. It can contains
	 *              spaces and it's not case sensitive.
	 */
	public Card(Suit suit, String face) {
		// Remove all spaces
		face = face.replaceAll(" ", "");
		// Check if the String passed is valid and set the relative value of this card
		checkValidFaceAndSetRank(face);
		// Get and set the  of this card based on the suit passed
		this.suit = suit.getImage();
	}
	
	public char getSuit() {
		return suit;
	}

	@Override
	public boolean equals(Object obj) {
		if(this == obj) 
			return true;
		
		if(obj == null || this.getClass() != obj.getClass()) {
			return false;
		}
		
		var card2 = (Card) obj;
		return (suit == card2.suit) && (face.equals(card2.face));
	}

	public String getFace() {
		return face;
	}


	public int getRank() {
		return rank;
	}

	@Override
	public String toString() {
		return "%s%c(%d)".formatted(face, suit, rank);
	}

	/**
	 * The cards are sorted according to the same suit and the natural numerical order of their value.
	 */
	@Override
	public int compareTo(Card cardToCompare) {
		var suit1 = this.suit + "";
		var suit2 = cardToCompare.suit + "";
		var result = suit1.compareTo(suit2);
		if (result == 0) {
			Integer rank1 = this.rank;
			Integer rank2 = cardToCompare.rank;
			result = rank1.compareTo(rank2);
		}
		return result;
	}
	
	/**
	 * Check if the String passed is valid and set the relative value of this card
	 * 
	 * @param face the string to check
	 */
	private void checkValidFaceAndSetRank(String face) {
		try {
			int value = Integer.parseInt(face);
			// If its a number but its not in the range, throw the exception
			if (value < 2 || value > 10) {
				throw new InvalidFaceException(InvalidFaceException.INVALID_FACE_NUMBER);
			} else {
				// Set the face corresponding to the valid number passed
				this.face = face;
				// Set the relative value
				rank = value - 2;
			}
		} catch (NumberFormatException e) {
			// At this point the string passed its not numeric.
			// Check if the first letter of the string is a valid card letter, if its so set the realtive 
			// value, if its not throw the exception.
			if (!checkValidFirstLetter(face)) {
				throw new InvalidFaceException(InvalidFaceException.INVALID_FACE_LETTER);
			}
		}
	}

	/**
	 * Check if the first letter of the string is a valid poker card letter, if it's so set the relative 
	 * value, if it's return false
	 * 
	 * @param face the string to check
	 * @return true if it is, false otherwise
	 */
	private boolean checkValidFirstLetter(String face) {
		// Set the string to upper case and get only the first char (in String)
		face = face.toUpperCase().substring(0, 1);
		// Get all suits values
		var letters = Letter.values();
		
		// Check if the string its equal at one of the letter values
		for (var l : letters) {
			if (face.equals((l).toString())) {
				// Set the face corresponding to the valid letter passed
				this.face = face;
				// Set the relative value of the letter
				rank = l.getRank();
				return true;
			}
		}
		return false;
	}
	

	/**
	 * Create the standard deck of 52 poker cards
	 * 
	 * @return deck 
	 */
	public static ArrayList<Card> getStandardDeck() {
		var deck = new ArrayList<Card>();
		var suits = Suit.values();
		// For each suits, add to the deck all the card form 2 to A
		Arrays.asList(suits).forEach(s -> {
			for (int i = 0; i < 13; i++) {
				if (i < 9) {
					deck.add(new Card(s, (i + 2) + ""));
				} else {
					switch (i) {
					case 10 -> deck.add(new Card(s, "Q"));
					case 11 -> deck.add(new Card(s, "K"));
					case 12 -> deck.add(new Card(s, "A"));
					default -> deck.add(new Card(s, "J"));
					}
				}
			}
		});
		return deck;
	}

	/**
	 * Print an ordered deck, a row for each suit
	 * 
	 * @param description of the deck
	 * @param deck to print
	 */
	public static void printDeck(String description, List<Card> deck) {
		Objects.requireNonNull(description);
		Objects.requireNonNull(deck);

		// Order based on the compareTo of the card
		deck.sort(Comparator.naturalOrder());
		
		// If description is not empty, print it
		if (!description.isBlank())
			System.out.println(description);
		
		// The suit of the first card
		var suit = deck.get(0).suit + "";
		
		// In the each row will be print the same suit cards
		for (var card : deck) {
			// Check if the suit is the same of the previous one
			if (suit.equals(card.suit + "")) {
				System.out.print(card + " ");
			} else {
				// If it's not, change row
				System.out.println();
				System.out.print(card + " ");
				suit = card.suit + "";
			}
		}
		// Change the row
		System.out.println();
	}
	
	public static Card getRandomCard() {
		String[] faces = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "A", "J", "Q", "K"};
		Suit[] suits = Suit.values();
		Random random = new Random();
		return new Card(suits[random.nextInt(0,suits.length)], faces[random.nextInt(0,faces.length)]);
	}

}