Word Card Game

 avatar
Darin
plain_text
a year ago
8.9 kB
3
Indexable
Never
package WordCardGame;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

class UserSolution {
	Card[] cards = new Card[10001];
	User[] users = new User[51];
	Map<String, List<Card>> map = new HashMap<>();

	void init(int N, char[][] mWord, char[][] mSubject) {
		for (int i = 0; i < N; i++)
			cards[i + 1] = new Card(i + 1, toStr(mWord[i]), toStr(mSubject[i]));
	}

	void join(int mID, int M, int[] mCardList) {
		users[mID] = new User();
		for (int i = 0; i < M; i++) {
			Card card = cards[mCardList[i]];
			map.computeIfAbsent(card.prefix1, k -> new ArrayList<>()).add(card);
			map.computeIfAbsent(card.prefix2, k -> new ArrayList<>()).add(card);
			users[mID].cards.compute(card, (k, v) -> v == null ? 1 : v + 1);
			card.users.add(mID);
		}
	}

	int playRound(char[] mBeginStr, char[] mSubject) {
		List<Card> list = map.get(toStr(mSubject) + toStr(mBeginStr));
		if (list == null)
			return 0;
		Collections.sort(
				list,
				(a, b) -> a.users.size() == b.users.size() ? a.name
						.compareTo(b.name) : b.users.size() - a.users.size());
		int sum = 0;
		int visit[] = new int[51];
		for (Card card : list) {
			List<Integer> playedThisCard = new ArrayList<>();
			for (int user : card.users) {
				if (visit[user] == 0) {
					visit[user] = 1;
					playedThisCard.add(user);
					sum += card.id;
				}
			}
			double point = Math.pow(playedThisCard.size() - 1, 2);
			for (int id : playedThisCard) {
				users[id].point += point;
				if (users[id].cards.compute(card, (k, v) -> v == 1 ? null
						: v - 1) == null)
					card.users.remove(id);
			}
		}
		return sum;
	}

	int leave(int mID) {
		for (Card card : users[mID].cards.keySet())
			card.users.remove(mID);
		return users[mID].point;
	}

	String toStr(char[] s) {
		return new String(s).trim();
	}
}

class User {
	Map<Card, Integer> cards = new HashMap<>();
	int point;
}

class Card {
	int id;
	String name, prefix1, prefix2;
	Set<Integer> users = new HashSet<>();

	Card(int mId, String mName, String mSubject) {
		id = mId;
		name = mName;
		prefix1 = mSubject + mName.charAt(0);
		prefix2 = prefix1 + mName.charAt(1);
	}
}

//[Problem Description]
//There are word cards.
//A word, and a keyword associated with that word are written on each card.
//Each player holds several cards, and each player may have a number of same cards.
//Players may hold different number of cards.
//Players can see one another’s cards.
//In each round, a keyword and a starting character string are given. Each player submits one card that satisfies the below conditions among the cards the player has. If a player does not have any cards that satisfy the below conditions, the player is not required to submit a card.
//① A player submits a card with the word that begins with the starting character string and the keyword that is same as the presented one, among the cards the player has, if the player has such a card.
//② If the player has multiple cards that meet condition ①, among those cards, the player submits the card with the highest number of players who also have the same card as that card. (Regardless of whether a player has one or multiple same cards, one player is counted as one.)
//③ If the player has several cards that meet condition ②, among those cards, the player submits one of the cards with the word that precedes all others in lexicographic order.
//All players submit their cards at the same time.
//Scores to get are calculated after comparing the submitted cards. Then, the submitted cards are discarded. Discarded cards are never used again in the next rounds.
//Let’s think about a case where a player holds cards like in [Fig. 1].
//If the starting character string is “ba” and the keyword is “food”, submit the card “banana/[food]”.
//If the starting character string is “ba” and the keyword is “sport”, between “baseball/[sport]” and “basketball/[sport]”, the player chooses and submits the card with the highest number of players who also have the same card as that card. If the number of players who have "baseball/[sport]" equals to the number of players with "basketball/[sport]", submit “baseball/[sport]” given that “baseball” comes before “basketball” in lexicographic order.
//If the starting character string is “z” and the keyword is “product”, do not submit any card as there is no card that start with “z” with the keyword of “product”.
//The following shows how each player gets scores in this round.
//If there are other players who submitted the same card as the card submitted by a player, the score to be given is the square of the number of the other players. The player excludes oneself when counting the number of players.
//For example, as for the case where player A submits the card on which “baseball/[sport]” is written, if 2 other players submit this same card, player A gets 4 points.
//If there are no other players who submitted the same card or if no card was submitted, no points are given.
//In the middle of a game, players may join in or leave the game freely. When they take part in the game, their initial scores are 0. Once players leave the game, they are not allowed to join in again. When they leave the game, they must return all cards they have.
//Write a program that simulates this word game.
//Implement each required function by referring to the following API description.
//The following is the description of API to be written in the User Code.
//void init(int N, char mWordList[][], char mSubjectList[][])
//This initialization function for each test case is called once in the beginning of each test case.
//The game uses N types of cards, and card’s numbers from 1 to N differentiate cards of each type. The word and the keyword written on the card of which the number is i are mWordList[i – 1] and mSubjectList[i – 1] respectively. (1 ≤ i ≤ N)
//mWordList[] and mSubjectList[] are character strings consisting of English lowercase letters. Their lengths are greater than or equal to 2 but less than or equal to 10. The character strings end with ‘\0’ which is not included in the length.
//All words given by mWordList are different. In other words, if a ≠ b, mWordList[a] ≠ mWordList[b].
//There are a maximum of 20 different keywords among the keywords given by mSubjectList.
//Initially, there are no players.
//Parameters
//  N : the number of card types used in the game (1 ≤ N ≤ 10,000)
//  mWordList : the list of words written on cards (2 ≤ |mWordList[]| ≤ 10, |a| means the length of character string a.)
//  mSubjectList : the list of keywords written on cards (2 ≤ |mSubjectList[]| ≤ 10)
//void join(int mID, int M, int mCardList[])
//A player with the ID of mID participates in the game.
//When joining in, player mID has a total of M cards, and the cards are given as mCardList[0] ~ mCardList[M – 1]. mCardList[] means the card’s number.
//The initial score of player mID is 0.
// 
//Players may have multiple same cards among the cards they have.
//When called at first, mID is 1. Then, it increases by 1 every time it is called.
// 
//Parameters
//  mID : the ID of the player who joins in (1 ≤ mID ≤ 50)
//  M : the number of cards held by the player who joins in (1 ≤ M ≤ 1,500)
//  mCardList : the list of cards held by the player who joins in (1 ≤ mCardList[] ≤ N)
//int playRound(char mBeginStr[], char mSubject[])
//One round is played. The starting character string of this round is mBeginStr and the keyword is mSubject.
//Please refer to the above description for explanations about how to play each round. 
//Return the sum of the submitted cards’ numbers after the end of the round. If there is no card submitted by all players, return 0.
//mBeginStr is a character string consisting of English lowercase letters and the length of the string is greater than or equal to 1 but less than or equal to 2. The character string ends with ‘\0’ which is not included in the length.
//mSubject is one of the character strings in array mSubjectList passed when calling init().
//Parameters
//  mBeginStr : the starting character string of the round (1 ≤ |mBeginStr| ≤ 2)
//  mSubject : the keyword of the round (2 ≤ |mSubject| ≤ 10)
//Returns
//  the sum of the submitted cards’ numbers after the end of the round
//int leave(int mID)
//Return the score player mID got after the player leaves the game.
//This function is never called with the mID of a player who did not join in or who already left.
//Parameters
//  mID : the ID of the player to leave (1 ≤ mID ≤ 50)
//Returns
//  The score player mID got