가상 투표 시뮬레이션 프로그램을 만들며 사용했던 Java의 기능들과 주어진 문제 해결을 위해 고민했던 부분을 정리해보았습니다.
사용자에게 진행할 총 투표수 (1 ~ 10000), 후보자 인원 (2 ~ 10), 후보자 이름(10자 미만 한글)을 입력 받고 가상 투표를 진행하는 프로그램을 만드는 문제입니다.(입력 조건에는 예외 없음) 후보 기호는 후보자 입력 순으로 정해지고, 각 투표는 Random 함수의 nextInt()
를 통해 생성한 랜덤 번호를 활용합니다. 매 투표마다 해당 투표의 결과와 후보별 득표 상황을 아래 예시와 같이 출력해야 합니다. 단, 최종 당선자 동률은 허용하지 않습니다.
총 진행할 투표 수와 후보자 이름을 Scanner로 받고, 후보자 이름은 HashMap을 사용해 기호 번호와 이름을 맵핑합니다.
static int totalCandidates = 0;
static int totalVotes = 0;
static HashMap<Integer, String> mapForNames = new HashMap<>(totalCandidates);
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("총 진행할 투표수를 입력해 주세요.");
totalVotes = sc.nextInt();
System.out.print("가상 선거를 진행할 후보자 인원을 입력해 주세요.");
totalCandidates = sc.nextInt();
sc.nextLine();
for (int i = 0; i < totalCandidates; i++) {
System.out.print((i + 1) + "번째 후보자이름을 입력해 주세요.");
String name = sc.nextLine();
mapForNames.put(i, name);
}
simulation();
}
투표를 진행할 메소드를 만들기 위해 아래와 같은 내용을 고려해서 코드를 작성했습니다.
📌 투표에 사용할 랜덤 번호 생성
📌 후보별 득표수를 담을 ArrayList 생성
📌 마지막 투표를 위한 랜덤 번호 생성시 동률 확인 (ArrayList에서 가장 큰 득표수와 동일한 값이 1개를 초과하면 랜덤 번호 재생성)
📌 매 투표마다 출력할 진행 상황을 포맷에 맞게 작성
📌 마지막 투표 시 동률이 아닌 경우, 당선인을 최종적으로 출력하고 프로그램 종료
public static void simulation() {
Random random = new Random();
ArrayList<Integer> list = new ArrayList<>(totalCandidates); // 득표수 담을 ArrayList
for (int a = 0; a < totalCandidates; a++) {
list.add(a, 0); // 기본 득표수 0으로 설정
}
for (int i = 0; i <= totalVotes - 1; i++) { // 투표 진행
int randomVote = random.nextInt(totalCandidates); // 투표할 기호 번호 랜덤 선정
list.set(randomVote, list.get(randomVote) + 1); // 선정된 기호의 득표수 추가
int max = Collections.max(list); // 동률 확인
int tieNum = Collections.frequency(list, max);
if (i == totalVotes - 1) {
if (tieNum > 1) {
i--;
continue;
}
}
// 투표마다 진행 상황 출력
String progress = String.format("%.2f%%", ((double) (i + 1) / totalVotes) * 100);
System.out.print("\n[투표진행률]: " + progress + ", ");
System.out.println((i + 1) + "명 투표 => " + mapForNames.get(randomVote));
for (int j = 0; j < totalCandidates; j++) {
String rate = String.format("%.2f%%", ((double) list.get(j) / totalVotes) * 100);
System.out.print("[기호:" + (j + 1) + "] ");
System.out.print(String.format("%-10s", mapForNames.get(j) + ":").replace(" ", " "));
System.out.println(rate + "\t(투표수: " + list.get(j) +")");
}
if (i == totalVotes - 1) {
System.out.println("\n[투표결과] 당선인 : " + mapForNames.get(list.indexOf(max)));
}
}
}
ArrayList가 List 인터페이스를 구현하고, List 인터페이스는 Collections 인터페이스를 상속하기 때문에, ArrayList를 사용해 Collections 클래스가 제공하는 메소드를 활용할 수 있었습니다.
✅ 컬렉션 프레임워크: Java에서 데이터를 그룹화하고 조작하는 클래스와 인터페이스 모음을 뜻합니다.
✅ 컬렉션 인터페이스: List, Set, Map 등이 해당됩니다.
✅ 컬렉션 클래스: ArrayList, HashSet, HashMap 등이 해당됩니다.
✅ Collections 클래스 (java.util.Collections): 유틸리티 클래스
로, 컬렉션 클래스들을 다룰 수 있는 정적 (static) 메소드를 제공합니다. 정렬, 검색, 최대값, 최소값 등을 위한 기능을 제공하는 메소드가 포함하며, 인스턴스 생성없이 직접 호출이 가능합니다.
이번 문제를 풀며 유용하게 사용한 코드들 입니다.
Random 함수의 nextInt(범위)
: 랜덤 번호를 생성해서 매 투표마다 기호 번호로 사용HashMap
: (Key: 후보 기호, Value: 후보 이름)을 쌍으로 저장map.get(key)
: key에 맵핑된 value 불러오기ArrayList
: 각 후보가 얻은 득표수 저장할 때 사용Collections.max(컬렉션 이름)
: 주어진 리스트에서 가장 큰 값을 반환 (최대 득표수를 찾을 때 활용)Collections.frequency(컬렉션 이름, 값)
: 주어진 리스트에서 특정 값과 동일한 값이 출현하는 횟수를 반환 (현재 최대 값인 득표수가 중복 출현하는지 확인할 때 활용)list.indexOf(값)
: 해당 값을 갖고 있는 인덱스 번호 반환 => 최대 득표자의 후보 기호를 불러올 때 사용String.format
: 출력 포맷을 지정"%-10s"
: 10개 문자(s)로 구성된 문자열을 만들고 문자가 없는 경우 오른쪽(-)부터 반각 공백을 채움 (왼쪽 정렬 효과)replace("a", "b")
: 문자열에서 "a"를 "b"로 바꾸기 => 반각 공백을 전각 공백으로 변경할 때 사용 가능특히 이번 문제는 득표수, 득표율, 투표 진행률 같은 결과를 얻기 위한 계산이 필요했는데 이때 명시적 형변환을 어느 위치에 사용하냐에 따라 결과의 정확도가 달라질 수 있다는 점을 다시 상기할 수 있었습니다.
(double) 명시적 형변환
: 소수점까지 반영하는 정확한 값기 위해서는 계산될 항목 중 하나를 미리 (double)로 캐스팅
해야 자동 형변환이 되어 소수점을 반영한 계산이 진행된다. 계산이 완료된 값에 double로 캐스팅을 하면, 소수점이 무시된 상태에서 계산한 후 (0하고 1만 나옴) 그 값을 형변환만 시키는 형태가 된다.참고
https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html (Collections method)
https://zz1-hyunn.tistory.com/89 (ArrayList 기능)
https://hianna.tistory.com/572 (ArrayList로 중복 값 세기)
https://dev-coco.tistory.com/15 (Array vs ArrayList 차이)
https://kadosholy.tistory.com/120 (HashMap 사용법)
https://adjh54.tistory.com/134#google_vignette (String.format() 문자열 채우기)