diff --git a/.github/workflows/Backend-CD-Dev.yml b/.github/workflows/Backend-CD-Dev.yml index 89497f1f3..d5d31cc7a 100644 --- a/.github/workflows/Backend-CD-Dev.yml +++ b/.github/workflows/Backend-CD-Dev.yml @@ -66,5 +66,5 @@ jobs: docker run -d -p 8080:8080 --name server \ -e JAVA_OPTS="-XX:InitialRAMPercentage=70.0 -XX:MaxRAMPercentage=70.0" \ -e TZ=Asia/Seoul \ - -e SPRING_PROFILES_ACTIVE=local \ + -e SPRING_PROFILES_ACTIVE=dev \ ${{ secrets.DOCKER_DEV_SERVER_IMAGE }} diff --git a/.github/workflows/Backend-CD-Prod.yml b/.github/workflows/Backend-CD-Prod.yml index a9ce38aa7..5640a3a86 100644 --- a/.github/workflows/Backend-CD-Prod.yml +++ b/.github/workflows/Backend-CD-Prod.yml @@ -17,7 +17,7 @@ jobs: build: needs: test - runs-on: cd + runs-on: [cd, app-a] steps: - name: Checkout @@ -50,7 +50,7 @@ jobs: deploy: needs: build - runs-on: cd + runs-on: [cd, app-a] steps: - name: Change permission diff --git a/.github/workflows/Backend-CI.yml b/.github/workflows/Backend-CI.yml index 582bb0275..90be30774 100644 --- a/.github/workflows/Backend-CI.yml +++ b/.github/workflows/Backend-CI.yml @@ -28,6 +28,7 @@ jobs: - name: Remove Containers run: | docker ps -aq | xargs -r docker rm -vf + docker builder prune - name: Set up Test MongoDB working-directory: ./backend/pokerogue/src/main/resources/ diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/controller/AbilityController.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/controller/AbilityController.java index bab16c4a8..3bccc02ff 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/controller/AbilityController.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/controller/AbilityController.java @@ -25,7 +25,12 @@ public ApiResponse> abilityList() { @GetMapping("/api/v1/ability2/{id}") public ApiResponse abilityDetails(@PathVariable("id") String id) { - log.info("---- URI : {}, Param : {}", "/api/v1/ability/{id}", id); + log.info( + "---- URI : {}, Param : {}, ThreadName : {}", + "/api/v1/ability/{id}", + id, + Thread.currentThread().getName() + ); return new ApiResponse<>("특성 정보 불러오기에 성공했습니다.", abilityService.findAbilityDetails(id)); } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/data/Ability.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/data/Ability.java index 10539eaf2..5c829c78b 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/data/Ability.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/data/Ability.java @@ -1,14 +1,16 @@ package com.pokerogue.helper.ability.data; -import com.pokerogue.helper.pokemon.data.InMemoryPokemon; import java.util.List; +import lombok.AccessLevel; import lombok.Getter; +import lombok.NoArgsConstructor; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; @Getter @Document(collection = "ability") +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class Ability { @Id @@ -30,7 +32,7 @@ public class Ability { private int generation; @Field("pokemonIds") - private List pokemonIds; + private List pokemonIds; @Field("isBypassFaint") private Boolean isBypassFaint; @@ -38,13 +40,7 @@ public class Ability { @Field("isIgnorable") private Boolean isIgnorable; - // Todo: 지우기 - private List inMemoryPokemons; - - public Ability(String id, String name, String description, List inMemoryPokemons) { - this.id = id; - this.name = name; - this.description = description; - this.inMemoryPokemons = inMemoryPokemons; + public boolean isPresent() { + return !id.equals("none"); } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/data/AbilityInfo.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/data/AbilityInfo.java deleted file mode 100644 index 9041aa682..000000000 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/data/AbilityInfo.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.pokerogue.helper.ability.data; - -import java.util.List; -import lombok.Getter; - -@Getter -public class AbilityInfo { - - private final String id; - private final String name; - private final String description; - private final List pokemons; - private final List pokedexNumbers; - - public AbilityInfo(String abilityInfo) { - String[] abilityInfos = abilityInfo.split(" / "); - this.id = abilityInfos[0]; - this.name = abilityInfos[1]; - this.description = abilityInfos[2]; - this.pokemons = List.of(abilityInfos[4].split(" , ")); - this.pokedexNumbers = List.of(abilityInfos[5].split(" , ")); - } -} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/dto/AbilityDetailResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/dto/AbilityDetailResponse.java index 2e7f88771..7b2924a16 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/dto/AbilityDetailResponse.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/dto/AbilityDetailResponse.java @@ -10,6 +10,6 @@ public record AbilityDetailResponse( ) { public static AbilityDetailResponse of(Ability ability, List pokemons) { - return new AbilityDetailResponse(ability.getName(), ability.getDescription(), pokemons); + return new AbilityDetailResponse(ability.getKoName(), ability.getDescription(), pokemons); } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/dto/AbilityPokemonResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/dto/AbilityPokemonResponse.java index 81e85c435..798a7532c 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/dto/AbilityPokemonResponse.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/dto/AbilityPokemonResponse.java @@ -1,5 +1,6 @@ package com.pokerogue.helper.ability.dto; +import com.pokerogue.helper.pokemon.data.Pokemon; import java.util.List; public record AbilityPokemonResponse( @@ -9,4 +10,17 @@ public record AbilityPokemonResponse( String image, List pokemonTypeResponses ) { + public static AbilityPokemonResponse of( + Pokemon pokemon, + String image, + List pokemonTypeResponses + ) { + return new AbilityPokemonResponse( + pokemon.getId(), + (long) pokemon.getPokedexNumber(), + pokemon.getKoName(), + image, + pokemonTypeResponses + ); + } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/dto/AbilityResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/dto/AbilityResponse.java index 97e2ca9c5..a12c422a3 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/dto/AbilityResponse.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/dto/AbilityResponse.java @@ -5,6 +5,6 @@ public record AbilityResponse(String id, String koName, String description) { public static AbilityResponse from(Ability ability) { - return new AbilityResponse(ability.getId(), ability.getName(), ability.getDescription()); + return new AbilityResponse(ability.getId(), ability.getKoName(), ability.getDescription()); } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/dto/AbilityTypeResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/dto/AbilityTypeResponse.java index cb9c8657e..0a2220ec0 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/dto/AbilityTypeResponse.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/dto/AbilityTypeResponse.java @@ -1,4 +1,10 @@ package com.pokerogue.helper.ability.dto; +import com.pokerogue.helper.type.data.Type; + public record AbilityTypeResponse(String typeLogo, String typeName) { + + public static AbilityTypeResponse from(Type type) { + return new AbilityTypeResponse(type.getImage(), type.getKoName()); + } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/repository/InMemoryAbilityRepository.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/repository/InMemoryAbilityRepository.java deleted file mode 100644 index 8916eb9ab..000000000 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/repository/InMemoryAbilityRepository.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.pokerogue.helper.ability.repository; - -import com.pokerogue.helper.ability.data.Ability; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Repository; - -@Repository -@RequiredArgsConstructor -public class InMemoryAbilityRepository { - - private final Map abilities; - - public InMemoryAbilityRepository() { - this.abilities = new HashMap<>(); - } - - public void save(Ability ability) { - abilities.put(ability.getId(), ability); - } - - public List findAll() { - return abilities.values().stream() - .toList(); - } - - public Optional findById(String id) { - return Optional.ofNullable(abilities.get(id)); - } -} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/service/AbilityService.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/service/AbilityService.java index 5f97f9886..fc586e13f 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/service/AbilityService.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/ability/service/AbilityService.java @@ -6,11 +6,12 @@ import com.pokerogue.helper.ability.dto.AbilityPokemonResponse; import com.pokerogue.helper.ability.dto.AbilityResponse; import com.pokerogue.helper.ability.dto.AbilityTypeResponse; -import com.pokerogue.helper.ability.repository.InMemoryAbilityRepository; -import com.pokerogue.helper.type.data.Type; +import com.pokerogue.helper.ability.repository.AbilityRepository; import com.pokerogue.helper.global.exception.ErrorMessage; import com.pokerogue.helper.global.exception.GlobalCustomException; -import java.util.ArrayList; +import com.pokerogue.helper.pokemon.data.Pokemon; +import com.pokerogue.helper.pokemon.repository.PokemonRepository; +import com.pokerogue.helper.type.data.Type; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -20,43 +21,45 @@ public class AbilityService { private final S3Service s3Service; - private final InMemoryAbilityRepository inMemoryAbilityRepository; + private final AbilityRepository abilityRepository; + private final PokemonRepository pokemonRepository; public List findAbilities() { - return inMemoryAbilityRepository.findAll().stream() + return abilityRepository.findAll().stream() + .filter(Ability::isPresent) .map(AbilityResponse::from) .toList(); } public AbilityDetailResponse findAbilityDetails(String id) { - Ability ability = inMemoryAbilityRepository.findById(id) + Ability ability = abilityRepository.findById(id) .orElseThrow(() -> new GlobalCustomException(ErrorMessage.POKEMON_ABILITY_NOT_FOUND)); - List abilityPokemonResponses = ability.getInMemoryPokemons().stream() - .map(abilityPokemon -> new AbilityPokemonResponse( - abilityPokemon.id(), - Long.parseLong(abilityPokemon.speciesId()), - abilityPokemon.koName(), - s3Service.getPokemonImageFromS3(abilityPokemon.id()), - getAbilityTypeResponses(abilityPokemon.firstType(), abilityPokemon.secondType()) + List abilityPokemonIds = ability.getPokemonIds(); + List pokemons = pokemonRepository.findAllById(abilityPokemonIds); + validateExistAllPokemonId(abilityPokemonIds, pokemons); + List abilityPokemonResponses = pokemons.stream() + .map(pokemon -> AbilityPokemonResponse.of( + pokemon, + s3Service.getPokemonImageFromS3(pokemon.getImageId()), + getAbilityTypeResponses(pokemon.getTypes()) )) .toList(); return AbilityDetailResponse.of(ability, abilityPokemonResponses); } - private List getAbilityTypeResponses(String firstType, String secondType) { - List abilityTypeResponses = new ArrayList<>(); - if (!firstType.equals("Type.undefined") && !firstType.isEmpty()) { - abilityTypeResponses.add(new AbilityTypeResponse(Type.findByEngName(firstType) - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.POKEMON_TYPE_NOT_FOUND)).getImage(), - firstType)); - } - if (!secondType.equals("Type.undefined") && !secondType.isEmpty()) { - abilityTypeResponses.add(new AbilityTypeResponse(Type.findByEngName(secondType) - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.POKEMON_TYPE_NOT_FOUND)).getImage(), - secondType)); + private static void validateExistAllPokemonId( + List abilityPokemonIds, + List abilityPokemonResponses + ) { + if (abilityPokemonIds.size() != abilityPokemonResponses.size()) { + throw new GlobalCustomException(ErrorMessage.POKEMON_NOT_FOUND); } + } - return abilityTypeResponses; + private List getAbilityTypeResponses(List types) { + return types.stream() + .map(AbilityTypeResponse::from) + .toList(); } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/data/BattleMove.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/data/BattleMove.java index 276a095e0..44beac667 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/data/BattleMove.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/data/BattleMove.java @@ -1,5 +1,6 @@ package com.pokerogue.helper.battle.data; +import com.pokerogue.helper.move.data.MoveCategory; import com.pokerogue.helper.type.data.Type; public record BattleMove( diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/dto/BattleResultResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/dto/BattleResultResponse.java index 363670088..25170edab 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/dto/BattleResultResponse.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/dto/BattleResultResponse.java @@ -1,5 +1,9 @@ package com.pokerogue.helper.battle.dto; +import com.pokerogue.helper.move.data.Move; +import com.pokerogue.helper.move.data.MoveCategory; +import com.pokerogue.helper.type.data.Type; + public record BattleResultResponse( int power, double multiplier, @@ -10,4 +14,20 @@ public record BattleResultResponse( String moveCategory, boolean isPreemptive ) { + + public static BattleResultResponse from(Move move, double multiplier, double accuracy, boolean isPreemptive) { + Type moveType = move.getType(); + MoveCategory moveCategory = move.getMoveCategory(); + + return new BattleResultResponse( + move.getPower(), + multiplier, + accuracy, + move.getName(), + move.getEffect(), + moveType.getKoName(), + moveCategory.getName(), + isPreemptive + ); + } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/service/BattleCalculator.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/service/BattleCalculator.java index ea8150b81..ad0761bf5 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/service/BattleCalculator.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/service/BattleCalculator.java @@ -35,12 +35,8 @@ public double calculateTotalMultiplier( return BattleMultiplier.DEFAULT_MULTIPLIER.getDoubleValue(); } - Type moveType = Type.valueOf(move.getType().toUpperCase()); // Todo - List rivalPokemonTypes = rivalPokemon.getTypes() - .stream() // Todo - .map(String::toUpperCase) - .map(Type::valueOf) - .toList(); + Type moveType = move.getType(); + List rivalPokemonTypes = rivalPokemon.getTypes(); BattleMultiplier weatherMultiplier = getWeatherMultiplier(weather, moveType); BattleMultiplier sameTypeBonusMultiplier = getSameTypeBonusMultiplier(moveType, myPokemon); BattleMultiplier typeMatchingMultiplier = getTypeMatchingMultiplier(moveType, rivalPokemonTypes); @@ -63,11 +59,13 @@ private BattleMultiplier getSameTypeBonusMultiplier(Type moveType, Pokemon myPok } private BattleMultiplier getTypeMatchingMultiplier(Type moveType, List rivalPokemonTypes) { - List typeMatchingMultipliers = typeMultiplierProvider.getAllByTypeMatchings(moveType, rivalPokemonTypes); + List typeMatchingMultipliers = typeMultiplierProvider.getAllByTypeMatchings(moveType, + rivalPokemonTypes); return BattleMultiplier.multiply(typeMatchingMultipliers.toArray(EMPTY_BATTLE_MULTIPLIER_ARRAY)); } - private BattleMultiplier applyStrongWindMultiplier(BattleMultiplier totalMultiplier, Type moveType, List rivalPokemonTypes) { + private BattleMultiplier applyStrongWindMultiplier(BattleMultiplier totalMultiplier, Type moveType, + List rivalPokemonTypes) { BattleMultiplier strongWindMultiplier = typeMultiplierProvider.getByStrongWind(moveType, rivalPokemonTypes); return BattleMultiplier.multiply(totalMultiplier, strongWindMultiplier); } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/service/BattleService.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/service/BattleService.java index 1b3ffe789..c307cf505 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/service/BattleService.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/service/BattleService.java @@ -8,7 +8,6 @@ import com.pokerogue.helper.move.repository.MoveRepository; import com.pokerogue.helper.pokemon.data.Pokemon; import com.pokerogue.helper.pokemon.repository.PokemonRepository; -import com.pokerogue.helper.type.data.Type; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -33,21 +32,11 @@ public BattleResultResponse calculateBattleResult( .orElseThrow(() -> new GlobalCustomException(ErrorMessage.POKEMON_NOT_FOUND)); Move move = moveRepository.findById(myMoveId) .orElseThrow(() -> new GlobalCustomException(ErrorMessage.MOVE_NOT_FOUND)); - Type moveType = Type.valueOf(move.getType().toUpperCase()); // Todo double finalAccuracy = battleCalculator.calculateAccuracy(move, weather); double totalMultiplier = battleCalculator.calculateTotalMultiplier(move, weather, rivalPokemon, myPokemon); boolean isPreemptive = battleCalculator.decidePreemptiveAttack(rivalPokemon, myPokemon); - return new BattleResultResponse( - move.getPower(), - totalMultiplier, - finalAccuracy, - move.getName(), - move.getEffect(), - moveType.getKoName(), - move.getMoveCategory(), - isPreemptive - ); + return BattleResultResponse.from(move, totalMultiplier, finalAccuracy, isPreemptive); } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/service/TypeMultiplierProvider.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/service/TypeMultiplierProvider.java index f50e95f9e..97b93674b 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/service/TypeMultiplierProvider.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/service/TypeMultiplierProvider.java @@ -1,11 +1,11 @@ package com.pokerogue.helper.battle.service; -import com.pokerogue.helper.battle.data.TypeMatching; -import com.pokerogue.helper.battle.repository.TypeMatchingRepository; import com.pokerogue.helper.global.exception.ErrorMessage; import com.pokerogue.helper.global.exception.GlobalCustomException; import com.pokerogue.helper.pokemon.data.Pokemon; +import com.pokerogue.helper.type.collection.TypeMatching; import com.pokerogue.helper.type.data.Type; +import com.pokerogue.helper.type.repository.TypeMatchingRepository; import java.math.BigDecimal; import java.util.List; import lombok.RequiredArgsConstructor; diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/config/BiomeDatabaseInitializer.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/config/BiomeDatabaseInitializer.java deleted file mode 100644 index dc3600238..000000000 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/config/BiomeDatabaseInitializer.java +++ /dev/null @@ -1,194 +0,0 @@ -package com.pokerogue.helper.biome.config; - -import com.pokerogue.external.s3.service.S3Service; -import com.pokerogue.helper.biome.data.Biome; -import com.pokerogue.helper.biome.data.BiomeLink; -import com.pokerogue.helper.biome.data.BiomePokemon; -import com.pokerogue.helper.biome.data.BiomePokemonType; -import com.pokerogue.helper.biome.data.BiomeTypeAndTrainer; -import com.pokerogue.helper.biome.data.NextBiome; -import com.pokerogue.helper.biome.data.Tier; -import com.pokerogue.helper.biome.data.Trainer; -import com.pokerogue.helper.biome.data.TrainerPokemon; -import com.pokerogue.helper.biome.data.TrainerType; -import com.pokerogue.helper.biome.repository.BiomePokemonTypeImageRepository; -import com.pokerogue.helper.biome.repository.InMemoryBiomeRepository; -import com.pokerogue.helper.global.exception.ErrorMessage; -import com.pokerogue.helper.global.exception.GlobalCustomException; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.ApplicationArguments; -import org.springframework.boot.ApplicationRunner; -import org.springframework.stereotype.Component; - -@Slf4j -@Component -@RequiredArgsConstructor -public class BiomeDatabaseInitializer implements ApplicationRunner { - - private final S3Service s3Service; - private final BiomePokemonTypeImageRepository biomePokemonTypeImageRepository; - private final InMemoryBiomeRepository inMemoryBiomeRepository; - - @Override - public void run(ApplicationArguments args) { - List biomePokemons = new ArrayList<>(); - List biomeLinks = new ArrayList<>(); - List biomeTypesAndTrainers = new ArrayList<>(); - List trainerTypes = new ArrayList<>(); - List trainerPokemons = new ArrayList<>(); - - try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("data/biome/biome-pokemons.txt"); - BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { - while (true) { - String biomePokemon = bufferedReader.readLine(); - if (biomePokemon == null) { - break; - } - biomePokemons.add(new BiomePokemon(biomePokemon)); - } - } catch (IOException e) { - log.error("error message : {}", e.getStackTrace()[0]); - } - - try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("data/biome/biome-links.txt"); - BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { - while (true) { - String biomeLink = bufferedReader.readLine(); - if (biomeLink == null) { - break; - } - biomeLinks.add(new BiomeLink(biomeLink)); - } - } catch (IOException e) { - log.error("error message : {}", e.getStackTrace()[0]); - } - - try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream( - "data/biome/biome-types-trainers.txt"); - BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { - while (true) { - String biomeTypeAndTrainer = bufferedReader.readLine(); - if (biomeTypeAndTrainer == null) { - break; - } - biomeTypesAndTrainers.add(new BiomeTypeAndTrainer(biomeTypeAndTrainer)); - } - } catch (IOException e) { - log.error("error message : {}", e.getStackTrace()[0]); - } - - try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("data/biome/trainer-types.txt"); - BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { - while (true) { - String trainerType = bufferedReader.readLine(); - if (trainerType == null) { - break; - } - trainerTypes.add(new TrainerType(trainerType)); - } - } catch (IOException e) { - log.error("error message : {}", e.getStackTrace()[0]); - } - - try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream( - "data/biome/trainer-pokemons.txt"); - BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { - while (true) { - String trainerPokemon = bufferedReader.readLine(); - if (trainerPokemon == null) { - break; - } - trainerPokemons.add(new TrainerPokemon(trainerPokemon)); - } - } catch (IOException e) { - log.error("error message : {}", e.getStackTrace()[0]); - } - - List trainers = trainerPokemons.stream() - .filter(trainerPokemon -> existsByTrainerName(trainerTypes, trainerPokemon.getTrainerName())) - .map(trainerPokemon -> new Trainer( - trainerPokemon.getId(), - trainerPokemon.getTrainerName(), - s3Service.getTrainerImageFromS3(trainerPokemon.getId()), - getTrainerTypes(trainerTypes, trainerPokemon.getTrainerName()), - trainerPokemon.getTrainerPokemons()) - ).toList(); - - biomeTypesAndTrainers.stream() - .map(biomeTypeAndTrainer -> new Biome( - biomeTypeAndTrainer.getId(), - biomeTypeAndTrainer.getBiomeName(), - s3Service.getBiomeImageFromS3(biomeTypeAndTrainer.getId()), - getBiomePokemons(biomePokemons, biomeTypeAndTrainer.getBiomeName()), - biomeTypeAndTrainer.getBiomeTypes(), - getBiomeTrainers(trainers, biomeTypeAndTrainer.getTrainerNames()), - getNextBiomes(biomeLinks, biomeTypeAndTrainer.getId())) - ) - .forEach(inMemoryBiomeRepository::save); - - Arrays.stream(BiomePokemonType.values()) - .forEach(biomePokemonType -> biomePokemonTypeImageRepository.save( - biomePokemonType.name(), - s3Service.getPokerogueTypeImageFromS3(biomePokemonType.name().toLowerCase())) - ); - } - - private boolean existsByTrainerName(List trainerTypes, String trainerName) { - return trainerTypes.stream() - .anyMatch(trainerType -> trainerType.getTrainerName().equals(trainerName)); - } - - private List getTrainerTypes(List trainerTypes, String trainerName) { - return trainerTypes.stream() - .filter(trainerType -> trainerType.getTrainerName().equals(trainerName)) - .map(TrainerType::getTrainerTypes) - .findFirst() - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.TRAINER_NOT_FOUND)); - } - - private Map> getBiomePokemons(List biomePokemons, String biomeName) { - List allBiomePokemons = biomePokemons.stream() - .filter(biomePokemon -> biomePokemon.getBiomeName().equals(biomeName)) - .filter(biomePokemon -> !biomePokemon.getPokemons().contains("없음")) - .toList(); - - Map> ret = new HashMap<>(); - for (BiomePokemon biomePokemon : allBiomePokemons) { - if (biomePokemon.getPokemons().contains("없음")) { - continue; - } - if (ret.containsKey(biomePokemon.getPokemonTier())) { - List pokemons = ret.get(biomePokemon.getPokemonTier()); - pokemons.addAll(biomePokemon.getPokemons()); - } else { - ret.put(biomePokemon.getPokemonTier(), new ArrayList<>(biomePokemon.getPokemons())); - } - } - - return ret; - } - - private List getBiomeTrainers(List trainers, List trainerNames) { - return trainers.stream() - .filter(trainer -> trainerNames.contains(trainer.getName())) - .toList(); - } - - private List getNextBiomes(List biomeLinks, String biomeId) { - return biomeLinks.stream() - .filter(biomeLink -> biomeLink.getId().equals(biomeId)) - .map(BiomeLink::getNextBiomes) - .findFirst() - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.BIOME_NOT_FOUND)); - } -} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/controller/BiomeController.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/controller/BiomeController.java index f07d3c635..11ebd3006 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/controller/BiomeController.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/controller/BiomeController.java @@ -25,7 +25,12 @@ public ApiResponse> biomeList() { @GetMapping("/api/v1/biome/{id}") public ApiResponse biomeDetails(@PathVariable("id") String id) { - log.info("---- URI : {}, Param : {}", "/api/v1/biome/{id}", id); + log.info( + "---- URI : {}, Param : {}, ThreadName : {}", + "/api/v1/biome/{id}", + id, + Thread.currentThread().getName() + ); return new ApiResponse<>("바이옴 정보 불러오기에 성공했습니다.", biomeService.findBiome(id)); } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/converter/TierConverter.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/converter/TierConverter.java new file mode 100644 index 000000000..b45f783e6 --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/converter/TierConverter.java @@ -0,0 +1,14 @@ +package com.pokerogue.helper.biome.converter; + +import com.pokerogue.helper.biome.data.Tier; +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.convert.ReadingConverter; + +@ReadingConverter +public class TierConverter implements Converter { + + @Override + public Tier convert(String tierData) { + return Tier.convertFrom(tierData); + } +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/Biome.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/Biome.java index d638803f4..3ea0d6e50 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/Biome.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/Biome.java @@ -1,16 +1,17 @@ package com.pokerogue.helper.biome.data; -import java.util.HashSet; +import com.pokerogue.helper.type.data.Type; import java.util.List; -import java.util.Map; -import java.util.Set; +import lombok.AccessLevel; import lombok.Getter; +import lombok.NoArgsConstructor; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; @Getter @Document(collection = "biome") +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class Biome { @Id @@ -23,7 +24,7 @@ public class Biome { private String koName; @Field("types") - private List types; // Todo: List 으로 바꾸기 + private List types; @Field("nextBiomes") private List nextBiomes; @@ -33,31 +34,4 @@ public class Biome { @Field("trainers") private List trainers; - - private String image; // Todo: 지우기 - - private Map> pokemons; // Todo: 지우기 - - private List mainTypes; // Todo: 지우기 - - public Biome(String id, String name, String image, Map> pokemons, List mainTypes, - List trainers, List nextBiomes) { - this.id = id; - this.name = name; - this.image = image; - this.pokemons = pokemons; - this.mainTypes = mainTypes; - this.trainers = trainers; - this.nextBiomes = nextBiomes; - } - - public List getTrainerTypes() { - Set trainerTypes = new HashSet<>(); - trainers.stream() - .filter(trainer -> !trainer.getName().equals("없음")) - .forEach(trainer -> trainerTypes.addAll(trainer.getTypes())); - - return trainerTypes.stream() - .toList(); - } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/BiomeLink.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/BiomeLink.java deleted file mode 100644 index f5541895a..000000000 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/BiomeLink.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.pokerogue.helper.biome.data; - -import java.util.Arrays; -import java.util.List; -import lombok.Getter; - -@Getter -public class BiomeLink { - - private final String id; - private final String currentBiome; - private final List nextBiomes; - - public BiomeLink(String biomeLink) { - String[] biomeLinkInforms = biomeLink.split(" / "); - this.id = biomeLinkInforms[0]; - this.currentBiome = biomeLinkInforms[1]; - this.nextBiomes = Arrays.stream(biomeLinkInforms[2].split(",")) - .map(s -> new NextBiome(s.split("~")[0], s.split("~")[1])) - .toList(); - } -} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/BiomePokemon.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/BiomePokemon.java deleted file mode 100644 index fad1a492e..000000000 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/BiomePokemon.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.pokerogue.helper.biome.data; - -import java.util.List; -import lombok.Getter; - -@Getter -public class BiomePokemon { - - private final String biomeName; - private final Tier pokemonTier; - private final List pokemons; - - public BiomePokemon(String biomePokemon) { - String[] biomePokemonInforms = biomePokemon.split(" / "); - this.biomeName = biomePokemonInforms[0]; - this.pokemonTier = Tier.getTierByName(biomePokemonInforms[2]); - this.pokemons = List.of(biomePokemonInforms[3].split(",")); - } -} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/BiomePokemonType.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/BiomePokemonType.java deleted file mode 100644 index 642aca646..000000000 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/BiomePokemonType.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.pokerogue.helper.biome.data; - -import com.pokerogue.helper.global.exception.ErrorMessage; -import com.pokerogue.helper.global.exception.GlobalCustomException; -import java.util.Arrays; -import lombok.Getter; - -@Getter -public enum BiomePokemonType { - - GRASS("풀", "grass"), - POISON("독", "poison"), - FIRE("불꽃", "fire"), - WATER("물", "water"), - ELECTRIC("전기", "electric"), - NORMAL("노말", "normal"), - FAIRY("페어리", "fairy"), - BUG("벌레", "bug"), - DARK("악", "dark"), - DRAGON("드래곤", "dragon"), - FIGHTING("격투", "fighting"), - FLYING("비행", "flying"), - GHOST("고스트", "ghost"), - GROUND("땅", "ground"), - ICE("얼음", "ice"), - ROCK("바위", "rock"), - PSYCHIC("에스퍼", "psychic"), - STEEL("강철", "steel"), - STELLAR("스텔라", "stellar"), - UNKNOWN("없음", "unknown"); - - private final String name; - private final String id; - - BiomePokemonType(String name, String id) { - this.name = name; - this.id = id; - } - - public static BiomePokemonType getBiomePokemonTypeByName(String name) { - return Arrays.stream(values()) - .filter(biomePokemonType -> biomePokemonType.name.equals(name)) - .findFirst() - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.POKEMON_TYPE_NOT_FOUND)); - } - - public static BiomePokemonType getBiomePokemonTypeById(String id) { - return Arrays.stream(values()) - .filter(biomePokemonType -> biomePokemonType.id.equals(id)) - .findFirst() - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.POKEMON_TYPE_NOT_FOUND)); - } -} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/BiomeTypeAndTrainer.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/BiomeTypeAndTrainer.java deleted file mode 100644 index 9cc8acb96..000000000 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/BiomeTypeAndTrainer.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.pokerogue.helper.biome.data; - -import java.util.List; -import lombok.Getter; - -@Getter -public class BiomeTypeAndTrainer { - - private final String id; - private final String biomeName; - private final List biomeTypes; - private final List trainerNames; - - public BiomeTypeAndTrainer(String biomeTypeAndTrainer) { - String[] biomeTypeAndTrainerInforms = biomeTypeAndTrainer.split(" / "); - this.id = biomeTypeAndTrainerInforms[0]; - this.biomeName = biomeTypeAndTrainerInforms[1]; - this.biomeTypes = List.of(biomeTypeAndTrainerInforms[2].split(",")); - this.trainerNames = List.of(biomeTypeAndTrainerInforms[3].split(",")); - } -} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/NativePokemon.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/NativePokemon.java index 7ddbc52de..d65afa012 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/NativePokemon.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/NativePokemon.java @@ -1,11 +1,28 @@ package com.pokerogue.helper.biome.data; import java.util.List; -import lombok.RequiredArgsConstructor; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.data.mongodb.core.mapping.Field; -@RequiredArgsConstructor +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class NativePokemon { - private final String tier; // Todo: enum 사용 - private final List pokemonIds; + private static final String BOSS = "보스"; + + @Field("tier") + private Tier tier; + + @Field("pokemonIds") + private List pokemonIds; + + public boolean isWild() { + return tier.isWild(); + } + + public boolean isBoss() { + return tier.isBoss(); + } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/NextBiome.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/NextBiome.java index 47d7b4af9..f4fc468c2 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/NextBiome.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/NextBiome.java @@ -1,19 +1,17 @@ package com.pokerogue.helper.biome.data; +import lombok.AccessLevel; import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.data.mongodb.core.mapping.Field; @Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class NextBiome { + @Field("name") private String name; - private int percentage; - - public NextBiome(String name, String percentage) { - this.name = name; - this.percentage = Integer.parseInt(percentage); // Todo - } - public String getPercent() { - return String.valueOf(percentage); - } + @Field("percentage") + private int percentage; } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/Tier.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/Tier.java index 1f7703537..142746347 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/Tier.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/Tier.java @@ -16,7 +16,7 @@ public enum Tier { BOSS("보스"), BOSS_RARE("레어 보스"), BOSS_SUPER_RARE("슈퍼 레어 보스"), - BOSS_ULTRA_RARE("슈퍼 울트라 레어 보스") + BOSS_ULTRA_RARE("슈퍼 울트라 레어 보스"), ; private final String name; @@ -25,18 +25,22 @@ public enum Tier { this.name = name; } - public static Tier getTierByName(String name) { - return Arrays.stream(values()) - .filter(tier -> tier.name.equals(name)) - .findFirst() - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.TIER_NOT_FOUND)); + public boolean isWild() { + return !name.contains("보스"); + } + + public boolean isBoss() { + return name.contains("보스"); } - public boolean isWildPokemon() { - return !this.name.contains("보스"); + public static Tier convertFrom(String tierData) { + return getTierByName(tierData); } - public boolean isBossPokemon() { - return this.name.contains("보스"); + private static Tier getTierByName(String name) { + return Arrays.stream(values()) + .filter(tier -> tier.name.equals(name)) + .findFirst() + .orElseThrow(() -> new GlobalCustomException(ErrorMessage.TIER_NOT_FOUND)); } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/Trainer.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/Trainer.java index 6753e420e..7bc427922 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/Trainer.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/Trainer.java @@ -1,16 +1,25 @@ package com.pokerogue.helper.biome.data; +import com.pokerogue.helper.type.data.Type; import java.util.List; +import lombok.AccessLevel; import lombok.Getter; -import lombok.RequiredArgsConstructor; +import lombok.NoArgsConstructor; +import org.springframework.data.mongodb.core.mapping.Field; @Getter -@RequiredArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class Trainer { - private final String id; // Todo: 지우기 - private final String name; - private final String image; // Todo: 지우기 - private final List types; // Todo: List - private final List pokemonIds; + @Field("name") + private String name; + + @Field("koName") + private String koName; + + @Field("types") + private List types; + + @Field("pokemonIds") + private List pokemonIds; } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/TrainerPokemon.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/TrainerPokemon.java deleted file mode 100644 index f58e488fe..000000000 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/TrainerPokemon.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.pokerogue.helper.biome.data; - -import java.util.List; -import lombok.Getter; - -@Getter -public class TrainerPokemon { - - private final String id; - private final String trainerName; - private final List trainerPokemons; - - public TrainerPokemon(String trainerPokemon) { - String[] trainerPokemonInforms = trainerPokemon.split(" / "); - this.id = trainerPokemonInforms[0]; - this.trainerName = trainerPokemonInforms[1]; - this.trainerPokemons = List.of(trainerPokemonInforms[2].split(",")); - } -} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/TrainerType.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/TrainerType.java deleted file mode 100644 index 6917a2f6b..000000000 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/data/TrainerType.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.pokerogue.helper.biome.data; - -import java.util.List; -import lombok.Getter; - -@Getter -public class TrainerType { - - private final String trainerName; - private final List trainerTypes; - - public TrainerType(String trainerType) { - String[] trainerTypeInforms = trainerType.split(" / "); - this.trainerName = trainerTypeInforms[0]; - this.trainerTypes = List.of(trainerTypeInforms[1].split(",")); - } -} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/BiomeAllPokemonResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/BiomeAllPokemonResponse.java index 0f7c3d883..7de4a41f1 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/BiomeAllPokemonResponse.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/BiomeAllPokemonResponse.java @@ -1,11 +1,11 @@ package com.pokerogue.helper.biome.dto; -import com.pokerogue.helper.biome.data.Tier; +import com.pokerogue.helper.biome.data.NativePokemon; import java.util.List; public record BiomeAllPokemonResponse(String tier, List pokemons) { - public static BiomeAllPokemonResponse of(Tier tier, List pokemons) { - return new BiomeAllPokemonResponse(tier.getName(), pokemons); + public static BiomeAllPokemonResponse of(NativePokemon nativePokemon, List pokemons) { + return new BiomeAllPokemonResponse(nativePokemon.getTier().getName(), pokemons); } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/BiomeDetailResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/BiomeDetailResponse.java index 3fb0a0913..300459469 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/BiomeDetailResponse.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/BiomeDetailResponse.java @@ -14,6 +14,7 @@ public record BiomeDetailResponse( ) { public static BiomeDetailResponse of( Biome biome, + String biomeImage, List wildPokemons, List bossPokemons, List trainerPokemons, @@ -21,8 +22,8 @@ public static BiomeDetailResponse of( ) { return new BiomeDetailResponse( biome.getId(), - biome.getName(), - biome.getImage(), + biome.getKoName(), + biomeImage, wildPokemons, bossPokemons, trainerPokemons, diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/BiomeResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/BiomeResponse.java index 5ef53c0ff..2aca68c01 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/BiomeResponse.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/BiomeResponse.java @@ -11,11 +11,11 @@ public record BiomeResponse( List trainerTypeResponses ) { - public static BiomeResponse of(Biome biome, List pokemonTypeLogos, List trainerTypeLogos) { + public static BiomeResponse of(Biome biome, String biomeImage, List pokemonTypeLogos, List trainerTypeLogos) { return new BiomeResponse( biome.getId(), - biome.getName(), - biome.getImage(), + biome.getKoName(), + biomeImage, pokemonTypeLogos, trainerTypeLogos ); diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/NextBiomeResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/NextBiomeResponse.java index 0f02ecab4..036af8eaf 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/NextBiomeResponse.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/NextBiomeResponse.java @@ -14,14 +14,15 @@ public record NextBiomeResponse( public static NextBiomeResponse of( Biome biome, + String biomeImage, String percent, List pokemonTypeResponses, List trainerTypeResponses ) { return new NextBiomeResponse( biome.getId(), - biome.getName(), - biome.getImage(), + biome.getKoName(), + biomeImage, percent, pokemonTypeResponses, trainerTypeResponses diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/TrainerPokemonResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/TrainerPokemonResponse.java index 166b1c4a7..fb78a78f1 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/TrainerPokemonResponse.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/dto/TrainerPokemonResponse.java @@ -12,11 +12,12 @@ public record TrainerPokemonResponse( public static TrainerPokemonResponse from( Trainer trainer, + String trainerImage, List trainerTypes, List trainerPokemons) { return new TrainerPokemonResponse( - trainer.getName(), - trainer.getImage(), + trainer.getKoName(), + trainerImage, trainerTypes, trainerPokemons ); diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/repository/BiomePokemonTypeImageRepository.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/repository/BiomePokemonTypeImageRepository.java deleted file mode 100644 index db00e33fc..000000000 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/repository/BiomePokemonTypeImageRepository.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.pokerogue.helper.biome.repository; - -import java.util.HashMap; -import java.util.Map; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Repository; - -@Repository -@RequiredArgsConstructor -public class BiomePokemonTypeImageRepository { - - private final Map biomePokemonTypeImages; - - public BiomePokemonTypeImageRepository() { - this.biomePokemonTypeImages = new HashMap<>(); - } - - public void save(String typeName, String typeImageUrl) { - biomePokemonTypeImages.put(typeName, typeImageUrl); - } - - public String findPokemonTypeImageUrl(String typeName) { - return biomePokemonTypeImages.get(typeName); - } -} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/repository/InMemoryBiomeRepository.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/repository/InMemoryBiomeRepository.java deleted file mode 100644 index dc39f961a..000000000 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/repository/InMemoryBiomeRepository.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.pokerogue.helper.biome.repository; - -import com.pokerogue.helper.biome.data.Biome; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Repository; - -@Repository -@RequiredArgsConstructor -public class InMemoryBiomeRepository { - - private final Map biomes; - - public InMemoryBiomeRepository() { - this.biomes = new HashMap<>(); - } - - public void save(Biome biome) { - biomes.put(biome.getId(), biome); - } - - public List findAll() { - return biomes.values().stream() - .toList(); - } - - public Optional findById(String id) { - return Optional.ofNullable(biomes.get(id)); - } -} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/service/BiomeService.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/service/BiomeService.java index 7f52b8d84..dd5741b91 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/service/BiomeService.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/biome/service/BiomeService.java @@ -2,8 +2,7 @@ import com.pokerogue.external.s3.service.S3Service; import com.pokerogue.helper.biome.data.Biome; -import com.pokerogue.helper.biome.data.BiomePokemonType; -import com.pokerogue.helper.biome.data.Tier; +import com.pokerogue.helper.biome.data.NativePokemon; import com.pokerogue.helper.biome.data.Trainer; import com.pokerogue.helper.biome.dto.BiomeAllPokemonResponse; import com.pokerogue.helper.biome.dto.BiomeDetailResponse; @@ -12,15 +11,12 @@ import com.pokerogue.helper.biome.dto.BiomeTypeResponse; import com.pokerogue.helper.biome.dto.NextBiomeResponse; import com.pokerogue.helper.biome.dto.TrainerPokemonResponse; -import com.pokerogue.helper.biome.repository.BiomePokemonTypeImageRepository; -import com.pokerogue.helper.biome.repository.InMemoryBiomeRepository; +import com.pokerogue.helper.biome.repository.BiomeRepository; import com.pokerogue.helper.global.exception.ErrorMessage; import com.pokerogue.helper.global.exception.GlobalCustomException; -import com.pokerogue.helper.pokemon.data.Type; -import com.pokerogue.helper.pokemon.repository.InMemoryPokemonRepository; -import java.util.ArrayList; +import com.pokerogue.helper.pokemon.repository.PokemonRepository; +import com.pokerogue.helper.type.data.Type; import java.util.List; -import java.util.Map; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -29,132 +25,114 @@ public class BiomeService { private final S3Service s3Service; - private final InMemoryBiomeRepository inMemoryBiomeRepository; - private final InMemoryPokemonRepository inMemoryPokemonRepository; - private final BiomePokemonTypeImageRepository biomePokemonTypeImageRepository; + private final BiomeRepository biomeRepository; + private final PokemonRepository pokemonRepository; public List findBiomes() { - return inMemoryBiomeRepository.findAll().stream() + return biomeRepository.findAll().stream() .map(biome -> BiomeResponse.of( biome, - getTypesResponses(biome.getMainTypes()), - getTypesResponses(biome.getTrainerTypes())) + s3Service.getBiomeImageFromS3(biome.getId()), + getTypesResponses(biome.getTypes()), + getTrainerTypesResponses(biome.getTrainers())) ) .toList(); } public BiomeDetailResponse findBiome(String id) { - Biome biome = inMemoryBiomeRepository.findById(id) + Biome biome = biomeRepository.findById(id) .orElseThrow(() -> new GlobalCustomException(ErrorMessage.BIOME_NOT_FOUND)); return BiomeDetailResponse.of( biome, - getWildPokemons(biome), - getBossPokemons(biome), + s3Service.getBiomeImageFromS3(biome.getId()), + getWildPokemons(biome.getNativePokemons()), + getBossPokemons(biome.getNativePokemons()), getTrainerPokemons(biome), getNextBiomes(biome) ); } - private List getWildPokemons(Biome biome) { - Map> biomePokemons = biome.getPokemons(); - - return biomePokemons.keySet().stream() - .filter(Tier::isWildPokemon) - .map(tier -> BiomeAllPokemonResponse.of(tier, getBiomePokemons(biomePokemons.get(tier)))) - .distinct() + private List getWildPokemons(List nativePokemons) { + return nativePokemons.stream() + .filter(NativePokemon::isWild) + .map(nativePokemon -> BiomeAllPokemonResponse.of( + nativePokemon, + getBiomePokemons(nativePokemon.getPokemonIds()))) .toList(); } - private List getBossPokemons(Biome biome) { - Map> biomePokemons = biome.getPokemons(); - - return biomePokemons.keySet().stream() - .filter(Tier::isBossPokemon) - .map(tier -> BiomeAllPokemonResponse.of(tier, getBiomePokemons(biomePokemons.get(tier)))) - .distinct() + private List getBossPokemons(List nativePokemons) { + return nativePokemons.stream() + .filter(NativePokemon::isBoss) + .map(nativePokemon -> BiomeAllPokemonResponse.of( + nativePokemon, + getBiomePokemons(nativePokemon.getPokemonIds()))) .toList(); } - private List getBiomePokemons(List biomePokemons) { - return biomePokemons.stream() - .map(biomePokemon -> inMemoryPokemonRepository.findById(biomePokemon) - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.POKEMON_NOT_FOUND)) - ) - .map(biomePokemonInfo -> new BiomePokemonResponse( - biomePokemonInfo.id(), - biomePokemonInfo.koName(), - s3Service.getPokemonImageFromS3(biomePokemonInfo.id()), - getBiomePokemonTypeResponses( - Type.findById(biomePokemonInfo.firstType()), - Type.findById(biomePokemonInfo.secondType())) - )) - .distinct() - .toList(); - } - - private List getBiomePokemonTypeResponses( - Type firstType, - Type secondType - ) { - List biomeTypeRespons = new ArrayList<>(); - if (!firstType.equals(Type.EMPTY) && !firstType.equals(Type.UNKNOWN)) { - biomeTypeRespons.add(new BiomeTypeResponse( - biomePokemonTypeImageRepository.findPokemonTypeImageUrl(firstType.name()), - firstType.getName()) - ); - } - if (!secondType.equals(Type.EMPTY) && !secondType.equals(Type.UNKNOWN)) { - biomeTypeRespons.add(new BiomeTypeResponse( - biomePokemonTypeImageRepository.findPokemonTypeImageUrl(secondType.name()), - secondType.getName()) - ); - } - - return biomeTypeRespons; - } - private List getTrainerPokemons(Biome biome) { - List trainerNames = biome.getTrainers().stream() - .map(Trainer::getName) - .toList(); - if (trainerNames.contains("없음")) { - return List.of(); - } - return biome.getTrainers().stream() .map(trainer -> TrainerPokemonResponse.from( trainer, + s3Service.getTrainerImageFromS3(trainer.getName()), getTypesResponses(trainer.getTypes()), getBiomePokemons(trainer.getPokemonIds())) ) .toList(); } - private List getTypesResponses(List types) { - return types.stream() - .map(type -> new BiomeTypeResponse(biomePokemonTypeImageRepository.findPokemonTypeImageUrl( - BiomePokemonType.getBiomePokemonTypeByName(type).name()), type) - ) - .toList(); - } - private List getNextBiomes(Biome biome) { - if (biome.getId().equals("end")) { - return List.of(); - } - return biome.getNextBiomes().stream() .map(nextBiomeInfo -> { - Biome nextBiome = inMemoryBiomeRepository.findById(nextBiomeInfo.getName()) + Biome nextBiome = biomeRepository.findById(nextBiomeInfo.getName()) .orElseThrow(() -> new GlobalCustomException(ErrorMessage.BIOME_NOT_FOUND)); + return NextBiomeResponse.of( nextBiome, - nextBiomeInfo.getPercent(), - getTypesResponses(nextBiome.getMainTypes()), - getTypesResponses(nextBiome.getTrainerTypes()) + s3Service.getBiomeImageFromS3(nextBiome.getId()), + String.valueOf(nextBiomeInfo.getPercentage()), + getTypesResponses(nextBiome.getTypes()), + getTrainerTypesResponses(nextBiome.getTrainers()) ); }) .toList(); } + + private List getBiomePokemons(List biomePokemons) { + List biomePokemonResponses = pokemonRepository.findAllById(biomePokemons).stream() + .map(pokemon -> new BiomePokemonResponse( + pokemon.getId(), + pokemon.getKoName(), + s3Service.getPokemonImageFromS3(pokemon.getImageId()), + getTypesResponses(pokemon.getTypes())) + ) + .distinct() + .toList(); + if (biomePokemons.size() == biomePokemonResponses.size()) { + return biomePokemonResponses; + } + + throw new GlobalCustomException(ErrorMessage.POKEMON_NOT_FOUND); + } + + private List getTypesResponses(List types) { + return types.stream() + .map(type -> new BiomeTypeResponse( + type.getImage(), + type.getKoName()) + ) + .toList(); + } + + private List getTrainerTypesResponses(List trainers) { + return trainers.stream() + .map(Trainer::getTypes) + .flatMap(List::stream) + .map(type -> new BiomeTypeResponse( + type.getImage(), + type.getKoName()) + ) + .toList(); + } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/data/PokemonValidator.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/data/PokemonValidator.java new file mode 100644 index 000000000..ae5f7fa16 --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/data/PokemonValidator.java @@ -0,0 +1,275 @@ +package com.pokerogue.helper.data; + +import static java.lang.Character.isDigit; +import static java.lang.Character.isLowerCase; + +import com.pokerogue.helper.global.exception.ErrorMessage; +import com.pokerogue.helper.global.exception.GlobalCustomException; +import com.pokerogue.helper.pokemon.data.Pokemon; +import com.pokerogue.helper.type.data.Type; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.IntPredicate; +import java.util.function.Predicate; +import java.util.stream.Stream; +import org.apache.logging.log4j.util.Strings; + +class PokemonValidator { + + private static final int POKEMON_SIZE = 1446; + private static final int MIN_GENERATION = 1; + private static final int MAX_GENERATION = 9; + private static final int MIN_TYPE_COUNT = 1; + private static final int MAX_TYPE_COUNT = 2; + private static final int MIN_ABILITY_COUNT = 2; + private static final int MAX_ABILITY_COUNT = 4; + private static final int MIN_NORMAL_ABILITY_COUNT = 1; + private static final int MAX_NORMAL_ABILITY_COUNT = 2; + private static final int MIN_STAT_VALUE = -1; + private static final int MAX_STAT_VALUE = 10000; + private static final String DELIMITER = "_"; + private static final String EMPTY_ABILITY = "none"; + private static final IntPredicate isExpectedIdLetter = character -> isLowerCase(character) + || isDigit(character) + || isDelimiter(character); + + private PokemonValidator() { + } + + static void validatePokemonSize(int pokemonCount) { + Predicate isTotalPokemonSizeMatch = count -> count == POKEMON_SIZE; + String message = String.format("포켓몬의 총 개수가 다릅니다. 예상값: %d, 현재값: %d", POKEMON_SIZE, pokemonCount); + + validate(isTotalPokemonSizeMatch, pokemonCount, ErrorMessage.POKEMON_SIZE_MISMATCH, message); + } + + static void validatePokemonIdFormat(List pokemonIds) { + Predicate isExpectedLetter = id -> id.codePoints().allMatch(isExpectedIdLetter); + Predicate isDelimiterSeparated = id -> id.contains(DELIMITER + DELIMITER); + Predicate isDelimiterInPlace = id -> id.startsWith(DELIMITER) || id.endsWith(DELIMITER); + + String message = "아이디: %s는 아이디 규칙에 맞지 않습니다."; + + for (String id : pokemonIds) { + validate(isExpectedLetter, id, ErrorMessage.POKEMON_ID_UNEXPECTED_LETTER, String.format(message, id)); + validate(isDelimiterSeparated, id, ErrorMessage.POKEMON_ID_DELIMITER_IS_SEQUENTIAL, + String.format(message, id)); + validate(isDelimiterInPlace, id, ErrorMessage.POKEMON_ID_DELIMITER_MISPLACED, String.format(message, id)); + } + } + + static void validatePokemonsBaseTotal(List pokemons) { + Predicate isBaseTotalCorrect = pokemon -> { + int hp = pokemon.getHp(); + int attack = pokemon.getAttack(); + int specialAttack = pokemon.getSpecialAttack(); + int defense = pokemon.getDefense(); + int specialDefense = pokemon.getSpecialDefense(); + int speed = pokemon.getSpeed(); + + int baseTotal = pokemon.getBaseTotal(); + int summation = hp + attack + specialAttack + defense + specialDefense + speed; + + return baseTotal == summation; + }; + + for (Pokemon pokemon : pokemons) { + validate(isBaseTotalCorrect, pokemon, ErrorMessage.POKEMON_SIZE_MISMATCH); + } + } + + static void validatePokemonsGeneration(List pokemons) { + Predicate isValidGeneration = gen -> isInRange(gen, MIN_GENERATION, MAX_GENERATION); + + for (Pokemon pokemon : pokemons) { + int generation = pokemon.getGeneration(); + validate(isValidGeneration, generation, ErrorMessage.POKEMON_GENERATION_MISMATCH); + } + } + + static void validatePokemonFormChanges(List pokemons) { + Predicate isFormChangeable = pokemon -> !pokemon.getFormChanges().isEmpty(); + List formChangeablePokemons = pokemons.stream() + .filter(Pokemon::isCanChangeForm) + .toList(); + + for (Pokemon fomrChangeablePokemon : formChangeablePokemons) { + validate(isFormChangeable, fomrChangeablePokemon, ErrorMessage.POKEMON_FORM_CHANGE_MISMATCH); + } + } + + static void validatePokemonRarity(List pokemons) { + Predicate isRarityCountLessOrEqualThanOne = pokemon -> { + boolean legendary = pokemon.isLegendary(); + boolean mythical = pokemon.isMythical(); + boolean subLegendary = pokemon.isSubLegendary(); + + long rarityCount = Stream.of(legendary, mythical, subLegendary) + .filter(Boolean::booleanValue) + .count(); + + return rarityCount <= 1; + }; + + for (Pokemon pokemon : pokemons) { + validate(isRarityCountLessOrEqualThanOne, pokemon, ErrorMessage.POKEMON_RARITY_COUNT_MISMATCH); + } + } + + static void validateNormalAbilityCount(List pokemons) { + Predicate isNormalAbilityCountInRange = normalAbilityCount -> + isInRange(normalAbilityCount, MIN_NORMAL_ABILITY_COUNT, MAX_NORMAL_ABILITY_COUNT); + + for (Pokemon pokemon : pokemons) { + int abilityCount = pokemon.getNormalAbilityIds().size(); + + validate(isNormalAbilityCountInRange, abilityCount, ErrorMessage.POKEMON_NORMAL_ABILITY_COUNT); + } + } + + static void validateTotalAbilityCount(List pokemons) { + Predicate isTotalAbilityCountInRange = pokemon -> { + List totalAbilityIds = pokemon.getNormalAbilityIds(); + totalAbilityIds.add(pokemon.getHiddenAbilityId()); + totalAbilityIds.add(pokemon.getPassiveAbilityId()); + + int totalAbilityCount = totalAbilityIds.stream() + .filter(id -> !id.equals(EMPTY_ABILITY)) + .mapToInt(id -> 1) + .sum(); + + return isInRange(totalAbilityCount, MIN_ABILITY_COUNT, MAX_ABILITY_COUNT); + }; + + for (Pokemon pokemon : pokemons) { + validate(isTotalAbilityCountInRange, pokemon, ErrorMessage.POKEMON_TOTAL_ABILITY_COUNT); + } + } + + static void validateTotalAbilityDuplication(List pokemons) { + Predicate isAbilityDisjoint = pokemon -> { + List totalAbilityIds = pokemon.getNormalAbilityIds(); + totalAbilityIds.add(pokemon.getHiddenAbilityId()); + totalAbilityIds.add(pokemon.getPassiveAbilityId()); + + Set uniqueIds = new HashSet<>(totalAbilityIds); + + return totalAbilityIds.size() == uniqueIds.size(); + }; + + for (Pokemon pokemon : pokemons) { + validate(isAbilityDisjoint, pokemon, ErrorMessage.POKEMON_ABILITY_DUPLICATION); + } + } + + static void validateStatValueRange(List pokemons) { + Predicate isStatsInRange = pokemon -> { + List stats = List.of( + pokemon.getDefense(), + pokemon.getAttack(), + pokemon.getSpecialAttack(), + pokemon.getSpecialDefense(), + pokemon.getWeight(), + pokemon.getHeight(), + pokemon.getFriendship(), + pokemon.getBaseExp(), + pokemon.getBaseTotal(), + pokemon.getHp(), + pokemon.getSpeed() + ); + + return stats.stream() + .map(Number::doubleValue) + .map(Double::intValue) + .allMatch(statValue -> isInRange(statValue, MIN_STAT_VALUE, MAX_STAT_VALUE)); + }; + + for (Pokemon pokemon : pokemons) { + validate(isStatsInRange, pokemon, ErrorMessage.POKEMON_STAT_OUT_OF_RANGE); + } + } + + static void validatePassiveAbilityExist(List pokemons) { + Predicate isPassiveExist = pokemon -> { + String passiveAbilityId = pokemon.getPassiveAbilityId(); + return Strings.isNotBlank(passiveAbilityId) && !EMPTY_ABILITY.equals(passiveAbilityId); + }; + + for (Pokemon pokemon : pokemons) { + validate(isPassiveExist, pokemon, ErrorMessage.POKEMON_PASSIVE_NOT_FOUND); + } + } + + static void validateEmptyHiddenAbilityExists(List pokemons) { + Predicate isEmptyHiddenExist = pokemon -> { + String hiddenAbilityId = pokemon.getPassiveAbilityId(); + return Strings.isNotBlank(hiddenAbilityId) || EMPTY_ABILITY.equals(hiddenAbilityId); + }; + + boolean isEmptyExist = pokemons.stream().anyMatch(isEmptyHiddenExist); + + validate(Predicate.isEqual(true), isEmptyExist, ErrorMessage.POKEMON_SIZE_MISMATCH); + } + + static void validateTypeCount(List pokemons) { + Predicate isTypeCountInRange = pokemon -> { + int typeCount = pokemon.getTypes().size(); + return isInRange(typeCount, MIN_TYPE_COUNT, MAX_TYPE_COUNT); + }; + + for (Pokemon pokemon : pokemons) { + validate(isTypeCountInRange, pokemon, ErrorMessage.POKEMON_TYPE_COUNT_OUT_OF_RANGE); + } + } + + static void validateTypeDuplication(List pokemons) { + Predicate isTypeDisjointed = pokemon -> { + List types = pokemon.getTypes(); + Set uniqueTypes = new HashSet<>(types); + return types.size() == uniqueTypes.size(); + }; + + for (Pokemon pokemon : pokemons) { + validate(isTypeDisjointed, pokemon, ErrorMessage.POKEMON_TYPE_DUPLICATION); + } + } + + static void validateEvolutionFromToIsPokemonId(List pokemons) { + List pokemonIds = pokemons.stream().map(Pokemon::getId).toList(); + List evolutionIds = pokemons.stream() + .flatMap(pokemon -> pokemon.getEvolutions().stream()) + .flatMap(evolution -> Stream.of(evolution.getFrom(), evolution.getTo())) + .distinct() + .toList(); + + boolean containsAll = new HashSet<>(pokemonIds).containsAll(evolutionIds); + + validate(Predicate.isEqual(true), containsAll, ErrorMessage.POKEMON_EVOLUTION_ID_MISMATCH); + } + + + private static void validate(Predicate predicate, T data, ErrorMessage errorMessage) { + if (predicate.test(data)) { + return; + } + throw new GlobalCustomException(errorMessage, data.toString()); + } + + private static void validate(Predicate predicate, T data, ErrorMessage errorMessage, + String detailedMessage) { + if (predicate.test(data)) { + return; + } + throw new GlobalCustomException(errorMessage, detailedMessage); + } + + private static boolean isInRange(int target, int min, int max) { + return target >= min && target <= max; + } + + private static boolean isDelimiter(int character) { + return DELIMITER.charAt(0) == character; + } + +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/global/config/ConverterConfig.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/global/config/ConverterConfig.java new file mode 100644 index 000000000..a6fad5ddc --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/global/config/ConverterConfig.java @@ -0,0 +1,28 @@ +package com.pokerogue.helper.global.config; + +import com.pokerogue.helper.biome.converter.TierConverter; +import com.pokerogue.helper.move.converter.FlagConverter; +import com.pokerogue.helper.move.converter.MoveCategoryConverter; +import com.pokerogue.helper.move.converter.MoveTargetConverter; +import com.pokerogue.helper.pokemon.converter.EvolutionItemConverter; +import com.pokerogue.helper.type.converter.TypeReadConverter; +import java.util.List; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.mongodb.core.convert.MongoCustomConversions; + +@Configuration +public class ConverterConfig { + + @Bean + public MongoCustomConversions customConversions() { + return new MongoCustomConversions(List.of( + new TypeReadConverter(), + new EvolutionItemConverter(), + new MoveCategoryConverter(), + new MoveTargetConverter(), + new FlagConverter(), + new TierConverter() + )); + } +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/global/exception/ErrorMessage.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/global/exception/ErrorMessage.java index d6d0ecfc1..35701d427 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/global/exception/ErrorMessage.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/global/exception/ErrorMessage.java @@ -7,24 +7,42 @@ @Getter @RequiredArgsConstructor public enum ErrorMessage { - - POKEMON_NOT_FOUND(HttpStatus.NOT_FOUND, "해당하는 포켓몬을 찾지 못했습니다."), - POKEMON_ABILITY_NOT_FOUND(HttpStatus.NOT_FOUND, "해당하는 특성을 찾지 못했습니다."), - POKEMON_TYPE_NOT_FOUND(HttpStatus.NOT_FOUND, "해당하는 타입을 찾지 못했습니다."), - ARTICLE_NOT_FOUND(HttpStatus.NOT_FOUND, "해당하는 꿀팁을 찾지 못했습니다."), - TIER_NOT_FOUND(HttpStatus.NOT_FOUND, "해당하는 티어를 찾지 못했습니다."), - TRAINER_NOT_FOUND(HttpStatus.NOT_FOUND, "해당하는 트레이너를 찾지 못했습니다."), - BIOME_NOT_FOUND(HttpStatus.NOT_FOUND, "해당하는 바이옴을 찾지 못했습니다."), - MOVE_BY_MACHINE_NOT_FOUND(HttpStatus.NOT_FOUND, "도감 번호에 해당하는 머신으로 배울 수 있는 기술을 찾지 못했습니다."), - MOVE_BY_EGG_NOT_FOUND(HttpStatus.NOT_FOUND, "도감 번호에 해당하는 알 기술을 찾지 못했습니다."), - MOVE_BY_SELF_NOT_FOUND(HttpStatus.NOT_FOUND, "도감 번호에 해당하는 자력 기술을 찾지 못했습니다."), - MOVE_NOT_FOUND(HttpStatus.NOT_FOUND, "id에 해당하는 기술을 찾지 못했습니다."), - MOVE_CATEGORY_NOT_FOUND(HttpStatus.NOT_FOUND, "기술 카테고리를 찾지 못했습니다."), - WEATHER_NOT_FOUND(HttpStatus.NOT_FOUND, "id에 해당하는 날씨를 찾지 못했습니다."), - EVOLUTION_NOT_FOUND(HttpStatus.NOT_FOUND, "해당하는 진화 정보를 찾지 못했습니다."), + POKEMON_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR, "해당하는 포켓몬을 찾지 못했습니다."), + POKEMON_ABILITY_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR, "해당하는 특성을 찾지 못했습니다."), + TYPE_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR, "해당하는 타입을 찾지 못했습니다."), + ARTICLE_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR, "해당하는 꿀팁을 찾지 못했습니다."), + MOVE_TARGET_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR, "기술 타켓을 찾지 못했습니다."), + MOVE_FLAG_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR, "기술 플래그를 찾지 못했습니다."), + WEATHER_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR, "id에 해당하는 날씨를 찾지 못했습니다."), + EVOLUTION_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR, "해당하는 진화 정보를 찾지 못했습니다."), + ITEM_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR, "해당하는 아이템을 찾지 못했습니다."), + + TIER_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR, "해당하는 티어를 찾지 못했습니다."), + BIOME_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR, "해당하는 바이옴을 찾지 못했습니다."), + MOVE_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR, "id에 해당하는 기술을 찾지 못했습니다."), + MOVE_CATEGORY_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR, "기술 카테고리를 찾지 못했습니다."), PARSE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "파싱에 실패했습니다."), TYPE_MATCHING_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "타입 상성 찾기에 실패했습니다."), + POKEMON_SIZE_MISMATCH(HttpStatus.INTERNAL_SERVER_ERROR, "예상 포켓몬 수와 실제 데이터가 일치하지 않습니다."), + POKEMON_BASE_TOTAL_MISMATCH(HttpStatus.INTERNAL_SERVER_ERROR, "종족값이 기본 능력치의 합과 다릅니다."), + POKEMON_ID_UNEXPECTED_LETTER(HttpStatus.INTERNAL_SERVER_ERROR, "아이디에 허용되지 않은 문자가 포함되어 있습니다."), + POKEMON_ID_DELIMITER_MISPLACED(HttpStatus.INTERNAL_SERVER_ERROR, "아이디에 구분자가 처음이나 끝에 올 수 없습니다."), + POKEMON_ID_DELIMITER_IS_SEQUENTIAL(HttpStatus.INTERNAL_SERVER_ERROR, "아이디에 구분자가 연속으로 배치되어 있습니다."), + POKEMON_GENERATION_MISMATCH(HttpStatus.INTERNAL_SERVER_ERROR,"적절하지 않은 포켓몬 세대입니다."), + POKEMON_FORM_CHANGE_MISMATCH(HttpStatus.INTERNAL_SERVER_ERROR,"폼변환이 가능하지만 변환 가능한 포켓몬이 없습니다."), + POKEMON_RARITY_COUNT_MISMATCH(HttpStatus.INTERNAL_SERVER_ERROR,"전설, 준전설, 미신은 셋 중 하나 이하만 선택될 수 있습니다."), + POKEMON_NORMAL_ABILITY_COUNT(HttpStatus.INTERNAL_SERVER_ERROR,"포켓몬 기본 특성 개수가 유효범위 내에 있지 않습니다."), + POKEMON_TOTAL_ABILITY_COUNT(HttpStatus.INTERNAL_SERVER_ERROR,"포켓몬 특성의 총 개수가 유효범위 내에 있지 않습니다."), + POKEMON_ABILITY_DUPLICATION(HttpStatus.INTERNAL_SERVER_ERROR,"중복되는 특성이 존재합니다."), + POKEMON_STAT_OUT_OF_RANGE(HttpStatus.INTERNAL_SERVER_ERROR, "포켓몬 능력 수치가 예상 범위 내에 있지 않습니다."), + POKEMON_PASSIVE_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR, "패시브 특성은 반드시 존재해야합니다."), + POKEMON_TYPE_COUNT_OUT_OF_RANGE(HttpStatus.INTERNAL_SERVER_ERROR,"포켓몬의 특성의 개수가 유효범위 내에 있지 않습니다."), + POKEMON_TYPE_DUPLICATION(HttpStatus.INTERNAL_SERVER_ERROR,"포켓몬의 타입은 중복될 수 없습니다."), + POKEMON_EVOLUTION_ID_MISMATCH(HttpStatus.INTERNAL_SERVER_ERROR, "포켓몬과 진화 포켓몬 아이디가 서로 일치하지 않습니다"), + + + FILE_ACCESS_FAILED(HttpStatus.BAD_REQUEST, "파일 정보 접근에 실패했습니다."), FILE_EXTENSION_NOT_APPLY(HttpStatus.BAD_REQUEST, "지원하지 않는 파일 형식입니다."), diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/global/exception/GlobalCustomException.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/global/exception/GlobalCustomException.java index 1f6c4d057..6eb9ee6a7 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/global/exception/GlobalCustomException.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/global/exception/GlobalCustomException.java @@ -14,4 +14,9 @@ public GlobalCustomException(ErrorMessage errorMessage) { super(errorMessage.getMessage()); this.httpStatus = errorMessage.getHttpStatus(); } + + public GlobalCustomException(ErrorMessage errorMessage, String message) { + super(errorMessage.getMessage() + message); + this.httpStatus = errorMessage.getHttpStatus(); + } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/move/controller/MoveController.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/move/controller/MoveController.java new file mode 100644 index 000000000..b8c990ca5 --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/move/controller/MoveController.java @@ -0,0 +1,44 @@ +package com.pokerogue.helper.move.controller; + +import com.pokerogue.helper.move.dto.MoveResponse; +import com.pokerogue.helper.move.service.MoveService; +import com.pokerogue.helper.util.dto.ApiResponse; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequiredArgsConstructor +public class MoveController { + + private final MoveService moveService; + + @GetMapping("/api/v1/moves") + public ApiResponse> moveListByPokedexNumber(@RequestParam("pokedex-number") Integer pokedexNumber) { + log.info( + "---- URI : {}, Param : {}, ThreadName : {}", + "/api/v1/moves?pokedex-number=", + pokedexNumber, + Thread.currentThread().getName() + ); + + return new ApiResponse<>("포켓몬의 기술 리스트 불러오기에 성공했습니다.", moveService.findMovesByPokemon(pokedexNumber)); + } + + @GetMapping("/api/v1/move/{id}") + public ApiResponse moveDetails(@PathVariable String id) { + log.info( + "---- URI : {}, Param : {}, ThreadName : {}", + "/api/v1/move/{id}", + id, + Thread.currentThread().getName() + ); + + return new ApiResponse<>("포켓몬의 기술 불러오기에 성공했습니다.", moveService.findMove(id)); + } +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/move/converter/FlagConverter.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/move/converter/FlagConverter.java new file mode 100644 index 000000000..f2c26bb4a --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/move/converter/FlagConverter.java @@ -0,0 +1,14 @@ +package com.pokerogue.helper.move.converter; + +import com.pokerogue.helper.move.data.MoveFlag; +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.convert.ReadingConverter; + +@ReadingConverter +public class FlagConverter implements Converter { + + @Override + public MoveFlag convert(String flagData) { + return MoveFlag.convertFrom(flagData); + } +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/move/converter/MoveCategoryConverter.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/move/converter/MoveCategoryConverter.java new file mode 100644 index 000000000..24d831aaf --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/move/converter/MoveCategoryConverter.java @@ -0,0 +1,14 @@ +package com.pokerogue.helper.move.converter; + +import com.pokerogue.helper.move.data.MoveCategory; +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.convert.ReadingConverter; + +@ReadingConverter +public class MoveCategoryConverter implements Converter { + + @Override + public MoveCategory convert(String moveCategoryDate) { + return MoveCategory.convertFrom(moveCategoryDate); + } +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/move/converter/MoveTargetConverter.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/move/converter/MoveTargetConverter.java new file mode 100644 index 000000000..5bb510a94 --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/move/converter/MoveTargetConverter.java @@ -0,0 +1,14 @@ +package com.pokerogue.helper.move.converter; + +import com.pokerogue.helper.move.data.MoveTarget; +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.convert.ReadingConverter; + +@ReadingConverter +public class MoveTargetConverter implements Converter { + + @Override + public MoveTarget convert(String moveTargetData) { + return MoveTarget.convertFrom(moveTargetData); + } +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/move/data/Move.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/move/data/Move.java index 1f9c9f3c6..c9fcf259d 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/move/data/Move.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/move/data/Move.java @@ -1,7 +1,8 @@ package com.pokerogue.helper.move.data; -import com.pokerogue.helper.battle.data.MoveCategory; +import com.pokerogue.helper.type.data.Type; import java.util.List; +import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -11,8 +12,8 @@ @Getter @AllArgsConstructor -@NoArgsConstructor @Document(collection = "move") +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class Move { @Id @@ -25,13 +26,13 @@ public class Move { private String koName; @Field("type") - private String type; // Todo enum 사용 + private Type type; @Field("moveCategory") - private String moveCategory; // Todo + private MoveCategory moveCategory; @Field("moveTarget") - private String moveTarget; // Todo enum 만들기 + private MoveTarget moveTarget; @Field("power") private int power; @@ -58,12 +59,12 @@ public class Move { private String released; @Field("flags") - private List flags; // Todo enum 사용 + private List flags; @Field("pokemonIds") private List pokemonIds; public boolean isAttackMove() { - return MoveCategory.valueOf(this.moveCategory.toUpperCase()) != MoveCategory.STATUS; // Todo + return this.moveCategory != MoveCategory.STATUS; } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/data/MoveCategory.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/move/data/MoveCategory.java similarity index 73% rename from backend/pokerogue/src/main/java/com/pokerogue/helper/battle/data/MoveCategory.java rename to backend/pokerogue/src/main/java/com/pokerogue/helper/move/data/MoveCategory.java index 1c7583516..d5a15022c 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/data/MoveCategory.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/move/data/MoveCategory.java @@ -1,5 +1,7 @@ -package com.pokerogue.helper.battle.data; +package com.pokerogue.helper.move.data; +import com.pokerogue.helper.global.exception.ErrorMessage; +import com.pokerogue.helper.global.exception.GlobalCustomException; import java.util.Arrays; import java.util.Optional; import lombok.Getter; @@ -26,7 +28,7 @@ public enum MoveCategory { public static Optional findByEngName(String name) { return Arrays.stream(values()) - .filter(category -> category.hasSameEngName(name)) + .filter(category -> category.hasSameEngName(name.toLowerCase())) .findAny(); } @@ -37,4 +39,9 @@ private boolean hasSameEngName(String name) { public String getImage() { return image + ".png"; } + + public static MoveCategory convertFrom(String moveCategoryData) { + return findByEngName(moveCategoryData) + .orElseThrow(() -> new GlobalCustomException(ErrorMessage.MOVE_CATEGORY_NOT_FOUND)); + } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/move/data/MoveFlag.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/move/data/MoveFlag.java new file mode 100644 index 000000000..cd7814246 --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/move/data/MoveFlag.java @@ -0,0 +1,43 @@ +package com.pokerogue.helper.move.data; + +import com.pokerogue.helper.global.exception.ErrorMessage; +import com.pokerogue.helper.global.exception.GlobalCustomException; +import java.util.Arrays; + +public enum MoveFlag { + + NONE("none"), + MAKES_CONTACT("makes_contact"), + IGNORE_PROTECT("ignore_protect"), + IGNORE_VIRTUAL("ignore_virtual"), + SOUND_BASED("sound_based"), + HIDE_USER("hide_user"), + HIDE_TARGET("hide_target"), + BITING_MOVE("biting_move"), + PULSE_MOVE("pulse_move"), + PUNCHING_MOVE("punching_move"), + SLICING_MOVE("slicing_move"), + RECKLESS_MOVE("reckless_move"), + BALLBOMB_MOVE("ballbomb_move"), + POWDER_MOVE("powder_move"), + DANCE_MOVE("dance_move"), + WIND_MOVE("wind_move"), + TRIAGE_MOVE("triage_move"), + IGNORE_ABILITIES("ignore_abilities"), + CHECK_ALL_HITS("check_all_hits"), + REDIRECT_COUNTER("redirect_counter"), + ; + + private final String id; + + MoveFlag(String id) { + this.id = id; + } + + public static MoveFlag convertFrom(String flagData) { + return Arrays.stream(MoveFlag.values()) + .filter(moveFlag -> moveFlag.id.equals(flagData)) + .findAny() + .orElseThrow(() -> new GlobalCustomException(ErrorMessage.MOVE_FLAG_NOT_FOUND)); + } +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/move/data/MoveTarget.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/move/data/MoveTarget.java new file mode 100644 index 000000000..ed0980533 --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/move/data/MoveTarget.java @@ -0,0 +1,43 @@ +package com.pokerogue.helper.move.data; + +import com.pokerogue.helper.global.exception.ErrorMessage; +import com.pokerogue.helper.global.exception.GlobalCustomException; +import java.util.Arrays; + +public enum MoveTarget { + + USER("user"), + OTHER("other"), + ALL_OTHERS("all_others"), + NEAR_OTHER("near_other"), + ALL_NEAR_OTHERS("all_near_others"), + NEAR_ENEMY("near_enemy"), + ALL_NEAR_ENEMIES("all_near_enemies"), + RANDOM_NEAR_ENEMY("random_near_enemy"), + ALL_ENEMIES("all_enemies"), + ATTACKER("attacker"), + NEAR_ALLY("near_ally"), + ALLY("ally"), + USER_OR_NEAR_ALLY("user_or_near_ally"), + USER_AND_ALLIES("user_and_allies"), + ALL("all"), + USER_SIDE("user_side"), + ENEMY_SIDE("enemy_side"), + BOTH_SIDES("both_sides"), + PARTY("party"), + CURSE("curse"), + ; + + private final String id; + + MoveTarget(String id) { + this.id = id; + } + + public static MoveTarget convertFrom(String moveTargetData) { + return Arrays.stream(MoveTarget.values()) + .filter(moveTarget -> moveTarget.id.equals(moveTargetData)) + .findAny() + .orElseThrow(() -> new GlobalCustomException(ErrorMessage.MOVE_TARGET_NOT_FOUND)); + } +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/move/service/MoveService.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/move/service/MoveService.java new file mode 100644 index 000000000..adbea2d32 --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/move/service/MoveService.java @@ -0,0 +1,63 @@ +package com.pokerogue.helper.move.service; + +import com.pokerogue.helper.global.exception.ErrorMessage; +import com.pokerogue.helper.global.exception.GlobalCustomException; +import com.pokerogue.helper.move.data.Move; +import com.pokerogue.helper.move.dto.MoveResponse; +import com.pokerogue.helper.move.repository.MoveRepository; +import com.pokerogue.helper.pokemon.data.LevelMove; +import com.pokerogue.helper.pokemon.data.Pokemon; +import com.pokerogue.helper.pokemon.repository.PokemonRepository; +import java.util.ArrayList; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class MoveService { + + private final PokemonRepository pokemonRepository; + private final MoveRepository moveRepository; + + public List findMovesByPokemon(Integer pokedexNumber) { + List pokemons = pokemonRepository.findByPokedexNumber(pokedexNumber); + if (pokemons.isEmpty()) { + throw new GlobalCustomException(ErrorMessage.POKEMON_NOT_FOUND); + } + return makeMoveResponse(pokemons.get(0)); + } + + private List makeMoveResponse(Pokemon pokemon) { + List allMoveIds = getAllMoveIds(pokemon); + List moves = allMoveIds.stream() + .distinct() + .map(this::findMoveById) + .toList(); + + return moves.stream() + .map(MoveResponse::from) + .toList(); + } + + private static List getAllMoveIds(Pokemon pokemon) { + List allMoveIds = new ArrayList<>(); + List levelMoves = pokemon.getLevelMoves().stream() + .map(LevelMove::getMoveId) + .toList(); + allMoveIds.addAll(levelMoves); + allMoveIds.addAll(pokemon.getTechnicalMachineMoveIds()); + allMoveIds.addAll(pokemon.getEggMoveIds()); + return allMoveIds; + } + + public MoveResponse findMove(String id) { + Move move = findMoveById(id); + return MoveResponse.from(move); + } + + private Move findMoveById(String id) { + return moveRepository.findById(id) + .orElseThrow(() -> new GlobalCustomException(ErrorMessage.MOVE_NOT_FOUND)); + } +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/config/ImageUrl.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/config/ImageUrl.java new file mode 100644 index 000000000..17aac1a38 --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/config/ImageUrl.java @@ -0,0 +1,32 @@ +package com.pokerogue.helper.pokemon.config; + +public enum ImageUrl { + + BASE_URL("https://dl70s9ccojnge.cloudfront.net/pokerogue-helper/pokerogue"), + POKEMON_FRONT("/pokemon/front/"), + POKEMON_BACK("/pokemon/back/"), + TYPE("/type/"), + MOVE_CATEGORY("/move-category/"), + BIOME("/biome/"), + ; + + public static final String PNG = ".png"; + private final String url; + + ImageUrl(String url) { + this.url = url; + } + + public static String getPokemonImage(String id) { + return BASE_URL.url + POKEMON_FRONT.url + id + PNG; + } + + public static String getPokemonBackImage(String id) { + return BASE_URL.url + POKEMON_BACK.url + id + PNG; + } + + public static String getBiomeImage(String id) { + return BASE_URL.url + BIOME.url + id + PNG; + } + +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/config/PokemonDatabaseInitializer.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/config/PokemonDatabaseInitializer.java deleted file mode 100644 index eb86030b2..000000000 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/config/PokemonDatabaseInitializer.java +++ /dev/null @@ -1,384 +0,0 @@ -package com.pokerogue.helper.pokemon.config; - -import com.pokerogue.helper.ability.data.Ability; -import com.pokerogue.helper.ability.data.AbilityInfo; -import com.pokerogue.helper.ability.repository.InMemoryAbilityRepository; -import com.pokerogue.helper.global.exception.ErrorMessage; -import com.pokerogue.helper.global.exception.GlobalCustomException; -import com.pokerogue.helper.pokemon.data.Evolution; -import com.pokerogue.helper.pokemon.data.EvolutionChain; -import com.pokerogue.helper.pokemon.data.InMemoryPokemon; -import com.pokerogue.helper.pokemon.repository.EvolutionRepository; -import com.pokerogue.helper.pokemon.repository.InMemoryPokemonRepository; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Queue; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.function.Consumer; -import java.util.stream.Collectors; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.ApplicationArguments; -import org.springframework.boot.ApplicationRunner; -import org.springframework.stereotype.Component; - -@Slf4j -@Component -@RequiredArgsConstructor -public class PokemonDatabaseInitializer implements ApplicationRunner { - - private static final int FIRST_LINE_NUMBER = 3; - private static final String FIELD_DELIMITER = "/"; - private static final String LIST_DELIMITER = ","; - - private final InMemoryPokemonRepository inMemoryPokemonRepository; - private final EvolutionRepository evolutionRepository; - private final InMemoryAbilityRepository inMemoryAbilityRepository; - private final List pokemonKeys = List.of( - "id", - "speciesId", - "nameKo", - "speciesName", - "formName", - "firstType", - "secondType", - "ability1", - "ability2", - "abilityHidden", - "abilityPassive", - "generation", - "legendary", - "subLegendary", - "mythical", - "canChangeForm", - "evolutionLevel", - "baseTotal", - "baseStats", - "height", - "weight", - "eggMoves", - "moves", - "biomes" - ); - private final List moveKeys = List.of( - "id", - "name", - "effect", - "power", - "accuracy", - "type", - "category" - ); - - private final List evolutionChainKeys = List.of( - "from", - "to", - "level", - "item", - "condition" - ); - - @Override - public void run(ApplicationArguments args) { - save("data/pokemon/pokemon.txt", this::savePokemon); - save("data/pokemon/evolution-for-pokemon-response.txt", this::saveEvolution); - saveAbility(); - } - - private void save(String file, Consumer consumer) { - try (InputStream inputStream = getClass() - .getClassLoader() - .getResourceAsStream(file); - BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)) - ) { - consumer.accept(br); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private void savePokemon(BufferedReader br) { - try { - Map> technicalMachineMoveInfos = savetechnicalMachineMoves("data/battle/tms.txt"); - String line; - while ((line = br.readLine()) != null) { - List tokens = parseToken(line); - - if (pokemonKeys.size() != tokens.size()) { - throw new IllegalArgumentException(pokemonKeys.size() + " " + tokens.size() + "포켓몬 데이터가 잘못 되었습니다."); - } - - InMemoryPokemon inMemoryPokemon = createPokemon(tokens, technicalMachineMoveInfos); - inMemoryPokemonRepository.save(inMemoryPokemon.id(), inMemoryPokemon); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private Map> savetechnicalMachineMoves(String path) { - Map> technicalMachineMoveInfos = new HashMap<>(); - try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path); - BufferedReader br = new BufferedReader(new InputStreamReader(inputStream))) { - int lineCount = 0; - String line; - while ((line = br.readLine()) != null) { - lineCount++; - if (lineCount < FIRST_LINE_NUMBER) { - continue; - } - List fields = splitFields(line); - List moveIds = Arrays.stream(fields.get(2).split(LIST_DELIMITER)) - .map(String::trim) - .filter(s -> !s.isEmpty()) - .toList(); - technicalMachineMoveInfos.put(fields.get(0), moveIds); - } - } catch (IOException e) { - log.error("error message : {}", e.getMessage(), e); - } - return technicalMachineMoveInfos; - } - - private List splitFields(String line) { - return Arrays.stream(line.split(FIELD_DELIMITER)) - .map(String::trim) - .map(this::regularizeEmptyField) - .toList(); - } - - private String regularizeEmptyField(String field) { - if (field.equals("EMPTY")) { - return ""; - } - return field; - } - - private InMemoryPokemon createPokemon(List values, Map> technicalMachineMoveInfos) { - List moves = Arrays.stream(values.get(22).split(",")) - .collect(Collectors.toList()); - for (int i = 0; i < moves.size(); i += 2) { - moves.set(i, regularize(moves.get(i))); - } - - List stats = Arrays.stream(regularize(values.get(18)).split(",")) - .mapToInt(Integer::parseInt) - .boxed() - .toList(); - - List technicalMachineMoves = technicalMachineMoveInfos.get(regularize(values.get(1))); - return new InMemoryPokemon( - regularize(values.get(0)), - regularize(values.get(1)), - regularize(values.get(2)), - regularize(values.get(3)), - regularize(values.get(4)), - regularize(values.get(5)), - regularize(values.get(6)), - regularize(values.get(7)), - regularize(values.get(8)), - regularize(values.get(9)), - regularize(values.get(10)), - Integer.valueOf(regularize(values.get(11))), - Boolean.valueOf(regularize(values.get(12))), - Boolean.valueOf(regularize(values.get(13))), - Boolean.valueOf(regularize(values.get(14))), - Boolean.valueOf(regularize(values.get(15))), - Arrays.stream(regularize(values.get(16)).split(",")).toList(), - Integer.parseInt(values.get(17)), - stats.get(0), - stats.get(1), - stats.get(2), - stats.get(3), - stats.get(4), - stats.get(5), - Double.parseDouble(values.get(19)), - Double.parseDouble(values.get(20)), - Arrays.stream(regularize(values.get(21)).split(",")).toList(), - moves, - technicalMachineMoves, - Arrays.stream(regularize(values.get(23)).split(",")).toList() - ); - } - - private void saveEvolution(BufferedReader br) { - try { - String line; - while ((line = br.readLine()) != null) { - List tokens = parseToken(line); - String speciesName = regularize(tokens.get(0)); - - for (int i = 1; i < tokens.size(); i++) { - Evolution evolution = createEvolution(speciesName, tokens.get(i)); - evolutionRepository.saveEdge(speciesName, evolution); - } - } - - for (InMemoryPokemon inMemoryPokemon : inMemoryPokemonRepository.findAll().values()) { - List normalForms = List.of("mega", "mega_x", "mega_y", "primal", "gigantamax", "eternamax"); - if (normalForms.contains(regularize(inMemoryPokemon.formName()))) { - - evolutionRepository.saveEdge( - inMemoryPokemon.speciesName(), - new Evolution(inMemoryPokemon.speciesName(), "1", inMemoryPokemon.id(), "", inMemoryPokemon.formName()) - ); - } - } - createEvolutionChains(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private void createEvolutionChains() { - List evolutions = evolutionRepository.findAll() - .keySet() - .stream() - .sorted(Comparator.comparing(r -> inMemoryPokemonRepository.findById(r) - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.POKEMON_NOT_FOUND)) - .speciesId() - )) - .toList(); - - Set vis = new HashSet<>(); - for (String from : evolutions) { - if (vis.contains(from)) { - continue; - } - EvolutionChain chain = new EvolutionChain(); - createChain(vis, from, chain); - evolutionRepository.saveChain(from, chain); - } - - for (String from : inMemoryPokemonRepository.findAll().keySet()) { - if ( - evolutionRepository.findEvolutionChainById(from).isEmpty() || - evolutionRepository.findEvolutionChainById(from).get().getChain().isEmpty() - ) { - evolutionRepository.saveChain(from, new EvolutionChain(List.of(List.of(from)))); - } - } - - } - - private void createChain(Set vis, String from, EvolutionChain chain) { - Queue q = new LinkedList<>(); - vis.add(from); - q.add(from); - int depth = 0; - while (!q.isEmpty()) { - int qs = q.size(); - while (qs-- > 0) { - String cur = q.poll(); - Optional> edges = evolutionRepository.findEdgeById(cur); - if (edges.isEmpty()) { - continue; - } - for (Evolution edge : edges.get()) { - if (vis.contains(edge.to())) { - continue; - } - q.add(edge.to()); - vis.add(edge.to()); - chain.push(edge, depth); - } - } - depth++; - } - - chain.getAllIds().forEach(id -> evolutionRepository.saveChain(id, chain)); - } - - private Evolution createEvolution(String from, String values) { - List evolveConditions = Arrays.stream(values.split(",")).toList(); - - return new Evolution( - regularize(from), - regularize(evolveConditions.get(0)), - regularize(evolveConditions.get(1)), - regularize(evolveConditions.get(2)), - regularize(evolveConditions.get(3)) - ); - } - - private String regularize(String str) { - String ret = str.strip() - .replace(" ", "_") - .replace("-", "_") - .toLowerCase(); - - if (List.of("empty", "type.undefined", "none").contains(ret)) { - return ""; - } - - return ret; - } - - private List parseToken(String line) { - StringTokenizer stringTokenizer = new StringTokenizer(line, "/"); - - List values = new ArrayList<>(); - while (stringTokenizer.hasMoreTokens()) { - String token = stringTokenizer.nextToken().strip(); - - if (token.contains("undefined")) { - token = ""; - } - - values.add(token); - } - - return values; - } - - private void saveAbility() { - List abilityInfos = new ArrayList<>(); - - try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("data/ability/ability.txt"); - BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { - while (true) { - String abilityInfo = bufferedReader.readLine(); - if (abilityInfo == null) { - break; - } - abilityInfos.add(new AbilityInfo(abilityInfo)); - } - } catch (IOException e) { - log.error("error message : {}", e.getStackTrace()[0]); - } - - abilityInfos.stream() - .map(abilityInfo -> new Ability( - abilityInfo.getId(), - abilityInfo.getName(), - abilityInfo.getDescription(), - getAbilityPokemon(abilityInfo.getPokemons())) - ).forEach(inMemoryAbilityRepository::save); - } - - private List getAbilityPokemon(List pokemons) { - List abilityInMemoryPokemons = new ArrayList<>(); - for (int i = 0; i < pokemons.size(); i++) { - String pokemonId = pokemons.get(i); - - InMemoryPokemon inMemoryPokemon = inMemoryPokemonRepository.findById(pokemonId) - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.POKEMON_NOT_FOUND)); - - abilityInMemoryPokemons.add(inMemoryPokemon); - } - - return abilityInMemoryPokemons; - } -} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/controller/PokemonController.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/controller/PokemonController.java index 3d134f3ac..fd03b55b1 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/controller/PokemonController.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/controller/PokemonController.java @@ -1,8 +1,8 @@ package com.pokerogue.helper.pokemon.controller; -import com.pokerogue.helper.pokemon.dto.PokemonResponse; import com.pokerogue.helper.pokemon.dto.PokemonDetailResponse; +import com.pokerogue.helper.pokemon.dto.PokemonResponse; import com.pokerogue.helper.pokemon.service.PokemonService; import com.pokerogue.helper.util.dto.ApiResponse; import java.util.List; @@ -18,12 +18,12 @@ public class PokemonController { private final PokemonService pokemonService; @GetMapping("/api/v1/pokemons2") - public ApiResponse> findAll() { + public ApiResponse> pokemonList() { return new ApiResponse<>("포켓몬 리스트 불러오기에 성공했습니다.", pokemonService.findAll()); } @GetMapping("/api/v1/pokemon2/{id}") - public ApiResponse findAll(@PathVariable("id") String id) { + public ApiResponse pokemonDetails(@PathVariable("id") String id) { return new ApiResponse<>("포켓몬 정보 불러오기에 성공했습니다.", pokemonService.findById(id)); } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/converter/EvolutionItemConverter.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/converter/EvolutionItemConverter.java new file mode 100644 index 000000000..8e844bcb9 --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/converter/EvolutionItemConverter.java @@ -0,0 +1,14 @@ +package com.pokerogue.helper.pokemon.converter; + +import com.pokerogue.helper.pokemon.data.EvolutionItem; +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.convert.ReadingConverter; + +@ReadingConverter +public class EvolutionItemConverter implements Converter { + + @Override + public EvolutionItem convert(String evolutionItemData) { + return EvolutionItem.convertFrom(evolutionItemData); + } +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/Evolution.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/Evolution.java index 3b0036935..3f727dfa0 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/Evolution.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/Evolution.java @@ -1,37 +1,28 @@ package com.pokerogue.helper.pokemon.data; +import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +import org.springframework.data.mongodb.core.mapping.Field; @Getter @AllArgsConstructor -@NoArgsConstructor -public final class Evolution { +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Evolution { + @Field("from") private String from; - private String level; - private String to; - private String item; - private String condition; - - public String from() { // Todo: 이 메소드들 지우기 - return from; - } - public String level() { - return level; - } + @Field("level") + private Integer level; - public String to() { - return to; - } + @Field("to") + private String to; - public String item() { - return item; - } + @Field("item") + private String item; - public String condition() { - return condition; - } + @Field("condition") + private String condition; } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/EvolutionChain.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/EvolutionChain.java deleted file mode 100644 index 43794659e..000000000 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/EvolutionChain.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.pokerogue.helper.pokemon.data; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; - - -public class EvolutionChain { - private List> chain = new ArrayList<>(); - - public EvolutionChain() { - } - - public EvolutionChain(List> newChain) { - this.chain = newChain; - } - - public void push(Evolution evolution, int depth) { - while (chain.size() <= depth + 1) { - chain.add(new ArrayList<>()); - } - - chain.get(depth).add(evolution.from()); - chain.get(depth + 1).add(evolution.to()); - - chain.set(depth, chain.get(depth).stream().distinct().collect(Collectors.toList())); - chain.set(depth + 1, chain.get(depth + 1).stream().distinct().collect(Collectors.toList())); - } - - public List getAllIds() { - return chain.stream() - .flatMap(Collection::stream) - .toList(); - } - - public List> getChain() { - return chain; - } -} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/EvolutionItem.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/EvolutionItem.java index fbfa52e2b..a6cb1bfad 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/EvolutionItem.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/EvolutionItem.java @@ -1,11 +1,14 @@ package com.pokerogue.helper.pokemon.data; +import com.pokerogue.helper.global.exception.ErrorMessage; +import com.pokerogue.helper.global.exception.GlobalCustomException; import java.util.Arrays; +import java.util.Optional; import lombok.Getter; @Getter public enum EvolutionItem { - EMPTY(""), + LINKING_CORD("연결의끈"), SUN_STONE("태양의돌"), MOON_STONE("달의돌"), @@ -31,9 +34,122 @@ public enum EvolutionItem { MALICIOUS_ARMOR("저주받은갑옷"), MASTERPIECE_TEACUP("걸작찻잔"), METAL_ALLOY("복합금속"), - SCROLL_OF_DARKNESS("악의족자"), - SCROLL_OF_WATERS("물의족자"), + SCROLL_OF_DARKNESS("악의 족자"), + SCROLL_OF_WATERS("물의 족자"), SYRUPY_APPLE("꿀맛사과"), + ABOMASITE("눈설왕나이트"), + ABSOLITE("앱솔나이트"), + AERODACTYLITE("프테라나이트"), + AGGRONITE("보스로라나이트"), + ALAKAZITE("후딘나이트"), + ALTARIANITE("파비코리나이트"), + AMPHAROSITE("전룡나이트"), + AUDINITE("다부니나이트"), + BANETTITE("다크펫나이트"), + BEEDRILLITE("독침붕나이트"), + BLASTOISINITE("거북왕나이트"), + BLAZIKENITE("번치코나이트"), + CAMERUPTITE("폭타나이트"), + CHARIZARDITE_X("리자몽나이트 X"), + CHARIZARDITE_Y("리자몽나이트 Y"), + DIANCITE("디안시나이트"), + GALLADITE("엘레이드나이트"), + GARCHOMPITE("한카리아스나이트"), + GARDEVOIRITE("가디안나이트"), + GENGARITE("팬텀나이트"), + GLALITITE("얼음귀신나이트"), + GYARADOSITE("갸라도스나이트"), + HERACRONITE("헤라크로스나이트"), + HOUNDOOMINITE("헬가나이트"), + KANGASKHANITE("캥카나이트"), + LATIASITE("라티아스나이트"), + LATIOSITE("라티오스나이트"), + LOPUNNITE("이어롭나이트"), + LUCARIONITE("루카리오나이트"), + MANECTITE("썬더볼트나이트"), + MAWILITE("입치트나이트"), + MEDICHAMITE("요가램나이트"), + METAGROSSITE("메타그로스나이트"), + MEWTWONITE_X("뮤츠나이트 X"), + MEWTWONITE_Y("뮤츠나이트 Y"), + PIDGEOTITE("피죤투나이트"), + PINSIRITE("쁘사이저나이트"), + RAYQUAZITE("레쿠쟈나이트"), + SABLENITE("깜까미나이트"), + SALAMENCITE("보만다나이트"), + SCEPTILITE("나무킹나이트"), + SCIZORITE("핫삼나이트"), + SHARPEDONITE("샤크니아나이트"), + SLOWBRONITE("야도란나이트"), + STEELIXITE("강철톤나이트"), + SWAMPERTITE("대짱이나이트"), + TYRANITARITE("마기라스나이트"), + VENUSAURITE("이상해꽃나이트"), + BLUE_ORB("쪽빛구슬"), + RED_ORB("주홍구슬"), + SHARP_METEORITE("뾰족한운석"), + HARD_METEORITE("단단한운석"), + SMOOTH_METEORITE("부드러운운석"), + ADAMANT_CRYSTAL("큰금강옥"), + LUSTROUS_GLOBE("큰백옥"), + GRISEOUS_CORE("큰백금옥"), + REVEAL_GLASS("비추는거울"), + GRACIDEA("그라시데아꽃"), + MAX_MUSHROOMS("다이버섯"), + DARK_STONE("다크스톤"), + LIGHT_STONE("라이트스톤"), + PRISON_BOTTLE("굴레의항아리"), + N_LUNARIZER("네크로플러스루나"), + N_SOLARIZER("네크로플러스솔"), + RUSTED_SWORD("녹슨검"), + RUSTED_SHIELD("녹슨방패"), + ICY_REINS_OF_UNITY("차가운유대의고삐"), + SHADOW_REINS_OF_UNITY("검은유대의고삐"), + WELLSPRING_MASK("우물의가면"), + HEARTHFLAME_MASK("화덕의가면"), + CORNERSTONE_MASK("주춧돌의가면"), + SHOCK_DRIVE("번개카세트"), + BURN_DRIVE("블레이즈카세트"), + CHILL_DRIVE("프리즈카세트"), + DOUSE_DRIVE("아쿠아카세트"), + FIST_PLATE("주먹플레이트"), + SKY_PLATE("푸른하늘플레이트"), + TOXIC_PLATE("맹독플레이트"), + EARTH_PLATE("대지플레이트"), + STONE_PLATE("암석플레이트"), + INSECT_PLATE("비단벌레플레이트"), + SPOOKY_PLATE("원령플레이트"), + IRON_PLATE("강철플레이트"), + FLAME_PLATE("불구슬플레이트"), + SPLASH_PLATE("물방울플레이트"), + MEADOW_PLATE("초록플레이트"), + ZAP_PLATE("우뢰플레이트"), + MIND_PLATE("이상한플레이트"), + ICICLE_PLATE("고드름플레이트"), + DRACO_PLATE("용의플레이트"), + DREAD_PLATE("공포플레이트"), + PIXIE_PLATE("정령플레이트"), + BLANK_PLATE("순백플레이트"), + LEGEND_PLATE("레전드플레이트"), + FIGHTING_MEMORY("파이팅메모리"), + FLYING_MEMORY("플라잉메모리"), + POISON_MEMORY("포이즌메모리"), + GROUND_MEMORY("그라운드메모리"), + ROCK_MEMORY("록메모리"), + BUG_MEMORY("버그메모리"), + GHOST_MEMORY("고스트메모리"), + STEEL_MEMORY("스틸메모리"), + FIRE_MEMORY("파이어메모리"), + WATER_MEMORY("워터메모리"), + GRASS_MEMORY("그래스메모리"), + ELECTRIC_MEMORY("일렉트릭메모리"), + PSYCHIC_MEMORY("사이킥메모리"), + ICE_MEMORY("아이스메모리"), + DRAGON_MEMORY("드래곤메모리"), + DARK_MEMORY("다크메모리"), + FAIRY_MEMORY("페어리메모리"), + BLANK_MEMORY("빈메모리"), + ULTRANECROZIUM_Z("울트라네크로"), ; private final String koName; @@ -42,12 +158,15 @@ public enum EvolutionItem { this.koName = koName; } - public static EvolutionItem findById(String id) { + public static Optional findById(String id) { return Arrays.stream(values()) .filter(value -> value.name() .toLowerCase() .equals(id)) - .findAny() - .orElse(EMPTY); + .findAny(); + } + + public static EvolutionItem convertFrom(String evolutionItemData) { + return findById(evolutionItemData).orElseThrow(()->new GlobalCustomException(ErrorMessage.ITEM_NOT_FOUND)); } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/FormChange.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/FormChange.java index d8f005d80..d47f90c5a 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/FormChange.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/FormChange.java @@ -1,16 +1,23 @@ package com.pokerogue.helper.pokemon.data; -import lombok.AllArgsConstructor; +import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; +import org.springframework.data.mongodb.core.mapping.Field; @Getter -@AllArgsConstructor -@NoArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class FormChange { + @Field("from") private String from; + + @Field("previousForm") private String previousForm; + + @Field("currentForm") private String currentForm; - private String item; // Todo: enum + + @Field("item") + private EvolutionItem item; } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/InMemoryPokemon.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/InMemoryPokemon.java deleted file mode 100644 index eca034812..000000000 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/InMemoryPokemon.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.pokerogue.helper.pokemon.data; - -import com.pokerogue.helper.type.data.Type; -import java.util.List; - -public record InMemoryPokemon( - String id, - String speciesId, - String koName, - String speciesName, - String formName, - String firstType, - String secondType, - String ability1, - String ability2, - String abilityHidden, - String abilityPassive, - Integer generation, - Boolean legendary, - Boolean subLegendary, - Boolean mythical, - Boolean canChangeForm, - List evolutionLevel, - Integer baseTotal, - Integer hp, - Integer attack, - Integer defense, - Integer specialAttack, - Integer specialDefense, - Integer speed, - Double height, - Double weight, - List eggMoves, - List moves, - List technicalMachineMoves, - List biomes -) { - - public boolean hasSameType(Type moveType) { - String engName = moveType.getName(); - return (engName.equals(firstType) || engName.equals(secondType)); - } -} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/LevelMove.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/LevelMove.java index 56a606f2c..36252e88c 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/LevelMove.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/LevelMove.java @@ -1,15 +1,19 @@ package com.pokerogue.helper.pokemon.data; +import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.RequiredArgsConstructor; +import org.springframework.data.mongodb.core.mapping.Field; @Getter @AllArgsConstructor -@NoArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class LevelMove { + @Field("level") private int level; + + @Field("moveId") private String moveId; } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/Pokemon.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/Pokemon.java index bee2a3560..271850a33 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/Pokemon.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/Pokemon.java @@ -5,12 +5,16 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; @Getter @AllArgsConstructor +@Setter +@ToString @NoArgsConstructor @Document(collection = "pokemon") public class Pokemon { @@ -46,7 +50,7 @@ public class Pokemon { private int friendship; @Field("types") - private List types; // Todo enum + private List types; @Field("normalAbilityIds") private List normalAbilityIds; @@ -115,9 +119,8 @@ public class Pokemon { private List biomeIds; public boolean hasSameType(Type type) { - String name = type.getName(); return this.types.stream() - .anyMatch(name::equals); + .anyMatch(myType -> myType == type); } public boolean isFasterThan(Pokemon other) { diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/Type.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/Type.java deleted file mode 100644 index 18bf7c4ff..000000000 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/data/Type.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.pokerogue.helper.pokemon.data; - -import java.util.Arrays; -import lombok.Getter; - -@Getter -public enum Type { - - UNKNOWN("UNKNOWN", "Unknown"), - NORMAL("NORMAL", "노말"), - FIGHTING("FIGHTING", "격투"), - FLYING("FLYING", "비행"), - POISON("POISON", "독"), - GROUND("GROUND", "땅"), - ROCK("ROCK", "바위"), - BUG("BUG", "벌레"), - GHOST("GHOST", "고스트"), - STEEL("STEEL", "강철"), - FIRE("FIRE", "불꽃"), - WATER("WATER", "물"), - GRASS("GRASS", "풀"), - ELECTRIC("ELECTRIC", "전기"), - PSYCHIC("PSYCHIC", "에스퍼"), - ICE("ICE", "얼음"), - DRAGON("DRAGON", "드래곤"), - DARK("DARK", "악"), - FAIRY("FAIRY", "페어리"), - STELLAR("STELLAR", "스텔라"), - EMPTY("", ""); - - private final String id; - private final String name; - - Type(String id, String name) { - this.id = id; - this.name = name; - } - - public static Type findById(String id) { - return Arrays.stream(values()) - .filter(value -> value.getId() - .replace("-", "_") - .replace(" ", "_") - .toLowerCase() - .equals(id) - ) - .findFirst() - .orElse(EMPTY); - } - - public static Type findByName(String name) { - return Arrays.stream(values()) - .filter(value -> value.getName() - .toLowerCase() - .equals(name) - ) - .findFirst() - .orElse(EMPTY); - } -} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/EggMoveResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/EggMoveResponse.java new file mode 100644 index 000000000..bcef25715 --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/EggMoveResponse.java @@ -0,0 +1,36 @@ +package com.pokerogue.helper.pokemon.dto; + +import com.pokerogue.helper.move.data.Move; +import com.pokerogue.helper.move.data.MoveCategory; +import com.pokerogue.helper.type.data.Type; + +public record EggMoveResponse( + String id, + String name, + Integer level, + Integer power, + Integer accuracy, + String type, + String typeLogo, + String category, + String categoryLogo +) { + + public static EggMoveResponse from(Move move) { + MoveCategory moveCategory = move.getMoveCategory(); + Type type = move.getType(); + + return new EggMoveResponse( + move.getId(), + move.getKoName(), + 1, + move.getPower(), + move.getAccuracy(), + type.getName(), + type.getImage(), + moveCategory.getName(), + moveCategory.getImage() + ); + } + +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/EvolutionResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/EvolutionResponse.java index 3b970e7f1..e58e1e597 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/EvolutionResponse.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/EvolutionResponse.java @@ -1,6 +1,9 @@ package com.pokerogue.helper.pokemon.dto; +import com.pokerogue.helper.pokemon.data.Evolution; +import com.pokerogue.helper.pokemon.data.Pokemon; + public record EvolutionResponse( String id, String name, @@ -11,4 +14,15 @@ public record EvolutionResponse( String image ) { + public static EvolutionResponse from(Pokemon pokemon, Evolution evolution, Integer depth) { + return new EvolutionResponse( + pokemon.getId(), + pokemon.getKoName(), + evolution.getLevel(), + depth, + evolution.getItem(), + evolution.getCondition(), + pokemon.getImageId() + ); + } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/EvolutionResponses.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/EvolutionResponses.java index eace06232..65afb5d9f 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/EvolutionResponses.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/EvolutionResponses.java @@ -3,5 +3,4 @@ import java.util.List; public record EvolutionResponses(int currentDepth, List stages) { - } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/MoveResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/MoveResponse.java deleted file mode 100644 index 197fb5017..000000000 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/MoveResponse.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.pokerogue.helper.pokemon.dto; - -import com.pokerogue.helper.battle.data.BattleMove; -import com.pokerogue.helper.battle.data.MoveCategory; -import com.pokerogue.helper.pokemon.data.Type; - -public record MoveResponse( - String id, - String name, - Integer level, - Integer power, - Integer accuracy, - String type, - String typeLogo, - String category, - String categoryLogo -) { - - public static MoveResponse from(BattleMove battleMove, Integer level, String typeImageFromS3) { - MoveCategory moveCategory = battleMove.category(); - Type firstType = Type.findById(battleMove.type().getKoName()); - - return new MoveResponse( - battleMove.id(), - battleMove.name(), - level, - battleMove.power(), - battleMove.accuracy(), - firstType.getName(), - typeImageFromS3, - moveCategory.getName(), - moveCategory.getImage() - ); - } - -} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonAbilityResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonAbilityResponse.java index b1465837c..c20af8392 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonAbilityResponse.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonAbilityResponse.java @@ -1,8 +1,44 @@ package com.pokerogue.helper.pokemon.dto; +import com.pokerogue.helper.ability.data.Ability; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + public record PokemonAbilityResponse(String id, String name, String description, Boolean passive, Boolean hidden) { - public static PokemonAbilityResponse from(String name, String description, boolean passive, boolean hidden) { - return new PokemonAbilityResponse(name, name, description, passive, hidden); + public static PokemonAbilityResponse from(Ability ability, boolean isPassive, boolean isHidden) { + return new PokemonAbilityResponse( + ability.getId(), + ability.getKoName(), + ability.getDescription(), + isPassive, + isHidden + ); + } + + + public static List createListFrom(List> abilities) { + final int HIDDEN_INDEX = abilities.size() - 1; + final int PASSIVE_INDEX = abilities.size() - 2; + + List> normals = abilities.subList(0, HIDDEN_INDEX); + Optional hidden = abilities.get(HIDDEN_INDEX); + Optional passive = abilities.get(PASSIVE_INDEX); + + List normalResponse = normals.stream() + .filter(Optional::isPresent) + .map(Optional::get) + .map(normal -> from(normal, false, false)) + .toList(); + + Optional passiveResponse = passive.map(ability -> from(ability, true, false)); + Optional hiddenResponse = hidden.map(ability -> from(ability, false, true)); + + List totalResponse = new ArrayList<>(normalResponse); + passiveResponse.ifPresent(totalResponse::add); + hiddenResponse.ifPresent(totalResponse::add); + + return totalResponse; } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonBiomeResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonBiomeResponse.java index 797376d4d..edded3bde 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonBiomeResponse.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonBiomeResponse.java @@ -1,5 +1,10 @@ package com.pokerogue.helper.pokemon.dto; -public record PokemonBiomeResponse(String id, String name, String image) { +import com.pokerogue.helper.biome.data.Biome; +import com.pokerogue.helper.pokemon.config.ImageUrl; +public record PokemonBiomeResponse(String id, String name, String image) { + public static PokemonBiomeResponse from(Biome biome) { + return new PokemonBiomeResponse(biome.getId(), biome.getKoName(), ImageUrl.getBiomeImage(biome.getId())); + } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonDetailResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonDetailResponse.java index 33f53ff97..d890d1449 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonDetailResponse.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonDetailResponse.java @@ -1,5 +1,7 @@ package com.pokerogue.helper.pokemon.dto; +import com.pokerogue.helper.pokemon.config.ImageUrl; +import com.pokerogue.helper.pokemon.data.Pokemon; import com.pokerogue.helper.type.dto.PokemonTypeResponse; import java.util.List; @@ -24,8 +26,43 @@ public record PokemonDetailResponse( Double weight, Double height, EvolutionResponses evolutions, - List moves, - List eggMoveResponses, + List moves, + List eggMoveResponses, List biomes ) { + public static PokemonDetailResponse from( + Pokemon pokemon, + List pokemonTypeResponses, + List pokemonAbilityResponses, + List moveResponse, + List eggMoveResponse, + List biomeResponse, + EvolutionResponses evolutionResponses + ) { + return new PokemonDetailResponse( + pokemon.getId(), + (long) pokemon.getPokedexNumber(), + pokemon.getKoName(), + ImageUrl.getPokemonImage(pokemon.getImageId()), + pokemonTypeResponses, + pokemonAbilityResponses, + pokemon.getBaseTotal(), + pokemon.getHp(), + pokemon.getAttack(), + pokemon.getDefense(), + pokemon.getSpecialAttack(), + pokemon.getSpecialDefense(), + pokemon.getSpeed(), + pokemon.isLegendary(), + pokemon.isSubLegendary(), + pokemon.isMythical(), + pokemon.isCanChangeForm(), + pokemon.getWeight(), + pokemon.getHeight(), + evolutionResponses, + moveResponse, + eggMoveResponse, + biomeResponse + ); + } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonMoveResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonMoveResponse.java new file mode 100644 index 000000000..d92af6b62 --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonMoveResponse.java @@ -0,0 +1,36 @@ +package com.pokerogue.helper.pokemon.dto; + +import com.pokerogue.helper.move.data.Move; +import com.pokerogue.helper.move.data.MoveCategory; +import com.pokerogue.helper.type.data.Type; + +public record PokemonMoveResponse( + String id, + String name, + Integer level, + Integer power, + Integer accuracy, + String type, + String typeLogo, + String category, + String categoryLogo +) { + + public static PokemonMoveResponse from(Move move, Integer level) { + MoveCategory moveCategory = move.getMoveCategory(); + Type moveType = move.getType(); + + return new PokemonMoveResponse( + move.getId(), + move.getKoName(), + level, + move.getPower(), + move.getAccuracy(), + moveType.getName(), + moveType.getImage(), + moveCategory.getName(), + moveCategory.getImage() + ); + } + +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonResponse.java index d169d5182..5a37fb43a 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonResponse.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/dto/PokemonResponse.java @@ -1,6 +1,7 @@ package com.pokerogue.helper.pokemon.dto; -import com.pokerogue.helper.pokemon.data.InMemoryPokemon; +import com.pokerogue.helper.pokemon.config.ImageUrl; +import com.pokerogue.helper.pokemon.data.Pokemon; import com.pokerogue.helper.type.dto.PokemonTypeResponse; import java.util.List; @@ -21,24 +22,23 @@ public record PokemonResponse( Integer specialAttack, Integer specialDefense ) { - public static PokemonResponse from(InMemoryPokemon inMemoryPokemon, String image, String backImage, List pokemonTypeResponse) { - + public static PokemonResponse from(Pokemon pokemon, List pokemonTypeResponses) { return new PokemonResponse( - inMemoryPokemon.id(), - Long.parseLong(inMemoryPokemon.speciesId()), - inMemoryPokemon.koName(), - inMemoryPokemon.formName(), - image, - backImage, - pokemonTypeResponse, - inMemoryPokemon.generation(), - inMemoryPokemon.baseTotal(), - inMemoryPokemon.hp(), - inMemoryPokemon.attack(), - inMemoryPokemon.defense(), - inMemoryPokemon.specialAttack(), - inMemoryPokemon.specialDefense(), - inMemoryPokemon.speed() + pokemon.getId(), + (long) pokemon.getPokedexNumber(), + pokemon.getKoName(), + pokemon.getFormName(), + ImageUrl.getPokemonImage(pokemon.getImageId()), //image front + ImageUrl.getPokemonBackImage(pokemon.getImageId()), //back + pokemonTypeResponses, + pokemon.getGeneration(), + pokemon.getBaseTotal(), + pokemon.getHp(), + pokemon.getAttack(), + pokemon.getDefense(), + pokemon.getSpecialAttack(), + pokemon.getSpecialDefense(), + pokemon.getSpeed() ); } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/repository/EvolutionRepository.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/repository/EvolutionRepository.java deleted file mode 100644 index 5125819c2..000000000 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/repository/EvolutionRepository.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.pokerogue.helper.pokemon.repository; - -import com.pokerogue.helper.pokemon.data.Evolution; -import com.pokerogue.helper.pokemon.data.EvolutionChain; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import org.springframework.stereotype.Repository; - -@Repository -public class EvolutionRepository { - private final Map> edges = new HashMap<>(); - private final Map chains = new HashMap<>(); - - public Map> findAll() { - return Collections.unmodifiableMap(edges); - } - - public Optional> findEdgeById(String id) { - return Optional.ofNullable(edges.get(id)); - } - - public Optional findEvolutionChainById(String id) { - return Optional.ofNullable(chains.get(id)); - } - - public void saveEdge(String key, Evolution value) { - edges.putIfAbsent(key, new ArrayList<>()); - edges.get(key).add(value); - } - - public void saveChain(String id, EvolutionChain value) { - chains.put(id, value); - } -} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/repository/InMemoryPokemonRepository.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/repository/InMemoryPokemonRepository.java deleted file mode 100644 index cfbcd5da9..000000000 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/repository/InMemoryPokemonRepository.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.pokerogue.helper.pokemon.repository; - - -import com.pokerogue.helper.pokemon.data.InMemoryPokemon; -import java.util.Collections; -import java.util.Map; -import java.util.Optional; -import java.util.TreeMap; -import org.springframework.stereotype.Repository; - -@Repository -public class InMemoryPokemonRepository { - private final Map data = new TreeMap<>(); - - public Map findAll() { - return Collections.unmodifiableMap(data); - } - - public Optional findById(String id) { - return Optional.ofNullable(data.get(id)); - } - - public void save(String key, InMemoryPokemon inMemoryPokemon) { - data.put(key, inMemoryPokemon); - } -} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/repository/PokemonRepository.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/repository/PokemonRepository.java index e8a0baba5..05fc4d910 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/repository/PokemonRepository.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/repository/PokemonRepository.java @@ -1,7 +1,10 @@ package com.pokerogue.helper.pokemon.repository; import com.pokerogue.helper.pokemon.data.Pokemon; +import java.util.List; import org.springframework.data.mongodb.repository.MongoRepository; public interface PokemonRepository extends MongoRepository { + + List findByPokedexNumber(int pokedexNumber); } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/service/BufferedQueue.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/service/BufferedQueue.java new file mode 100644 index 000000000..894c32aad --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/service/BufferedQueue.java @@ -0,0 +1,45 @@ +package com.pokerogue.helper.pokemon.service; + +import java.util.Queue; + +public class BufferedQueue { + + private final Queue value; + private int bufferCapacity; + private int bufferCount; + + public BufferedQueue(Queue queue) { + this.value = queue; + } + + public boolean hasNext() { + return !value.isEmpty(); + } + + public T poll() { + T removedValue = value.remove(); + bufferCapacity = Math.max(bufferCapacity - 1, 0); + return removedValue; + } + + public void add(T s) { + value.add(s); + } + + public boolean hasBufferedNext() { + return bufferCapacity > 0; + } + + public void buffer() { + bufferCapacity = value.size(); + bufferCount++; + } + + public int getBufferCount() { + return bufferCount; + } + + public int getSize() { + return value.size(); + } +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/service/EvolutionContext.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/service/EvolutionContext.java new file mode 100644 index 000000000..aabd11cdf --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/service/EvolutionContext.java @@ -0,0 +1,45 @@ +package com.pokerogue.helper.pokemon.service; + +import com.pokerogue.helper.global.exception.ErrorMessage; +import com.pokerogue.helper.global.exception.GlobalCustomException; +import com.pokerogue.helper.pokemon.data.Evolution; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + + +public class EvolutionContext { + + private final List evolutions; + private final Map> edges; + private final Map depth; + + public EvolutionContext(List evolutions) { + this.evolutions = evolutions; + this.edges = createEdges(evolutions); + this.depth = new TreeDepthCalculator(edges).calculateDepths(); + } + + private Map> createEdges(List evolutions) { + return evolutions.stream() + .collect(Collectors.groupingBy( + Evolution::getFrom, + Collectors.mapping(Evolution::getTo, Collectors.toList())) + ); + } + + public Evolution getEvolutionOf(String pokemonId) { + return Stream.of( + evolutions.stream().filter(evolution -> evolution.getTo().equals(pokemonId)), + evolutions.stream().filter(evolution -> evolution.getFrom().equals(pokemonId)) + ) + .flatMap(stream -> stream) + .findFirst() + .orElseThrow(() -> new GlobalCustomException(ErrorMessage.POKEMON_NOT_FOUND)); + } + + public Integer getDepthOf(String pokemonId) { + return depth.getOrDefault(pokemonId, -1); // TODO: 진화체인 없으면 depth -1을 반환..? 얘기 해보기 + } +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/service/EvolutionService.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/service/EvolutionService.java new file mode 100644 index 000000000..07ed7daa0 --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/service/EvolutionService.java @@ -0,0 +1,47 @@ +package com.pokerogue.helper.pokemon.service; + +import com.pokerogue.helper.pokemon.data.Evolution; +import com.pokerogue.helper.pokemon.data.Pokemon; +import com.pokerogue.helper.pokemon.dto.EvolutionResponse; +import com.pokerogue.helper.pokemon.dto.EvolutionResponses; +import com.pokerogue.helper.pokemon.repository.PokemonRepository; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + + +@Service +@RequiredArgsConstructor +public class EvolutionService { + + private final PokemonRepository pokemonRepository; + + public EvolutionResponses getEvolutionResponses(Pokemon pokemon) { + List evolutions = pokemon.getEvolutions(); + List connectedPokemons = createConnectedPokemons(evolutions); + EvolutionContext evolutionContext = new EvolutionContext(evolutions); + + List responses = connectedPokemons.stream() + .map(connectedPokemon -> createEvolutionResponse(connectedPokemon, evolutionContext)) + .toList(); + + return new EvolutionResponses(evolutionContext.getDepthOf(pokemon.getId()), responses); + } + + private EvolutionResponse createEvolutionResponse(Pokemon pokemon, EvolutionContext evolutionContext) { + return EvolutionResponse.from(pokemon, evolutionContext.getEvolutionOf(pokemon.getId()), + evolutionContext.getDepthOf(pokemon.getId())); + } + + private List createConnectedPokemons(List evolutions) { + return evolutions.stream() + .flatMap(evolution -> Stream.of(evolution.getFrom(), evolution.getTo())) + .distinct() + .map(pokemonRepository::findById) + .filter(Optional::isPresent) // TODO: data is inconsistent, isPresent is change to throw + .map(Optional::get) + .toList(); + } +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/service/PokemonService.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/service/PokemonService.java index 94e7080dd..1ca748fb0 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/service/PokemonService.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/service/PokemonService.java @@ -1,38 +1,27 @@ package com.pokerogue.helper.pokemon.service; -import com.pokerogue.external.s3.service.S3Service; import com.pokerogue.helper.ability.data.Ability; -import com.pokerogue.helper.ability.repository.InMemoryAbilityRepository; -import com.pokerogue.helper.battle.BattleMoveRepository; -import com.pokerogue.helper.biome.data.Biome; -import com.pokerogue.helper.biome.repository.InMemoryBiomeRepository; +import com.pokerogue.helper.ability.repository.AbilityRepository; +import com.pokerogue.helper.biome.repository.BiomeRepository; import com.pokerogue.helper.global.exception.ErrorMessage; import com.pokerogue.helper.global.exception.GlobalCustomException; -import com.pokerogue.helper.pokemon.data.Evolution; -import com.pokerogue.helper.pokemon.data.EvolutionChain; -import com.pokerogue.helper.pokemon.data.EvolutionItem; -import com.pokerogue.helper.pokemon.data.InMemoryPokemon; -import com.pokerogue.helper.pokemon.data.Type; -import com.pokerogue.helper.pokemon.dto.EvolutionResponse; +import com.pokerogue.helper.move.data.Move; +import com.pokerogue.helper.move.repository.MoveRepository; +import com.pokerogue.helper.pokemon.data.LevelMove; +import com.pokerogue.helper.pokemon.data.Pokemon; +import com.pokerogue.helper.pokemon.dto.EggMoveResponse; import com.pokerogue.helper.pokemon.dto.EvolutionResponses; -import com.pokerogue.helper.pokemon.dto.MoveResponse; import com.pokerogue.helper.pokemon.dto.PokemonAbilityResponse; import com.pokerogue.helper.pokemon.dto.PokemonBiomeResponse; import com.pokerogue.helper.pokemon.dto.PokemonDetailResponse; +import com.pokerogue.helper.pokemon.dto.PokemonMoveResponse; import com.pokerogue.helper.pokemon.dto.PokemonResponse; -import com.pokerogue.helper.pokemon.repository.EvolutionRepository; -import com.pokerogue.helper.pokemon.repository.InMemoryPokemonRepository; +import com.pokerogue.helper.pokemon.repository.PokemonRepository; +import com.pokerogue.helper.type.data.Type; import com.pokerogue.helper.type.dto.PokemonTypeResponse; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import java.util.stream.Stream; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -40,242 +29,98 @@ @RequiredArgsConstructor public class PokemonService { - private final S3Service s3Service; - private final InMemoryPokemonRepository inMemoryPokemonRepository; - private final BattleMoveRepository battleMoveRepository; - private final EvolutionRepository evolutionRepository; - private final InMemoryBiomeRepository inMemoryBiomeRepository; - private final InMemoryAbilityRepository inMemoryAbilityRepository; + private final PokemonRepository pokemonRepository; + private final MoveRepository moveRepository; + private final BiomeRepository biomeRepository; + private final AbilityRepository abilityRepository; + private final EvolutionService evolutionService; - private List findAllCache = List.of(); - private Map findByIdCache = new HashMap<>(); - - public List findAll() { - if (findAllCache.isEmpty()) { - initFindAllCache(); - } - return findAllCache; - } + public PokemonDetailResponse findById(String id) { + Pokemon pokemon = pokemonRepository.findById(id) + .orElseThrow(() -> new GlobalCustomException(ErrorMessage.POKEMON_NOT_FOUND)); - private void initFindAllCache() { - findAllCache = inMemoryPokemonRepository.findAll().values().stream() - .map(pokemon -> PokemonResponse.from( - pokemon, - s3Service.getPokemonImageFromS3(pokemon.id()), - s3Service.getPokemonBackImageFromS3(pokemon.id()), - createTypeResponse(pokemon) - )) - .sorted(Comparator.comparingLong(PokemonResponse::pokedexNumber)) - .toList(); + return createPokemonDetailResponse(pokemon); } - public PokemonDetailResponse findById(String id) { - if (findByIdCache.isEmpty()) { - initFindByIdCache(); - } - return findByIdCache.get(id); - } + public List findAll() { + List pokemons = pokemonRepository.findAll(); - private void initFindByIdCache() { - List pokemonDetailRespons = inMemoryPokemonRepository.findAll().values() - .stream() - .map(this::toPokemon2DetailResponse) + return pokemons.stream() + .map(pokemon -> PokemonResponse.from(pokemon, createTypeResponse(pokemon))) .toList(); - - findByIdCache = pokemonDetailRespons.stream().collect( - Collectors.toMap( - PokemonDetailResponse::id, - Function.identity() - )); } - private PokemonDetailResponse toPokemon2DetailResponse(InMemoryPokemon inMemoryPokemon) { - List pokemonTypeResponses = createTypeResponse(inMemoryPokemon); - List pokemonAbilityResponses = createAbilityResponse(inMemoryPokemon); - EvolutionResponses evolutionResponses = createEvolutionResponse(inMemoryPokemon); - List moveResponse = createMoveResponse(inMemoryPokemon.moves()); - List eggMoveResponse = createEggMoveResponse(inMemoryPokemon.eggMoves()); - List biomeResponse = createBiomeResponse(inMemoryPokemon.biomes()); + private PokemonDetailResponse createPokemonDetailResponse(Pokemon pokemon) { + List pokemonTypeResponses = createTypeResponse(pokemon); + List pokemonAbilityResponses = createAbilityResponse(pokemon); + List moveResponse = createMoveResponse(pokemon); + List eggMoveResponses = createEggMoveResponse(pokemon); + List biomeResponses = createBiomeResponse(pokemon); + EvolutionResponses evolutionResponses = evolutionService.getEvolutionResponses(pokemon); - return new PokemonDetailResponse( - inMemoryPokemon.id(), - Long.parseLong(inMemoryPokemon.speciesId()), - inMemoryPokemon.koName(), - s3Service.getPokemonImageFromS3(inMemoryPokemon.id()), + return PokemonDetailResponse.from( + pokemon, pokemonTypeResponses, pokemonAbilityResponses, - inMemoryPokemon.baseTotal(), - inMemoryPokemon.hp(), - inMemoryPokemon.attack(), - inMemoryPokemon.defense(), - inMemoryPokemon.specialAttack(), - inMemoryPokemon.specialDefense(), - inMemoryPokemon.speed(), - inMemoryPokemon.legendary(), - inMemoryPokemon.subLegendary(), - inMemoryPokemon.mythical(), - inMemoryPokemon.canChangeForm(), - inMemoryPokemon.weight(), - inMemoryPokemon.height(), - evolutionResponses, moveResponse, - eggMoveResponse, - biomeResponse - ); - } - - private EvolutionResponses createEvolutionResponse(InMemoryPokemon inMemoryPokemon) { - EvolutionChain chain = evolutionRepository.findEvolutionChainById(inMemoryPokemon.id()) - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.EVOLUTION_NOT_FOUND)); - - int currentStage = IntStream.range(0, chain.getChain().size()) - .filter(i -> chain.getChain().get(i).stream().anyMatch(r -> r.equals(inMemoryPokemon.id()))) - .sum(); - - return new EvolutionResponses( - currentStage, - createStages(chain) + eggMoveResponses, + biomeResponses, + evolutionResponses ); } - private List createStages(EvolutionChain evolutionChain) { - List> chain = evolutionChain.getChain(); - List ret = new ArrayList<>(); + private List createTypeResponse(Pokemon pokemon) { + List types = pokemon.getTypes(); - InMemoryPokemon firstInMemoryPokemon = inMemoryPokemonRepository.findById(chain.get(0).get(0)) - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.POKEMON_NOT_FOUND)); - - ret.add(new EvolutionResponse( - firstInMemoryPokemon.id(), - firstInMemoryPokemon.koName(), - 1, - 0, - "", - "", - s3Service.getPokemonImageFromS3(firstInMemoryPokemon.id()) - )); - - for (int i = 0; i < chain.size() - 1; i++) { - List stage = chain.get(i); - for (String id : stage) { - List evolutions = evolutionRepository.findEdgeById(id) - .orElse(null); - - if (evolutions == null) { - continue; - } - - for (Evolution evolution : evolutions) { - InMemoryPokemon inMemoryPokemon = inMemoryPokemonRepository.findById(evolution.to()) - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.POKEMON_NOT_FOUND)); - ret.add(new EvolutionResponse( - inMemoryPokemon.id(), - inMemoryPokemon.koName(), - Integer.parseInt(evolution.level()), - i + 1, - EvolutionItem.findById(evolution.item()).getKoName(), - evolution.condition(), - s3Service.getPokemonImageFromS3(inMemoryPokemon.id()) - )); - } - } - } - return ret; + return types.stream() + .map(PokemonTypeResponse::from) + .toList(); } - private List createAbilityResponse(InMemoryPokemon inMemoryPokemon) { - List ret = new ArrayList<>(); - - Ability passive = inMemoryAbilityRepository.findById(inMemoryPokemon.abilityPassive()) - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.POKEMON_ABILITY_NOT_FOUND)); - ret.add(new PokemonAbilityResponse( - inMemoryPokemon.abilityPassive(), passive.getName(), passive.getDescription(), - true, false - )); + private List createAbilityResponse(Pokemon pokemon) { + List abilityIds = pokemon.getNormalAbilityIds(); + abilityIds.add(pokemon.getPassiveAbilityId()); + abilityIds.add(pokemon.getHiddenAbilityId()); - Ability ability1 = inMemoryAbilityRepository.findById(inMemoryPokemon.ability1()) - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.POKEMON_ABILITY_NOT_FOUND)); - Ability ability2 = inMemoryAbilityRepository.findById(inMemoryPokemon.ability2()) - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.POKEMON_ABILITY_NOT_FOUND)); - List defaultAbilities = Stream.of(ability1, ability2) - .distinct() - .map(ability -> new PokemonAbilityResponse( - inMemoryPokemon.ability1(), ability.getName(), - ability.getDescription(), false, false) - ) + List> abilities = abilityIds.stream() + .map(abilityRepository::findById) .toList(); - ret.addAll(defaultAbilities); - - if (!inMemoryPokemon.abilityHidden().isEmpty()) { - Ability hidden = inMemoryAbilityRepository.findById(inMemoryPokemon.abilityHidden()) - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.POKEMON_ABILITY_NOT_FOUND)); - ret.add(new PokemonAbilityResponse(inMemoryPokemon.abilityHidden(), hidden.getName(), hidden.getDescription(), - false, - true)); - - for (int i = 1; i < ret.size() - 1; i++) { - if (inMemoryAbilityRepository.findById(ret.get(i).id()) - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.POKEMON_ABILITY_NOT_FOUND)) == hidden - ) { - ret.remove(i); - break; - } - } - } - - return ret; + return PokemonAbilityResponse.createListFrom(abilities); } - private List createTypeResponse(InMemoryPokemon inMemoryPokemon) { - Type firstType = Type.findById(inMemoryPokemon.firstType()); - Type secondType = Type.findById(inMemoryPokemon.secondType()); - return Stream.of(firstType, secondType) - .distinct() - .filter(type -> type != Type.EMPTY) - .map(type -> new PokemonTypeResponse(type.getName(), - s3Service.getPokerogueTypeImageFromS3(type.getId().toLowerCase()))) - .toList(); - } + private List createBiomeResponse(Pokemon pokemon) { + List biomes = pokemon.getBiomeIds(); - private List createBiomeResponse(List biomes) { return biomes.stream() - .map(id -> { - if (id.isEmpty()) { - return new PokemonBiomeResponse("", "", ""); - } - Biome biome = inMemoryBiomeRepository.findById(id).orElseThrow(() -> new GlobalCustomException(ErrorMessage.BIOME_NOT_FOUND)); - return new PokemonBiomeResponse( - id, - biome.getName(), - s3Service.getBiomeImageFromS3(id) - ); - } - ) + .map(biomeRepository::findById) + .filter(Optional::isPresent) + .map(Optional::get) + .map(PokemonBiomeResponse::from) .toList(); } - private List createEggMoveResponse(List moves) { + private List createEggMoveResponse(Pokemon pokemon) { + List moves = pokemon.getEggMoveIds(); + return moves.stream() - .map(r -> battleMoveRepository.findById(r).orElseThrow(() -> new GlobalCustomException(ErrorMessage.MOVE_NOT_FOUND))) - .map(move -> MoveResponse.from(move, 1, - s3Service.getPokerogueTypeImageFromS3(battleMoveRepository.findById(move.id()) - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.MOVE_NOT_FOUND)) - .type().getName()))) + .map(moveRepository::findById) + .filter(Optional::isPresent) + .map(Optional::get) + .map(EggMoveResponse::from) .toList(); } - private List createMoveResponse(List moves) { - return IntStream.iterate(0, index -> index + 2) - .limit(moves.size() / 2) - .mapToObj(index -> MoveResponse.from( - battleMoveRepository.findById(moves.get(index)).orElseThrow(() -> new GlobalCustomException(ErrorMessage.MOVE_NOT_FOUND)), - Integer.parseInt(moves.get(index + 1)), - s3Service.getPokerogueTypeImageFromS3( - battleMoveRepository.findById(moves.get(index)) - .orElseThrow(() -> new GlobalCustomException(ErrorMessage.MOVE_NOT_FOUND)) - .type().getName()) - )) + private List createMoveResponse(Pokemon pokemon) { + List levelMoves = pokemon.getLevelMoves(); + + return levelMoves.stream() + .map(levelMove -> PokemonMoveResponse.from(getMoveById(levelMove), levelMove.getLevel())) .toList(); } + + private Move getMoveById(LevelMove levelMove) { + return moveRepository.findById(levelMove.getMoveId()) + .orElseThrow(() -> new GlobalCustomException(ErrorMessage.MOVE_NOT_FOUND)); + } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/service/TreeDepthCalculator.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/service/TreeDepthCalculator.java new file mode 100644 index 000000000..214a29b97 --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/pokemon/service/TreeDepthCalculator.java @@ -0,0 +1,98 @@ +package com.pokerogue.helper.pokemon.service; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class TreeDepthCalculator { + private final Map> adjacentNodes; + private final Map indegree; + + public TreeDepthCalculator(Map> adjacentNodes) { + this.adjacentNodes = adjacentNodes; + this.indegree = createIndegree(); + } + + private Map createIndegree() { + return adjacentNodes.values().stream() + .flatMap(List::stream) + .collect(Collectors.groupingBy(Function.identity(), Collectors.summingInt(cnt -> 1))); + } + + public Map calculateDepths() { + Map depths = new HashMap<>(); + loadDefaults(depths); + BufferedQueue bufferedQueue = createBufferedQueue(); + + calculateDepthByTopologicalSort(bufferedQueue, depths); + + return depths; + } + + private void loadDefaults(Map depths) { + List allNodes = getAllNodes(); + allNodes.stream() + .peek(node -> indegree.putIfAbsent(node, 0)) + .peek(node -> depths.putIfAbsent(node, 0)) + .forEach(node -> adjacentNodes.putIfAbsent(node, new ArrayList<>())); + } + + private BufferedQueue createBufferedQueue() { + List allNodes = getAllNodes(); + + return new BufferedQueue<>(allNodes.stream() + .filter(this::isIndegreeZero) + .collect(Collectors.toCollection(ArrayDeque::new))); + } + + private List getAllNodes() { + return Stream.concat( + adjacentNodes.keySet().stream(), + adjacentNodes.values().stream().flatMap(List::stream)) + .distinct() + .toList(); + } + + private void calculateDepthByTopologicalSort(BufferedQueue bufferedQueue, Map depths) { + while (bufferedQueue.hasNext()) { + bufferedQueue.buffer(); + flushNodes(bufferedQueue, depths); + } + } + + private void flushNodes(BufferedQueue bufferedQueue, Map depths) { + while (bufferedQueue.hasBufferedNext()) { + String currentNode = bufferedQueue.poll(); + List nextNodes = adjacentNodes.get(currentNode); + + nextNodes.stream() + .peek(nextNode -> updateDepthCount(nextNode, depths, bufferedQueue)) + .peek(this::decreaseIndegreeCount) + .filter(this::isIndegreeZero) + .filter(this::isAdjacentNodeExist) + .forEach(bufferedQueue::add); + } + } + + private void updateDepthCount(String nextNode, Map depths, BufferedQueue bufferedQueue) { + depths.put(nextNode, bufferedQueue.getBufferCount()); + } + + private void decreaseIndegreeCount(String nextNode) { + indegree.merge(nextNode, -1, Integer::sum); + } + + + private boolean isIndegreeZero(String node) { + return indegree.get(node) == 0; + } + + private boolean isAdjacentNodeExist(String node) { + return !adjacentNodes.get(node).isEmpty(); + } +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/data/TypeMatching.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/type/collection/TypeMatching.java similarity index 70% rename from backend/pokerogue/src/main/java/com/pokerogue/helper/battle/data/TypeMatching.java rename to backend/pokerogue/src/main/java/com/pokerogue/helper/type/collection/TypeMatching.java index 03393eebe..7f9b88766 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/data/TypeMatching.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/type/collection/TypeMatching.java @@ -1,7 +1,7 @@ -package com.pokerogue.helper.battle.data; +package com.pokerogue.helper.type.collection; +import com.pokerogue.helper.type.data.Type; import lombok.AccessLevel; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import org.springframework.data.annotation.Id; @@ -9,20 +9,19 @@ import org.springframework.data.mongodb.core.mapping.Field; @Getter -@AllArgsConstructor -@NoArgsConstructor(access = AccessLevel.PROTECTED) @Document(collection = "typeMatching") +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class TypeMatching { @Id private String id; @Field("from") - private String from; // Todo: enum + private Type from; @Field("to") - private String to; // Todo: enum + private Type to; @Field("result") - private double result; + private int result; } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/type/controller/PokemonTypeController.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/type/controller/PokemonTypeController.java index 7a7d61cb4..036c72b3a 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/type/controller/PokemonTypeController.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/type/controller/PokemonTypeController.java @@ -1,5 +1,7 @@ package com.pokerogue.helper.type.controller; +import com.pokerogue.helper.type.dto.PokemonTypeMatchingResponse; +import com.pokerogue.helper.type.dto.PokemonTypeResponse; import com.pokerogue.helper.type.service.PokemonTypeService; import com.pokerogue.helper.util.dto.ApiResponse; import java.util.List; @@ -14,12 +16,12 @@ public class PokemonTypeController { private final PokemonTypeService pokemonTypeService; @GetMapping("/api/v1/types") - public ApiResponse> typeList() { + public ApiResponse> typeList() { return new ApiResponse<>("타입 리스트 불러오기에 성공했습니다.", pokemonTypeService.findTypes()); } @GetMapping("/api/v1/types/matching") - public ApiResponse matchingAndTypeList() { + public ApiResponse matchingAndTypeList() { return new ApiResponse<>("타입 상성 리스트 불러오기에 성공했습니다.", pokemonTypeService.findMatchingAndTypes()); } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/type/converter/TypeReadConverter.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/type/converter/TypeReadConverter.java new file mode 100644 index 000000000..b250a60c1 --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/type/converter/TypeReadConverter.java @@ -0,0 +1,14 @@ +package com.pokerogue.helper.type.converter; + +import com.pokerogue.helper.type.data.Type; +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.convert.ReadingConverter; + +@ReadingConverter +public class TypeReadConverter implements Converter { + + @Override + public Type convert(String typeData) { + return Type.convertFrom(typeData); + } +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/type/data/Type.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/type/data/Type.java index d17dc7bef..8a887c739 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/type/data/Type.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/type/data/Type.java @@ -1,5 +1,7 @@ package com.pokerogue.helper.type.data; +import com.pokerogue.helper.global.exception.ErrorMessage; +import com.pokerogue.helper.global.exception.GlobalCustomException; import java.util.Arrays; import java.util.Optional; import lombok.Getter; @@ -50,4 +52,9 @@ public static Optional findByEngName(String engName) { .filter(type -> type.name.equals(engName)) .findAny(); } + + public static Type convertFrom(String typeData) { + return findByEngName(typeData) + .orElseThrow(() -> new GlobalCustomException(ErrorMessage.TYPE_NOT_FOUND)); + } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/type/dto/PokemonTypeMatchingResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/type/dto/PokemonTypeMatchingResponse.java new file mode 100644 index 000000000..7a99f75b5 --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/type/dto/PokemonTypeMatchingResponse.java @@ -0,0 +1,6 @@ +package com.pokerogue.helper.type.dto; + +import java.util.List; + +public record PokemonTypeMatchingResponse(List matching, List images) { +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/type/dto/PokemonTypeResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/type/dto/PokemonTypeResponse.java index 89b8b99eb..0693a0054 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/type/dto/PokemonTypeResponse.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/type/dto/PokemonTypeResponse.java @@ -1,4 +1,10 @@ package com.pokerogue.helper.type.dto; +import com.pokerogue.helper.type.data.Type; + public record PokemonTypeResponse(String typeName, String typeLogo) { + + public static PokemonTypeResponse from(Type type) { + return new PokemonTypeResponse(type.getKoName(), type.getImage()); + } } diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/type/dto/TypeMatchingResponse.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/type/dto/TypeMatchingResponse.java new file mode 100644 index 000000000..89d56396a --- /dev/null +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/type/dto/TypeMatchingResponse.java @@ -0,0 +1,11 @@ +package com.pokerogue.helper.type.dto; + +import com.pokerogue.helper.type.collection.TypeMatching; + +public record TypeMatchingResponse(String from, String to, int result) { + + public static TypeMatchingResponse from(TypeMatching typeMatching) { + return new TypeMatchingResponse(typeMatching.getFrom().getName(), typeMatching.getTo().getName(), + typeMatching.getResult()); + } +} diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/repository/TypeMatchingRepository.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/type/repository/TypeMatchingRepository.java similarity index 71% rename from backend/pokerogue/src/main/java/com/pokerogue/helper/battle/repository/TypeMatchingRepository.java rename to backend/pokerogue/src/main/java/com/pokerogue/helper/type/repository/TypeMatchingRepository.java index 7e57924d7..ffc86d508 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/battle/repository/TypeMatchingRepository.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/type/repository/TypeMatchingRepository.java @@ -1,6 +1,6 @@ -package com.pokerogue.helper.battle.repository; +package com.pokerogue.helper.type.repository; -import com.pokerogue.helper.battle.data.TypeMatching; +import com.pokerogue.helper.type.collection.TypeMatching; import java.util.Optional; import org.springframework.data.mongodb.repository.MongoRepository; diff --git a/backend/pokerogue/src/main/java/com/pokerogue/helper/type/service/PokemonTypeService.java b/backend/pokerogue/src/main/java/com/pokerogue/helper/type/service/PokemonTypeService.java index 696a6f756..a7e3d1e61 100644 --- a/backend/pokerogue/src/main/java/com/pokerogue/helper/type/service/PokemonTypeService.java +++ b/backend/pokerogue/src/main/java/com/pokerogue/helper/type/service/PokemonTypeService.java @@ -1,16 +1,36 @@ package com.pokerogue.helper.type.service; +import com.pokerogue.helper.type.collection.TypeMatching; +import com.pokerogue.helper.type.data.Type; +import com.pokerogue.helper.type.dto.PokemonTypeMatchingResponse; +import com.pokerogue.helper.type.dto.PokemonTypeResponse; +import com.pokerogue.helper.type.dto.TypeMatchingResponse; +import com.pokerogue.helper.type.repository.TypeMatchingRepository; import java.util.List; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @Service +@RequiredArgsConstructor public class PokemonTypeService { - public List findTypes() { - return List.of(); + + private final TypeMatchingRepository typeMatchingRepository; + + public List findTypes() { + List types = List.of(Type.values()); + + return types.stream() + .map(PokemonTypeResponse::from) + .toList(); } - public String findMatchingAndTypes() { - return null; + public PokemonTypeMatchingResponse findMatchingAndTypes() { + List typeMatchings = typeMatchingRepository.findAll(); + List typeMatchingResponses = typeMatchings.stream() + .map(TypeMatchingResponse::from) + .toList(); + + return new PokemonTypeMatchingResponse(typeMatchingResponses, findTypes()); } } diff --git a/backend/pokerogue/src/test/java/com/pokerogue/environment/repository/MongoRepositoryTest.java b/backend/pokerogue/src/test/java/com/pokerogue/environment/repository/MongoRepositoryTest.java index 67b807be2..4d9648777 100644 --- a/backend/pokerogue/src/test/java/com/pokerogue/environment/repository/MongoRepositoryTest.java +++ b/backend/pokerogue/src/test/java/com/pokerogue/environment/repository/MongoRepositoryTest.java @@ -1,9 +1,12 @@ package com.pokerogue.environment.repository; +import com.pokerogue.helper.global.config.ConverterConfig; import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest; +import org.springframework.context.annotation.Import; import org.springframework.test.context.ActiveProfiles; @DataMongoTest @ActiveProfiles("local") +@Import(ConverterConfig.class) public abstract class MongoRepositoryTest { } diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/ability/service/AbilityServiceTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/ability/service/AbilityServiceTest.java new file mode 100644 index 000000000..6cc13cf87 --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/ability/service/AbilityServiceTest.java @@ -0,0 +1,35 @@ +package com.pokerogue.helper.ability.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import com.pokerogue.environment.service.ServiceTest; +import com.pokerogue.helper.ability.dto.AbilityDetailResponse; +import com.pokerogue.helper.ability.dto.AbilityResponse; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class AbilityServiceTest extends ServiceTest { + + @Autowired + private AbilityService abilityService; + + @Test + void findAbilities() { + List abilityResponses = abilityService.findAbilities(); + + assertThat(abilityResponses).hasSize(310); + } + + @Test + void findAbilityDetails() { + AbilityDetailResponse abilityDetails = abilityService.findAbilityDetails("stench"); + + assertAll( + () -> assertThat(abilityDetails.koName()).isEqualTo("악취"), + () -> assertThat(abilityDetails.description()).isEqualTo("악취를 풍겨서 공격했을 때 상대가 풀죽을 때가 있다."), + () -> assertThat(abilityDetails.pokemons()).hasSize(9) + ); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/battle/MoveCategoryTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/battle/MoveCategoryTest.java new file mode 100644 index 000000000..eaa0807d3 --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/battle/MoveCategoryTest.java @@ -0,0 +1,30 @@ +package com.pokerogue.helper.battle; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.pokerogue.helper.global.exception.ErrorMessage; +import com.pokerogue.helper.global.exception.GlobalCustomException; +import com.pokerogue.helper.move.data.MoveCategory; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class MoveCategoryTest { + + @ParameterizedTest + @ValueSource(strings = {"aaa", "polla", "po"}) + @DisplayName("존재하지 않는 MoveCategory인 경우 에러를 발생한다.") + void convertFrom_WhenNotExist(String inputCategory) { + assertThatThrownBy(() -> MoveCategory.convertFrom(inputCategory)) + .isInstanceOf(GlobalCustomException.class) + .hasMessage(ErrorMessage.MOVE_CATEGORY_NOT_FOUND.getMessage()); + } + + @Test + @DisplayName("일치하는 MoveCategory를 찾는다.") + void convertFrom() { + assertThat(MoveCategory.convertFrom("special")).isEqualTo(MoveCategory.SPECIAL); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/battle/service/TypeMultiplierProviderTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/battle/service/TypeMultiplierProviderTest.java index 10aa4e368..ba2ffe03d 100644 --- a/backend/pokerogue/src/test/java/com/pokerogue/helper/battle/service/TypeMultiplierProviderTest.java +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/battle/service/TypeMultiplierProviderTest.java @@ -24,11 +24,7 @@ class TypeMultiplierProviderTest extends ServiceTest { @DisplayName("타입 상성에 따른 배틀 결과 배수를 구한다.") void getByTypeMatching() { Pokemon rivalPokemon = pokemonRepository.findById("squirtle").get(); - List rivalPokemonTypes = rivalPokemon.getTypes() - .stream() - .map(String::toUpperCase) // Todo - .map(Type::valueOf) - .toList(); + List rivalPokemonTypes = rivalPokemon.getTypes(); Type attackMoveType = Type.FIRE; List multipliers = typeMultiplierProvider.getAllByTypeMatchings(attackMoveType, @@ -45,6 +41,8 @@ void getBySameTypeAttackBonus() { BattleMultiplier multiplier = typeMultiplierProvider.getBySameTypeAttackBonus(attackMoveType, rivalPokemon); + System.out.println("actual: " + multiplier.getDoubleValue()); + System.out.println("expected: " + BattleMultiplier.STRONG_MULTIPLIER.getDoubleValue()); assertThat(multiplier).isEqualTo(BattleMultiplier.STRONG_MULTIPLIER); } @@ -52,11 +50,7 @@ void getBySameTypeAttackBonus() { @DisplayName("강한 바람이 불 때 비행타입 라이벌 포켓몬의 약점을 가려주는 배수를 구한다.") void getByStrongWind() { Pokemon rivalPokemon = pokemonRepository.findById("pidgey").get(); - List rivalPokemonTypes = rivalPokemon.getTypes() - .stream() - .map(String::toUpperCase) // Todo - .map(Type::valueOf) - .toList(); + List rivalPokemonTypes = rivalPokemon.getTypes(); Type attackMoveType = Type.ELECTRIC; BattleMultiplier multiplier = typeMultiplierProvider.getByStrongWind(attackMoveType, rivalPokemonTypes); diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/biome/config/BiomeDatabaseInitializerTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/biome/config/BiomeDatabaseInitializerTest.java deleted file mode 100644 index 8ddad3891..000000000 --- a/backend/pokerogue/src/test/java/com/pokerogue/helper/biome/config/BiomeDatabaseInitializerTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.pokerogue.helper.biome.config; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.pokerogue.environment.service.ServiceTest; -import com.pokerogue.helper.biome.repository.InMemoryBiomeRepository; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.DefaultApplicationArguments; - -class BiomeDatabaseInitializerTest extends ServiceTest { - - @Autowired - private BiomeDatabaseInitializer biomeDatabaseInitializer; - - @Autowired - private InMemoryBiomeRepository inMemoryBiomeRepository; - - @Test - @DisplayName("바이옴 데이터를 세팅한다.") - void setBiomesData() { - biomeDatabaseInitializer.run(new DefaultApplicationArguments()); - - assertThat(inMemoryBiomeRepository.findAll()).hasSize(35); - } -} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/biome/converter/TierConverterTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/biome/converter/TierConverterTest.java new file mode 100644 index 000000000..8563c23d4 --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/biome/converter/TierConverterTest.java @@ -0,0 +1,18 @@ +package com.pokerogue.helper.biome.converter; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.pokerogue.helper.biome.data.Tier; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class TierConverterTest { + + @Test + @DisplayName("들어온 값을 Tier Enum으로 변화한다.") + void convert() { + TierConverter tierConverter = new TierConverter(); + + assertThat(tierConverter.convert("보스")).isEqualTo(Tier.BOSS); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/biome/data/TierTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/biome/data/TierTest.java new file mode 100644 index 000000000..402624c57 --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/biome/data/TierTest.java @@ -0,0 +1,29 @@ +package com.pokerogue.helper.biome.data; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.pokerogue.helper.global.exception.ErrorMessage; +import com.pokerogue.helper.global.exception.GlobalCustomException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class TierTest { + + @ParameterizedTest + @ValueSource(strings = {"aaa", "polla", "polaaaa"}) + @DisplayName("존재하지 않는 티어인 경우 에러를 발생한다.") + void convertFrom_WhenNotExist(String inputTier) { + assertThatThrownBy(() -> Tier.convertFrom(inputTier)) + .isInstanceOf(GlobalCustomException.class) + .hasMessage(ErrorMessage.TIER_NOT_FOUND.getMessage()); + } + + @Test + @DisplayName("일치하는 티어를 찾는다.") + void convertFrom() { + assertThat(Tier.convertFrom("보스")).isEqualTo(Tier.BOSS); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/biome/repository/BiomeRepositoryTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/biome/repository/BiomeRepositoryTest.java new file mode 100644 index 000000000..04cc3ef4a --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/biome/repository/BiomeRepositoryTest.java @@ -0,0 +1,49 @@ +package com.pokerogue.helper.biome.repository; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import com.pokerogue.environment.repository.MongoRepositoryTest; +import com.pokerogue.helper.biome.data.Biome; +import com.pokerogue.helper.biome.data.NativePokemon; +import com.pokerogue.helper.biome.data.Tier; +import com.pokerogue.helper.biome.data.Trainer; +import com.pokerogue.helper.type.data.Type; +import java.util.Collection; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class BiomeRepositoryTest extends MongoRepositoryTest { + + @Autowired + private BiomeRepository biomeRepository; + + @Test + @DisplayName("모든 바이옴 정보가 정상적으로 매핑되는지 확인한다.") + void findAll_AndConvertToBiome() { + List biomes = biomeRepository.findAll(); + + assertAll( + () -> assertThat(biomes).hasSize(35), + () -> assertThat(biomes.stream() + .flatMap(biome -> biome.getTypes().stream())) + .allMatch(type -> type.getDeclaringClass() + .equals(Type.class)), + () -> assertThat(biomes.stream() + .flatMap(biome -> biome.getNativePokemons().stream() + .map(NativePokemon::getTier)) + .allMatch(tier -> tier.getDeclaringClass() + .equals(Tier.class))) + .isTrue(), + () -> assertThat(biomes.stream() + .flatMap(biome -> biome.getTrainers().stream() + .map(Trainer::getTypes)) + .flatMap(Collection::stream) + .allMatch(type -> type.getDeclaringClass() + .equals(Type.class))) + .isTrue() + ); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/biome/service/BiomeServiceTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/biome/service/BiomeServiceTest.java new file mode 100644 index 000000000..bed2ec008 --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/biome/service/BiomeServiceTest.java @@ -0,0 +1,52 @@ +package com.pokerogue.helper.biome.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; + +import com.pokerogue.environment.service.ServiceTest; +import com.pokerogue.helper.biome.dto.BiomeDetailResponse; +import com.pokerogue.helper.biome.dto.BiomeResponse; +import com.pokerogue.helper.global.exception.ErrorMessage; +import com.pokerogue.helper.global.exception.GlobalCustomException; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class BiomeServiceTest extends ServiceTest { + + @Autowired + private BiomeService biomeService; + + @Test + @DisplayName("전체 바이옴 리스트를 불러온다") + void findBoimes() { + List biomes = biomeService.findBiomes(); + + assertThat(biomes.size()).isEqualTo(35); + } + + @Test + @DisplayName("단일 바이옴 정보를 불러온다") + void findBiome() { + BiomeDetailResponse biomeDetailResponse = biomeService.findBiome("fairy_cave"); + + assertAll( + () -> assertThat(biomeDetailResponse.id()).isEqualTo("fairy_cave"), + () -> assertThat(biomeDetailResponse.name()).isEqualTo("페어리 동굴"), + () -> assertThat(biomeDetailResponse.wildPokemons()).hasSize(5), + () -> assertThat(biomeDetailResponse.bossPokemons()).hasSize(4), + () -> assertThat(biomeDetailResponse.trainerPokemons()).hasSize(3), + () -> assertThat(biomeDetailResponse.nextBiomes()).hasSize(2) + ); + } + + @Test + @DisplayName("해당 id의 바이옴이 없는 경우 예외를 발생시킨다") + void notExistBiome() { + assertThatThrownBy(() -> biomeService.findBiome("test")) + .isInstanceOf(GlobalCustomException.class) + .hasMessage(ErrorMessage.BIOME_NOT_FOUND.getMessage()); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/data/PokemonDataTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/data/PokemonDataTest.java new file mode 100644 index 000000000..e8a79bb85 --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/data/PokemonDataTest.java @@ -0,0 +1,189 @@ +package com.pokerogue.helper.data; + +import static com.pokerogue.helper.data.PokemonValidator.validatePokemonIdFormat; +import static com.pokerogue.helper.data.PokemonValidator.validatePokemonSize; + +import com.pokerogue.environment.repository.MongoRepositoryTest; +import com.pokerogue.helper.pokemon.data.Pokemon; +import com.pokerogue.helper.pokemon.repository.PokemonRepository; +import java.util.List; +import org.assertj.core.api.Assertions; +import org.assertj.core.api.ThrowableAssert.ThrowingCallable; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class PokemonDataTest extends MongoRepositoryTest { + + @Autowired + private PokemonRepository pokemonRepository; + + @DisplayName("포켓몬 데이터의 개수를 확인한다.") + @Test + void pokemonCount() { + int actual = pokemonRepository.findAll().size(); + + ThrowingCallable validator = () -> validatePokemonSize(actual); + + Assertions.assertThatCode(validator).doesNotThrowAnyException(); + } + + @Disabled("파싱코드의 replace를 한 문자가 아닌 스트링의 전체를 replace하도록 바꿔야 함. 잘못된 id가 있어 disalbed") + @DisplayName("포켓몬 데이터의 아이디 형식을 확인한다.") + @Test + void pokemonIdFormat() { + List actual = pokemonRepository.findAll().stream().map(Pokemon::getId).toList(); + + ThrowingCallable validator = () -> validatePokemonIdFormat(actual); + + Assertions.assertThatCode(validator).doesNotThrowAnyException(); + } + + @Disabled(""" + 디버깅 결과 + ID / actualTotal / expectedTotal + charizard_gigantamax / 634 / 644, + kingler_gigantamax / 575 / 585 + + 두 건의 데이터에 대해 종족값이 일치하지 않는다. + 추가적인 논의가 필요하여 disalbed""") + @DisplayName("포켓몬 데이터의 종족값은 기본 능력치의 합이다.") + @Test + void pokemonTotalStats() { + List actual = pokemonRepository.findAll(); + + ThrowingCallable callable = () -> PokemonValidator.validatePokemonsBaseTotal(actual); + + Assertions.assertThatCode(callable).doesNotThrowAnyException(); + } + + @DisplayName("포켓몬 데이터의 세대가 유효한지 확인한다.") + @Test + void pokemonGeneration() { + List actual = pokemonRepository.findAll(); + + ThrowingCallable validator = () -> PokemonValidator.validatePokemonsGeneration(actual); + + Assertions.assertThatCode(validator).doesNotThrowAnyException(); + } + + @Disabled("폼변환이 가능하지만 정보가 주어지지 않는 데이터가 존재하여 disalbed.") + @DisplayName("포켓몬 폼변환이 가능하면 폼변환 정보가 주어진다.") + @Test + void pokemonGeneration2() { + List actual = pokemonRepository.findAll(); + + ThrowingCallable validator = () -> PokemonValidator.validatePokemonFormChanges(actual); + + Assertions.assertThatCode(validator).doesNotThrowAnyException(); + } + + + @DisplayName("legendary, subLegendary, mythical 셋 중 하나만 true거나 모두 false여야한다.") + @Test + void pokemonGeneration3() { + List actual = pokemonRepository.findAll(); + + ThrowingCallable validator = () -> PokemonValidator.validatePokemonRarity(actual); + + Assertions.assertThatCode(validator).doesNotThrowAnyException(); + } + + @DisplayName("normal ability id는 항상 1개 또는 2개이다.") + @Test + void pokemonGeneration4() { + List actual = pokemonRepository.findAll(); + + ThrowingCallable validator = () -> PokemonValidator.validateNormalAbilityCount(actual); + + Assertions.assertThatCode(validator).doesNotThrowAnyException(); + } + + @Disabled(""" + 기본 특성이 히든 특성과 같은 데이터가 있어서 disable + +) 이상해꽃 기간타맥스가 되면 기본 특성이 달라진다 + +) pokerouge dex와 데이터가 다른걸 보니 추가 확인이 필요""") + @DisplayName("abilitiy id는 서로 중복될 수 없다.") + @Test + void pokemonGeneration5() { + List actual = pokemonRepository.findAll(); + + ThrowingCallable validator = () -> PokemonValidator.validateTotalAbilityDuplication(actual); + + Assertions.assertThatCode(validator).doesNotThrowAnyException(); + } + + @DisplayName("능력치가 정해진 범위의 수인지 확인한다.") + @Test + void pokemonGeneration6() { + List actual = pokemonRepository.findAll(); + + ThrowingCallable validator = () -> PokemonValidator.validateStatValueRange(actual); + + Assertions.assertThatCode(validator).doesNotThrowAnyException(); + } + + @DisplayName("패시브 특성은 항상 존재한다.") + @Test + void pokemonGeneration7() { + List actual = pokemonRepository.findAll(); + + ThrowingCallable validator = () -> PokemonValidator.validatePassiveAbilityExist(actual); + + Assertions.assertThatCode(validator).doesNotThrowAnyException(); + } + + @DisplayName("히든 특성은 존재할 수도 안할 수도 있다.") + @Test + void pokemonGeneration8() { + List actual = pokemonRepository.findAll(); + + ThrowingCallable validator = () -> PokemonValidator.validateEmptyHiddenAbilityExists(actual); + + Assertions.assertThatCode(validator).doesNotThrowAnyException(); + } + + @DisplayName("특성의 총 개수는 2개에서 4개 사이다.") + @Test + void pokemonGeneration9() { + List actual = pokemonRepository.findAll(); + + ThrowingCallable validator = () -> PokemonValidator.validateTotalAbilityCount(actual); + + Assertions.assertThatCode(validator).doesNotThrowAnyException(); + } + + + @DisplayName("타입의 개수는 1개 혹은 2개다.") + @Test + void pokemonGeneration10() { + List actual = pokemonRepository.findAll(); + + ThrowingCallable validator = () -> PokemonValidator.validateTypeCount(actual); + + Assertions.assertThatCode(validator).doesNotThrowAnyException(); + } + + @DisplayName("중복된 타입은 존재하지 않는다.") + @Test + void pokemonGeneration11() { + List actual = pokemonRepository.findAll(); + + ThrowingCallable validator = () -> PokemonValidator.validateTypeDuplication(actual); + + Assertions.assertThatCode(validator).doesNotThrowAnyException(); + } + + + @Disabled("데이터상 진화아이디와 포켓몬아이디가 불일치하여 disabled") + @DisplayName("진화 아이디는 모두 포켓몬 아이디에 포함된다.") + @Test + void pokemonGeneration12() { + List actual = pokemonRepository.findAll(); + + ThrowingCallable validator = () -> PokemonValidator.validateEvolutionFromToIsPokemonId(actual); + + Assertions.assertThatCode(validator).doesNotThrowAnyException(); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/data/PokemonValidatorTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/data/PokemonValidatorTest.java new file mode 100644 index 000000000..a529fecab --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/data/PokemonValidatorTest.java @@ -0,0 +1,41 @@ +package com.pokerogue.helper.data; + +import com.pokerogue.helper.global.exception.ErrorMessage; +import com.pokerogue.helper.global.exception.GlobalCustomException; +import com.pokerogue.helper.pokemon.data.Pokemon; +import com.pokerogue.helper.type.data.Type; +import java.util.List; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +public class PokemonValidatorTest { + + @DisplayName("예상하는 포켓몬 개수와 일치하지 않으면 예외가 발생한다") + @ParameterizedTest + @ValueSource(ints = {-1, 0, 1, 1445, 1447, 20241006}) + void pokemonSize(int pokemonSize) { + Assertions.assertThatThrownBy(() -> PokemonValidator.validatePokemonSize(pokemonSize)) + .isInstanceOf(GlobalCustomException.class) + .hasMessageContaining(ErrorMessage.POKEMON_SIZE_MISMATCH.getMessage()); + } + + @DisplayName("포켓몬 타입의 개수가 1개 혹은 2개가 아니라면 예외가 발생한다") + @Test + void pokemonTypeSize() { + Pokemon pokemon = new Pokemon(); + Pokemon pokemon2 = new Pokemon(); + + pokemon.setTypes(List.of()); + pokemon2.setTypes(List.of(Type.FIRE, Type.ICE, Type.BUG)); + + List pokemons = List.of(pokemon, pokemon2); + + Assertions.assertThatThrownBy(() -> PokemonValidator.validateTypeCount(pokemons)) + .isInstanceOf(GlobalCustomException.class) + .hasMessageContaining(ErrorMessage.POKEMON_TYPE_COUNT_OUT_OF_RANGE.getMessage()); + } + +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/data/PokeomonControllerTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/data/PokeomonControllerTest.java new file mode 100644 index 000000000..b74c03beb --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/data/PokeomonControllerTest.java @@ -0,0 +1,54 @@ +package com.pokerogue.helper.data; + +import static io.restassured.RestAssured.given; + +import com.pokerogue.environment.repository.MongoRepositoryTest; +import com.pokerogue.helper.pokemon.data.Pokemon; +import com.pokerogue.helper.pokemon.repository.PokemonRepository; +import io.restassured.RestAssured; +import io.restassured.http.ContentType; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + + +@Disabled("디버깅용 API 테스트") +public class PokeomonControllerTest extends MongoRepositoryTest { + + @Autowired + PokemonRepository pokemonRepository; + + @BeforeAll + public static void setup() { + RestAssured.baseURI = "http://localhost:8080/api/v1"; + } + + @Test + public void testApiError() { + given() + .contentType(ContentType.JSON) + .when() + .get("/pokemons2") + .then() + .statusCode(200); + } + + @Test + public void testApiError2() { + + List all = pokemonRepository.findAll(); + + for (Pokemon pokemon : all) { + System.out.println(pokemon); + given() + .contentType(ContentType.JSON) + .when() + .get("/pokemon2/" + pokemon.getId()) + .then() + .statusCode(200); + } + + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/move/converter/FlagConverterTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/move/converter/FlagConverterTest.java new file mode 100644 index 000000000..dc5188d3f --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/move/converter/FlagConverterTest.java @@ -0,0 +1,18 @@ +package com.pokerogue.helper.move.converter; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.pokerogue.helper.move.data.MoveFlag; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class FlagConverterTest { + + @Test + @DisplayName("들어온 값을 Flag Enum으로 변화한다.") + void convert() { + FlagConverter flagConverter = new FlagConverter(); + + assertThat(flagConverter.convert("dance_move")).isEqualTo(MoveFlag.DANCE_MOVE); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/move/converter/MoveCategoryConverterTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/move/converter/MoveCategoryConverterTest.java new file mode 100644 index 000000000..36ae52c5c --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/move/converter/MoveCategoryConverterTest.java @@ -0,0 +1,18 @@ +package com.pokerogue.helper.move.converter; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.pokerogue.helper.move.data.MoveCategory; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class MoveCategoryConverterTest { + + @Test + @DisplayName("들어온 값을 MoveCategory Enum으로 변화한다.") + void convert() { + MoveCategoryConverter moveCategoryConverter = new MoveCategoryConverter(); + + assertThat(moveCategoryConverter.convert("special")).isEqualTo(MoveCategory.SPECIAL); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/move/converter/MoveTargetConverterTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/move/converter/MoveTargetConverterTest.java new file mode 100644 index 000000000..3398f0992 --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/move/converter/MoveTargetConverterTest.java @@ -0,0 +1,18 @@ +package com.pokerogue.helper.move.converter; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.pokerogue.helper.move.data.MoveTarget; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class MoveTargetConverterTest { + + @Test + @DisplayName("들어온 값을 Move Target Enum 으로 변화한다.") + void convert() { + MoveTargetConverter moveTargetConverter = new MoveTargetConverter(); + + assertThat(moveTargetConverter.convert("user")).isEqualTo(MoveTarget.USER); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/move/data/MoveFlagTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/move/data/MoveFlagTest.java new file mode 100644 index 000000000..302f435fc --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/move/data/MoveFlagTest.java @@ -0,0 +1,28 @@ +package com.pokerogue.helper.move.data; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.pokerogue.helper.global.exception.ErrorMessage; +import com.pokerogue.helper.global.exception.GlobalCustomException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class MoveFlagTest { + + @ParameterizedTest + @ValueSource(strings = {"aaa", "polla", "pp"}) + void convertFrom_WhenNotExist(String inputMoveFlag) { + assertThatThrownBy(() -> MoveFlag.convertFrom(inputMoveFlag)) + .isInstanceOf(GlobalCustomException.class) + .hasMessage(ErrorMessage.MOVE_FLAG_NOT_FOUND.getMessage()); + } + + @Test + @DisplayName("일치하는 Move Flag를 찾아온다.") + void convertFrom() { + assertThat(MoveFlag.convertFrom("dance_move")).isEqualTo(MoveFlag.DANCE_MOVE); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/move/data/MoveTargetTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/move/data/MoveTargetTest.java new file mode 100644 index 000000000..d49f9414b --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/move/data/MoveTargetTest.java @@ -0,0 +1,28 @@ +package com.pokerogue.helper.move.data; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.pokerogue.helper.global.exception.ErrorMessage; +import com.pokerogue.helper.global.exception.GlobalCustomException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class MoveTargetTest { + + @ParameterizedTest + @ValueSource(strings = {"aaa", "polla", "ald"}) + void convertFrom_WhenNotExist(String inputMoveTarget) { + assertThatThrownBy(() -> MoveTarget.convertFrom(inputMoveTarget)) + .isInstanceOf(GlobalCustomException.class) + .hasMessage(ErrorMessage.MOVE_TARGET_NOT_FOUND.getMessage()); + } + + @Test + @DisplayName("일치하는 MoveTarget을 찾아온다.") + void convertFrom() { + assertThat(MoveTarget.convertFrom("all")).isEqualTo(MoveTarget.ALL); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/move/repository/MoveRepositoryTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/move/repository/MoveRepositoryTest.java new file mode 100644 index 000000000..74eeb1251 --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/move/repository/MoveRepositoryTest.java @@ -0,0 +1,51 @@ +package com.pokerogue.helper.move.repository; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import com.pokerogue.environment.repository.MongoRepositoryTest; +import com.pokerogue.helper.move.data.Move; +import com.pokerogue.helper.move.data.MoveCategory; +import com.pokerogue.helper.move.data.MoveFlag; +import com.pokerogue.helper.move.data.MoveTarget; +import com.pokerogue.helper.type.data.Type; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class MoveRepositoryTest extends MongoRepositoryTest { + + @Autowired + private MoveRepository moveRepository; + + @Test + @DisplayName("모든 기술 정보가 정상적으로 매핑되는지 확인한다.") + void findAll_AndConvertToMove() { + List moves = moveRepository.findAll(); + + assertAll( + () -> assertThat(moves).hasSize(920), + () -> assertThat(moves.stream() + .allMatch(move -> move.getType() + .getDeclaringClass() + .equals(Type.class))) + .isTrue(), + () -> assertThat(moves.stream() + .allMatch(move -> move.getMoveTarget() + .getDeclaringClass() + .equals(MoveTarget.class))) + .isTrue(), + () -> assertThat(moves.stream() + .allMatch(move -> move.getMoveCategory() + .getDeclaringClass() + .equals(MoveCategory.class))) + .isTrue(), + () -> assertThat(moves.stream() + .flatMap(move -> move.getFlags().stream()) + .allMatch(flag -> flag.getDeclaringClass() + .equals(MoveFlag.class))) + .isTrue() + ); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/move/service/MoveServiceTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/move/service/MoveServiceTest.java new file mode 100644 index 000000000..aeffda2f4 --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/move/service/MoveServiceTest.java @@ -0,0 +1,54 @@ +package com.pokerogue.helper.move.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; + +import com.pokerogue.environment.service.ServiceTest; +import com.pokerogue.helper.global.exception.ErrorMessage; +import com.pokerogue.helper.global.exception.GlobalCustomException; +import com.pokerogue.helper.move.dto.MoveResponse; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class MoveServiceTest extends ServiceTest { + + @Autowired + private MoveService moveService; + + @Test + @DisplayName("해당 포켓몬의 전체 기술 목록을 반환한다") + void findMovesByPokemon() { + List movesByPokemon = moveService.findMovesByPokemon(1); + + assertThat(movesByPokemon.size()).isEqualTo(72); + } + + @Test + @DisplayName("단일 기술 정보를 불러온다") + void findMove() { + MoveResponse moveResponse = moveService.findMove("earth_power"); + + assertAll( + () -> assertThat(moveResponse.id()).isEqualTo("earth_power"), + () -> assertThat(moveResponse.name()).isEqualTo("대지의힘"), + () -> assertThat(moveResponse.typeEngName()).isEqualTo("ground"), + () -> assertThat(moveResponse.typeLogo()).contains("type/ground"), + () -> assertThat(moveResponse.categoryEngName()).isEqualTo("special"), + () -> assertThat(moveResponse.categoryLogo()).contains("move-category/special.png"), + () -> assertThat(moveResponse.power()).isEqualTo(90), + () -> assertThat(moveResponse.accuracy()).isEqualTo(100), + () -> assertThat(moveResponse.effect()).isEqualTo("상대의 발밑에 대지의 힘을 방출한다. 상대의 특수방어를 떨어뜨릴 때가 있다.") + ); + } + + @Test + @DisplayName("id에 해당하는 기술이 없는 경우 예외를 발생시킨다") + void notExistMove() { + assertThatThrownBy(() -> moveService.findMove("test")) + .isInstanceOf(GlobalCustomException.class) + .hasMessage(ErrorMessage.MOVE_NOT_FOUND.getMessage()); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/converter/EvolutionItemConverterTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/converter/EvolutionItemConverterTest.java new file mode 100644 index 000000000..ff5ba2b55 --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/converter/EvolutionItemConverterTest.java @@ -0,0 +1,18 @@ +package com.pokerogue.helper.pokemon.converter; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.pokerogue.helper.pokemon.data.EvolutionItem; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class EvolutionItemConverterTest { + + @Test + @DisplayName("들어온 겂을 EvolutionItem Enum으로 변화한다.") + void convert() { + EvolutionItemConverter evolutionItemConverter = new EvolutionItemConverter(); + + assertThat(evolutionItemConverter.convert("dusk_stone")).isEqualTo(EvolutionItem.DUSK_STONE); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/data/EvolutionItemTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/data/EvolutionItemTest.java new file mode 100644 index 000000000..8347b7826 --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/data/EvolutionItemTest.java @@ -0,0 +1,30 @@ +package com.pokerogue.helper.pokemon.data; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.pokerogue.helper.global.exception.ErrorMessage; +import com.pokerogue.helper.global.exception.GlobalCustomException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class EvolutionItemTest { + + @ParameterizedTest + @ValueSource(strings = {"aaa", "poa", "polla"}) + @DisplayName("존재하지 않는 아이템인 경우 빈 것을 의미하는 값을 반환한다.") + void convertFrom_WhenNotExit(String inputEvolutionItem) { + assertThatThrownBy(()->EvolutionItem.convertFrom(inputEvolutionItem)) + .isInstanceOf(GlobalCustomException.class) + .hasMessage(ErrorMessage.ITEM_NOT_FOUND.getMessage()); + } + + @Test + @DisplayName("일치하는 아이템을 찾아온다.") + void convertFrom() { + assertThat(EvolutionItem.convertFrom("dawn_stone")) + .isEqualTo(EvolutionItem.DAWN_STONE); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/data/InMemoryPokemonDatabaseInitializerTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/data/InMemoryPokemonDatabaseInitializerTest.java deleted file mode 100644 index d634db1ce..000000000 --- a/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/data/InMemoryPokemonDatabaseInitializerTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.pokerogue.helper.pokemon.data; - -import com.pokerogue.helper.ability.repository.InMemoryAbilityRepository; -import com.pokerogue.helper.pokemon.config.PokemonDatabaseInitializer; -import com.pokerogue.helper.pokemon.repository.EvolutionRepository; -import com.pokerogue.helper.pokemon.repository.InMemoryPokemonRepository; -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import org.springframework.boot.DefaultApplicationArguments; - -class InMemoryPokemonDatabaseInitializerTest { - - @Test - @DisplayName("포켓몬 정보가 지정된 개수만큼 저장된다") - void savePokemonCount() { - InMemoryPokemonRepository inMemoryPokemonRepository = new InMemoryPokemonRepository(); - PokemonDatabaseInitializer pokemonDatabaseInitializer = new PokemonDatabaseInitializer( - inMemoryPokemonRepository, - new EvolutionRepository(), - new InMemoryAbilityRepository() - ); - - pokemonDatabaseInitializer.run(new DefaultApplicationArguments()); - - Assertions.assertThat(inMemoryPokemonRepository.findAll()).hasSize(1268); - } - - @ParameterizedTest - @ValueSource(strings = {"bulbasaur", "chikorita", "wailmer", "virizion", "golisopod", "melmetal", "spidops", - "hydrapple", "alola_exeggutor"}) - @DisplayName("포켓몬의 저장된 이름을 확인한다") - void savePokemonNames(String name) { - InMemoryPokemonRepository inMemoryPokemonRepository = new InMemoryPokemonRepository(); - PokemonDatabaseInitializer pokemonDatabaseInitializer = new PokemonDatabaseInitializer( - inMemoryPokemonRepository, - new EvolutionRepository(), - new InMemoryAbilityRepository() - ); - - pokemonDatabaseInitializer.run(new DefaultApplicationArguments()); - - Assertions.assertThat(inMemoryPokemonRepository.findById(name)).isNotNull(); - } -} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/data/PokemonTestFixture.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/data/PokemonTestFixture.java index 91d39297d..32ff0ec71 100644 --- a/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/data/PokemonTestFixture.java +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/data/PokemonTestFixture.java @@ -1,12 +1,13 @@ package com.pokerogue.helper.pokemon.data; +import com.pokerogue.helper.type.data.Type; import java.util.Arrays; import java.util.List; public class PokemonTestFixture { public static List BULBASAUR_EVOLUTIONS = Arrays.asList( - new Evolution("bulbasaur", "16", "ivysaur", null, null), - new Evolution("ivysaur", "32", "venusaur", null, null) + new Evolution("bulbasaur", 16, "ivysaur", null, null), + new Evolution("ivysaur", 32, "venusaur", null, null) ); public static List BULBASAUR_LEVEL_MOVES = Arrays.asList( @@ -38,7 +39,7 @@ public class PokemonTestFixture { "", // formName 64, // baseExp 50, // friendship - Arrays.asList("grass", "poison"), // types + Arrays.asList(Type.GRASS, Type.POISON), // types Arrays.asList("overgrow"), // normalAbilityIds "chlorophyll", // hiddenAbilityId "grassy_surge", // passiveAbilityId @@ -73,8 +74,8 @@ public class PokemonTestFixture { ); public static List CHARMANDER_EVOLUTIONS = List.of( - new Evolution("charmander", "16", "charmeleon", null, null), - new Evolution("charmeleon", "36", "charizard", null, null) + new Evolution("charmander", 16, "charmeleon", null, null), + new Evolution("charmeleon", 36, "charizard", null, null) ); public static List CHARMANDER_LEVEL_MOVES = List.of( @@ -103,7 +104,7 @@ public class PokemonTestFixture { "", // formName 62, // baseExp 50, // friendship - List.of("fire"), // types + List.of(Type.FIRE), // types List.of("blaze"), // normalAbilityIds "solar_power", // hiddenAbilityId "beast_boost", // passiveAbilityId diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/service/BufferedQueueTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/service/BufferedQueueTest.java new file mode 100644 index 000000000..98a9dfc0e --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/service/BufferedQueueTest.java @@ -0,0 +1,58 @@ +package com.pokerogue.helper.pokemon.service; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class BufferedQueueTest { + + @DisplayName("버퍼에 삽입 전에는 버퍼 카운팅이 작동하지 않는다.") + @Test + void bufferCounting() { + BufferedQueue bufferedQueue = new BufferedQueue<>(new LinkedList<>()); + bufferedQueue.add(1); + bufferedQueue.add(2); + bufferedQueue.add(3); + + Assertions.assertThat(bufferedQueue.hasBufferedNext()).isFalse(); + Assertions.assertThat(bufferedQueue.getBufferCount()).isZero(); + } + + @DisplayName("버퍼에 삽입 후 버퍼 카운팅이 증가한다.") + @Test + void bufferCounting2() { + BufferedQueue bufferedQueue = new BufferedQueue<>(new LinkedList<>()); + bufferedQueue.add(1); + bufferedQueue.add(2); + bufferedQueue.add(3); + + bufferedQueue.buffer(); + + Assertions.assertThat(bufferedQueue.hasBufferedNext()).isTrue(); + Assertions.assertThat(bufferedQueue.getBufferCount()).isOne(); + } + + @DisplayName("버퍼 호출시 그 전에 저장된 값만 꺼낼 수 있다.") + @Test + void beforeBufferValues() { + BufferedQueue bufferedQueue = new BufferedQueue<>(new LinkedList<>()); + List bufferedValues = new ArrayList<>(); + bufferedQueue.add(1); + bufferedQueue.add(10000); + bufferedQueue.buffer(); + bufferedQueue.add(3); + bufferedQueue.add(4); + bufferedQueue.add(5); + + while (bufferedQueue.hasBufferedNext()) { + Integer poll = bufferedQueue.poll(); + bufferedValues.add(poll); + } + + Assertions.assertThat(bufferedValues).hasSameElementsAs(List.of(1, 10000)); + Assertions.assertThat(bufferedQueue.getSize()).isEqualTo(3); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/service/EvolutionContextTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/service/EvolutionContextTest.java new file mode 100644 index 000000000..d856a5ec6 --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/service/EvolutionContextTest.java @@ -0,0 +1,59 @@ +package com.pokerogue.helper.pokemon.service; + +import static org.junit.jupiter.api.Assertions.assertAll; + +import com.pokerogue.helper.global.exception.ErrorMessage; +import com.pokerogue.helper.global.exception.GlobalCustomException; +import com.pokerogue.helper.pokemon.data.Evolution; +import java.util.List; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class EvolutionContextTest { + + @DisplayName("각 포켓몬 진화 깊이 정보를 가져올 수 있다.") + @Test + void getDepthOf() { + Evolution evolution = createEvolution("A", "B"); + Evolution evolution2 = createEvolution("B", "C"); + Evolution evolution3 = createEvolution("C", "D"); + Evolution evolution4 = createEvolution("D", "E"); + + EvolutionContext context = new EvolutionContext(List.of(evolution, evolution2, evolution3, evolution4)); + + assertAll(() -> { + Assertions.assertThat(context.getDepthOf("A")).isEqualTo(0); + Assertions.assertThat(context.getDepthOf("B")).isEqualTo(1); + Assertions.assertThat(context.getDepthOf("C")).isEqualTo(2); + Assertions.assertThat(context.getDepthOf("D")).isEqualTo(3); + Assertions.assertThat(context.getDepthOf("E")).isEqualTo(4); + }); + } + + @DisplayName("포켓몬의 진화 정보를 가져올 수 있다.") + @Test + void getEvolutionOf() { + Evolution actual = createEvolution("A", "B"); + + EvolutionContext context = new EvolutionContext(List.of(actual)); + Evolution expected = context.getEvolutionOf("A"); + + Assertions.assertThat(expected).isEqualTo(actual); + } + + @DisplayName("잘못된 포켓몬 아이디라면 예외가 발생한다.") + @Test + void getEvolutionOfException() { + Evolution actual = createEvolution("A", "B"); + EvolutionContext context = new EvolutionContext(List.of(actual)); + + Assertions.assertThatThrownBy(() -> context.getEvolutionOf("C")) + .isInstanceOf(GlobalCustomException.class) + .hasMessage(ErrorMessage.POKEMON_NOT_FOUND.getMessage()); + } + + private static Evolution createEvolution(String from, String to) { + return new Evolution(from, 1, to, "", ""); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/service/TreeDepthCalculatorTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/service/TreeDepthCalculatorTest.java new file mode 100644 index 000000000..4a8f9acc4 --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/pokemon/service/TreeDepthCalculatorTest.java @@ -0,0 +1,33 @@ +package com.pokerogue.helper.pokemon.service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class TreeDepthCalculatorTest { + + @DisplayName("인접한 간선의 정보가 주어지면 각 노드의 깊이를 구할 수 있다") + @Test + void calculateDepths() { + Map> adjacentNodes = new HashMap<>(Map.of( + "A", List.of("B", "C", "D", "E"), + "B", List.of("C", "D", "E"), + "C", List.of("D", "E"), + "D", List.of("E") + )); + Map expected = new HashMap<>(Map.of( + "A", 0, + "B", 1, + "C", 2, + "D", 3, + "E", 4 + )); + + Map actual = new TreeDepthCalculator(adjacentNodes).calculateDepths(); + + Assertions.assertThat(actual).isEqualTo(expected); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/type/converter/TypeReadConverterTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/type/converter/TypeReadConverterTest.java new file mode 100644 index 000000000..721a1db71 --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/type/converter/TypeReadConverterTest.java @@ -0,0 +1,18 @@ +package com.pokerogue.helper.type.converter; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.pokerogue.helper.type.data.Type; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class TypeReadConverterTest { + + @Test + @DisplayName("들어온 값을 Type enum으로 변화한다.") + void convert() { + TypeReadConverter typeReadConverter = new TypeReadConverter(); + + assertThat(typeReadConverter.convert("fire")).isEqualTo(Type.FIRE); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/type/data/TypeTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/type/data/TypeTest.java new file mode 100644 index 000000000..6e69ed498 --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/type/data/TypeTest.java @@ -0,0 +1,29 @@ +package com.pokerogue.helper.type.data; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.pokerogue.helper.global.exception.ErrorMessage; +import com.pokerogue.helper.global.exception.GlobalCustomException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class TypeTest { + + @ParameterizedTest + @ValueSource(strings = {"aaa", "polla", "jdj"}) + @DisplayName("존재하지 않는 타입인 경우 에러를 발생한다.") + void convertFrom_WhenNotExist(String inputType) { + assertThatThrownBy(() -> Type.convertFrom(inputType)) + .isInstanceOf(GlobalCustomException.class) + .hasMessage(ErrorMessage.TYPE_NOT_FOUND.getMessage()); + } + + @Test + @DisplayName("일치하는 타입을 찾아온다.") + void convertFrom() { + assertThat(Type.convertFrom("dragon")).isEqualTo(Type.DRAGON); + } +} diff --git a/backend/pokerogue/src/test/java/com/pokerogue/helper/type/repository/TypeMatchingRepositoryTest.java b/backend/pokerogue/src/test/java/com/pokerogue/helper/type/repository/TypeMatchingRepositoryTest.java new file mode 100644 index 000000000..6a4967a29 --- /dev/null +++ b/backend/pokerogue/src/test/java/com/pokerogue/helper/type/repository/TypeMatchingRepositoryTest.java @@ -0,0 +1,38 @@ +package com.pokerogue.helper.type.repository; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import com.pokerogue.environment.repository.MongoRepositoryTest; +import com.pokerogue.helper.type.collection.TypeMatching; +import com.pokerogue.helper.type.data.Type; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class TypeMatchingRepositoryTest extends MongoRepositoryTest { + + @Autowired + private TypeMatchingRepository typeMatchingRepository; + + @Test + @DisplayName("모든 상성 정보가 정상적으로 Entity와 매핑되는지 확인한다.") + void findAll_AndConvertToTypeMatching() { + List typeMatchings = typeMatchingRepository.findAll(); + + assertAll( + () -> assertThat(typeMatchings).hasSize(361), + () -> assertThat(typeMatchings.stream() + .allMatch(typeMatching -> typeMatching.getTo() + .getDeclaringClass() + .equals(Type.class))) + .isTrue(), + () -> assertThat(typeMatchings.stream() + .allMatch(typeMatching -> typeMatching.getFrom() + .getDeclaringClass() + .equals(Type.class))) + .isTrue() + ); + } +}