Java에서 부울 배열 채우기
상당히 친환경적인 자바 코더로서 저는 간단한 텍스트 어드벤처를 작성하는 데 많은 어려움을 겪었습니다. 당연히 벌써 어려움을 겪었습니다!
내 Location 클래스에 포함 된 종료를 저장할 속성을 제공하려고합니다. 이를 위해 부울 배열을 사용하여 본질적으로 각 출구를 나타내는 참 / 거짓 값을 유지했습니다. 나는 완전히 확신하지 않는다
a) 이 작업을 수행하는 가장 효율적인 방법이며
b) 배열을 채우기 위해 올바른 코드를 사용하고 있습니다.
완전한 코드 점검을위한 것이더라도 모든 피드백에 감사드립니다!
현재 위치를 인스턴스화 할 때 setExits 메서드로 보내는 문자열을 생성합니다.
String e = "N S U";
secretRoom.setExits(e);
Location 클래스에서 setExits는 다음과 같습니다.
public void setExits(String e) {
if (e.contains("N"))
bexits[0] = true;
else if (e.contains("W"))
bexits[1] = true;
else if (e.contains("S"))
bexits[2] = true;
else if (e.contains("E"))
bexits[3] = true;
else if (e.contains("U"))
bexits[4] = true;
else if (e.contains("D"))
bexits[5] = true;
}
솔직히 말해서이게 특히 투박해 보이지만 다른 방법은 생각할 수 없었습니다. 또한 getExits 메서드를 작성하는 방법을 완전히 확신하지 못합니다.
어떤 도움이라도 환영합니다!
당신이이 일을 왜 어떤 이유가 String
s와 전달되지 않은 booleans
즉,
public void setExits(boolean N, boolean E, boolean S, boolean W, boolean U, boolean D)
아니면 세터가 있습니까?
public void setNorthOpen(boolean open)
{
bexits[4] = open;
}
둘째, 왜 출구를 부울 배열로 저장하고 있습니까? 작은 유한 세트입니다.
boolean N,S,E,W,U,D;
그러면 각 방향이 배열의 어떤 숫자인지 추적 할 필요가 없습니다.
또한
이것은 정답입니다 (@gexicide와 같이 완전히 최적화되지는 않았지만) Java에서 다른 방식으로 일을 수행하는 방법에 대한 흥미로운보기를 위해 여기에서 다른 답변을 살펴볼 것을 전적으로 권장합니다.
향후 참조를 위해
작동하는 코드는 Stack Overflow가 아닌 Code Review에 속합니다 . @kajacx가 지적했듯이이 코드는 실제로 작동하지 않아야합니다.
가장 효율적 이고 표현적인 방법은 다음과 같습니다.
사용 enum
의 종료로와은을 사용하여 EnumSet
저장할 수 있습니다. 열거 형 상수를 나타 내기 위해 비트 필드를 사용 EnumSet
하는 효율적인 Set
구현입니다.
방법은 다음과 같습니다.
public enum Exit { North, West, South, East, Up, Down; }
EnumSet<Exit> set = EnumSet.noneOf(Exit.class); // An empty set.
// Now you can simply add or remove exits, everything will be stored compactly
set.add(Exit.North); // Add exit
set.contains(Exit.West); // Test if an exit is present
set.remove(Exit.South); //Remove an exit
Enum 세트는 모든 이탈을 long
내부적 으로 단일에 저장 하므로 코드가 표현력 있고 빠르며 많은 메모리를 절약합니다.
좋아, 우선, 당신의 setExits()
메소드는 의도 한대로 작동하지 않을 것이고, 연결된 if-elseif는 코드의 한 가지를 최대로 실행할 것입니다. 예를 들면 :
if (e.contains("N"))
bexits[0] = true;
else if (e.contains("W"))
bexits[1] = true;
경우에도 e
모두 포함 N
하고 W
만 bexits[0]
설정됩니다. 또한이 메소드는 이탈 만 추가합니다 (예 : 호출 setExits("")
은 기존 이탈을 삭제하지 않습니다.
이 방법을 다음과 같이 변경합니다.
bexits[0] = e.contains("N");
bexits[1] = e.contains("W");
...
또한 북쪽은 인덱스 0에 있고 서쪽은 1에 있다는 것을 확실히 기억하지 못할 것입니다. 따라서 일반적인 관행은 최종 정적 상수를 사용하여 인덱스 이름을 지정하는 것입니다.
public static final int NORTH = 0;
public static final int WEST = 1;
...
그런 다음 setExits
방법을 작성할 수 있습니다 .
bexits[NORTH] = e.contains("N");
bexits[WEST] = e.contains("W");
...
(훨씬 더 읽기 쉬움)
마지막으로, 코드를 더 잘 정리하려면 Exits
사용 가능한 이탈을 나타내는 클래스를 만들고 부울 배열로 뒷받침 할 수 있습니다 . 그런 다음 String을 생성하는 위치에서 대신이 클래스를 생성하고 문자열 생성 및 구문 분석 작업을 절약 할 수 있습니다.
편집하다:
@gexicide가 대답 EnumSet
했듯이 볼린 배열보다 출구를 나타내는 데 더 좋은 정말 편리한 클래스 가 있습니다.
EnumSet
다른 대답이 작업을 수행하는 가장 좋은 방법입니다, 난 그냥 당신이 당신이 이동할 수 있지만, 위치를 이동 여부에 있지 찾고 시작할 때 미래에 불구하고 한 가지 더 추가하고 싶었다.
뿐만 아니라 EnumSet
당신은 또한이 EnumMap
.
Room 클래스 / 인터페이스를 정의하면 Room 클래스 내부에
Map<Direction, Room> exits = new EnumMap<>(Direction.class);
이제 다음과 같이지도에 링크를 추가 할 수 있습니다.
exits.put(Direction.NORTH, theRoomNorthOfMe);
그러면 방 사이를 이동하는 코드가 매우 일반적인 목적이 될 수 있습니다.
Room destination=currentRoom.getExit(directionMoved);
if (destination == null) {
// Cannot move that way
} else {
// Handle move to destination
}
나는 Exit 열거 형을 만들고 위치 클래스에서 Exit 객체 목록을 설정합니다.
그래서 다음과 같을 것입니다.
public enum Exit { N, S, E, W, U, D }
List<Exit> exits = parseExits(String exitString);
location.setExits(exits);
코드가 어떻게 생겼는지 감안할 때 이것이 제가 생각해 낼 수있는 가장 읽기 쉬운 구현입니다.
public class Exits {
private static final char[] DIRECTIONS = "NSEWUD".toCharArray();
public static void main(String... args) {
String input = "N S E";
boolean[] exits = new boolean[DIRECTIONS.length];
for(int i = 0; i< exits.length; i++) {
if (input.indexOf(DIRECTIONS[i]) >= 0) {
exits[i] = true;
}
}
}
}
즉, 가능한 많은 깨끗한 솔루션이 있습니다. 개인적으로 나는 enums와 EnumSet
.
그건 그렇고, 배열에서 대부분의 값을 true로 설정하므로 원래 코드가 올바르지 않습니다.
이탈을 문자열로 정의하는 경우이를 사용해야합니다. 다음과 같이 할 것입니다.
public class LocationWithExits {
public static final String NORTH_EXIT="[N]";
public static final String SOUTH_EXIT="[S]";
public static final String EAST_EXIT="[E]";
public static final String WEST_EXIT="[W]";
private final String exitLocations;
public LocationWithExits(String exitLocations) {
this.exitLocations = exitLocations;
}
public boolean hasNorthExit(){
return exitLocations.contains(NORTH_EXIT);
}
public static void main(String[] args) {
LocationWithExits testLocation=new LocationWithExits(NORTH_EXIT+SOUTH_EXIT);
System.out.println("Has exit on north?: "+testLocation.hasNorthExit());
}
}
부울 배열을 사용하면 bexits [0]이 정확히 무엇을 의미하는지 잊어 버리면 많은 문제가 발생할 수 있습니다. 북쪽이나 남쪽을 위해? 기타
또는 열거 형과 사용 가능한 종료 목록을 사용할 수 있습니다. 그런 다음 목록에 특정 열거 형 값이 포함되어 있으면 methid 테스트에서
개인적으로 enum을 사용하여 약간 해킹하고 다음을 바꿀 수 있다고 생각합니다.
public void setExits(String e) {
if (e.contains("N"))
bexits[0] = true;
else if (e.contains("W"))
bexits[1] = true;
else if (e.contains("S"))
bexits[2] = true;
else if (e.contains("E"))
bexits[3] = true;
else if (e.contains("U"))
bexits[4] = true;
else if (e.contains("D"))
bexits[5] = true;
}
으로
public enum Directions
{
NORTH("N"),
WEST("W"),
SOUTH("S"),
EAST("E"),
UP("U"),
DOWN("D");
private String identifier;
private Directions(String identifier)
{
this.identifier = identifier;
}
public String getIdentifier()
{
return identifier;
}
}
그리고 다음을 수행하십시오.
public void setExits(String e)
{
String[] exits = e.split(" ");
for(String exit : exits)
{
for(Directions direction : Directions.values())
{
if(direction.getIdentifier().equals(exit))
{
bexits[direction.ordinal()] = true;
break;
}
}
}
}
적어 놓은 후에는 그것이 훨씬 더 좋은지 말할 수는 없습니다. 새로운 방향을 추가하는 것이 더 쉽습니다.
답변에 나열된 모든 접근 방식이 좋습니다. 하지만 당신이 취해야 할 접근 방식은 출구 필드를 사용할 방법에 달려 있다고 생각합니다. 예를 들어 exit를 문자열로 처리하려는 경우 Ross Drews 접근 방식에는 많은 if-else 조건 및 변수가 필요합니다.
String exit = "N E";
String[] exits = exit.split(" ");
boolean N = false, E = false, S = false, W = false, U = false, D = false;
for(String e : exits){
if(e.equalsIgnoreCase("N")){
N = true;
} else if(e.equalsIgnoreCase("E")){
E = true;
} else if(e.equalsIgnoreCase("W")){
W= true;
} else if(e.equalsIgnoreCase("U")){
U = true;
} else if(e.equalsIgnoreCase("D")){
D = true;
} else if(e.equalsIgnoreCase("S")){
S = true;
}
}
setExits(N, E, S, W, U, D);
또한 출구가 있고 위치에 특정 출구가 있는지 확인하려면 다시 똑같이해야합니다.
public boolean hasExit(String exit){
if(e.equalsIgnoreCase("N")){
return this.N; // Or the corresponding getter method
} else if(e.equalsIgnoreCase("E")){
return this.E;
} else if(e.equalsIgnoreCase("W")){
return this.W;
} else if(e.equalsIgnoreCase("U")){
return this.U;
} else if(e.equalsIgnoreCase("D")){
return this.D;
} else if(e.equalsIgnoreCase("S")){
return this.S;
}
}
따라서 문자열로 조작하려는 경우 내 생각에 가장 좋은 방법은 목록과 열거 형을 사용하는 것입니다. 이렇게하면 hasExit, hasAnyExit, hasAllExits, hasNorthExit, hasSouthExit, getAvailableExits 등과 같은 메소드를 매우 쉽게 수행 할 수 있습니다. 그리고 목록 (또는 집합)을 사용하여 이탈 수 (6)를 고려하면 오버 헤드가 발생하지 않습니다. 예를 들면
열거 형
public enum EXIT {
EAST("E"),
WEST("W"),
NORTH("N"),
SOUTH("S"),
UP("U"),
DOWN("D");
private String exitCode;
private EXIT(String exitCode) {
this.exitCode = exitCode;
}
public String getExitCode() {
return exitCode;
}
public static EXIT fromValue(String exitCode) {
for (EXIT exit : values()) {
if (exit.exitCode.equalsIgnoreCase(exitCode)) {
return exit;
}
}
return null;
}
public static EXIT fromValue(char exitCode) {
for (EXIT exit : values()) {
if (exit.exitCode.equalsIgnoreCase(String.valueOf(exitCode))) {
return exit;
}
}
return null;
}
}
Location.java
import java.util.ArrayList;
import java.util.List;
public class Location {
private List<EXIT> exits;
public Location(){
exits = new ArrayList<EXIT>();
}
public void setExits(String exits) {
for(char exitCode : exits.toCharArray()){
EXIT exit = EXIT.fromValue(exitCode);
if(exit != null){
this.exits.add(exit);
}
}
}
public boolean hasExit(String exitCode){
return exits.contains(EXIT.fromValue(exitCode));
}
public boolean hasAnyExit(String exits){
for(char exitCode : exits.toCharArray()){
if(this.exits.contains(EXIT.fromValue(exitCode))){
return true;
}
}
return false;
}
public boolean hasAllExit(String exits){
for(char exitCode : exits.toCharArray()){
EXIT exit = EXIT.fromValue(exitCode);
if(exit != null && !this.exits.contains(exit)){
return false;
}
}
return true;
}
public boolean hasExit(char exitCode){
return exits.contains(EXIT.fromValue(exitCode));
}
public boolean hasNorthExit(){
return exits.contains(EXIT.NORTH);
}
public boolean hasSouthExit(){
return exits.contains(EXIT.SOUTH);
}
public List<EXIT> getExits() {
return exits;
}
public static void main(String args[]) {
String exits = "N E W";
Location location = new Location();
location.setExits(exits);
System.out.println(location.getExits());
System.out.println(location.hasExit('W'));
System.out.println(location.hasAllExit("N W"));
System.out.println(location.hasAnyExit("U D"));
System.out.println(location.hasNorthExit());
}
}
더 짧은 코드를 원하면 왜 안될까요?
String symbols = "NWSEUD";
public void setExits(String e) {
for (int i = 0; i < 6; i++) {
bexits[i] = e.contains(symbols.charAt(i));
}
}
If you want a generic solution you can use a map, which maps from a key (in your case W, S, E.. ) to a corresponding value (in your case a boolean).
When you do a set
, you update the value the key is associated with. When you do a get
, you can take an argument key and simply retrieve the value of the key. This functionality does already exist in map, called put and get.
I really like the idea of assigning the exits from a String, because it makes for brief and readable code. Once that's done, I don't see why you would want to create a boolean array. If you have a String, just use it, although you might want to add some validation to prevent accidental assignment of strings containing unwanted characters:
private String exits;
public void setExits(String e) {
if (!e.matches("[NSEWUD ]*")) throw new IllegalArgumentException();
exits = e;
}
The only other thing I would add is a method canExit
that you can call with a direction parameter; e.g., if (location.canExit('N')) ...
:
public boolean canExit(char direction) {
return exits.indexOf(direction) >= 0;
}
I like enums, but using them here seems like over-engineering to me, which will rapidly become annoying.
**Edit**: Actually, don't do this. It answers the wrong question, and it does something which doesn't need to be done. I just noticed @TimB's answer of using a map (an EnumMap) to associate directions with rooms. It makes sense.
I still feel that if you only need to track exit existence, a String is simple and effective, and anything else is over-complicating it. However, only knowing which exits are available isn't useful. You will want to go through those exits, and unless your game has a very plain layout it won't be doable for the code to infer the correct room for each direction, so you'll need to explicitly associate each direction with another room. So there seems to be no actual use for any method "setExits" which accepts a list of directions (regardless of how it's implemented internally).
public void setExits(String e)
{
String directions="NwSEUD";
for(int i=0;i<directions.length();i++)
{
if(e.contains(""+directions.charAt(i)))
{
bexits[i]=true;
break;
}
}
}
the iterative way of doing the same thing..
Long chains of else if
statements should be replaced with switch
statements.
Enum
s are the most expressive way to store such values as long as the efficiency is not a concern. Keep in mind that enum
is a class, so creation of a new enum is associated with corresponding overhead.
참고URL : https://stackoverflow.com/questions/24651403/populating-a-boolean-array-in-java
'Program Tip' 카테고리의 다른 글
내 스크립트에서 사용할 사용자 지정 형식을 PowerShell에서 만들려면 어떻게해야합니까? (0) | 2020.10.25 |
---|---|
WPF DataGrid에서 ComboBoxColumn의 ItemsSource 바인딩 (0) | 2020.10.25 |
Hudson과 CruiseControl for Java 프로젝트의 차이점은 무엇입니까? (0) | 2020.10.25 |
C #을 사용한 연도의 날짜 차이 (0) | 2020.10.25 |
Eclipse LogCat 뷰어에서 태그 이름을 필터링하는 방법 (0) | 2020.10.25 |