알고리즘 모음(C++)

2019 충북 컴퓨터 꿈나무 축제 기출문제 - 중등부(지역대회, 아두이노) 본문

아두이노 대회(충북)

2019 충북 컴퓨터 꿈나무 축제 기출문제 - 중등부(지역대회, 아두이노)

공대생의 잡다한 사전 2022. 7. 21. 18:34

2019 충북 컴퓨터 꿈나무 축제 중등부 지역대회 기출문제 답안입니다.

필수 요소와 창의적 요소를 모두 구현습니다.

사용한 센서는 간단했으며 문제 난이도 자체는 어렵지 않았습니다.

millis()와 토글 스위치를 사용하실수 있으면 필수 요소는 구현하실 수 있을겁니다.

 

문제를 읽지 않으셨다면 먼저 아래의 파일을 통해 문제를 읽어주세요

SW(중)2019(지역).hwp
0.06MB

 

제가 구현한 회로도입니다.

 

첫번째로 스위치를 누르는데 걸리는 시간을 구하는 코드입니다.

millis()함수를 사용했습니다.

void return_time() { // 스위치를 누르는데 걸리는 시간을 구한다
  long long current = millis();
  if (current - previous >= 10) {
    previous = current;
    time_++;
  }
}

current 변수를 통해 millis 값을 받아, 이전 시간 값인 previous와의 비교를 통해 초를 구하는 방법입니다.

0.01초 단위이기에 차이를 10으로 했습니다.

 

 

두번째는 토글 스위치 코드입니다.

이번 문제에서 기본이 되는 코드입니다.

void Sw_1() {  // 토글 스위치 사용
  buttonstate_1 = digitalRead(2);
  if (buttonstate_1 != lastbutton_1) {
    if (buttonstate_1 == HIGH) {
      cnt_1++;
    }
  }
  lastbutton_1 = buttonstate_1;
}

현재 버튼의 상태(눌림, 안눌림)과 이전 버튼의 상태를 비교해서 누른 것을 한번만 인식하는 코드입니다.

 

 

세번째는 정렬 코드입니다. 선택 정렬로 구현했습니다.

void Sort() { // 오름차순 정렬
  for (int i = 0; i < Size; i++) {
    for (int j = i + 1; j < Size; j++) {
      if (Answer[i] > Answer[j]) {  //현재 나보다 뒤에 있는 수가 나보다 작을 때 값을 바꿔준다.
        int tmp = Answer[i];
        Answer[i] = Answer[j];
        Answer[j] = tmp;
      }
    }
  }
}

자신보다 뒤에 있는 수가 자신의 값보다 작을 때, 두 수를 바꾸는 방식입니다.

2중 for문을 통해 구현했습니다.

 

 

남은 코드는 무작위 수를 정해 LED를 키고, 스위치를 눌렀을 때 누른 스위치가 맞는지를 판별하는 코드입니다.

함수에 매개 변수가 많습니다. 따라서 각각의 매개 변수가 어떤 역할을 하는지 이해를 하시고 보는 것이 좋습니다.

배열도 사용이 되었는데, 주석을 통해 각 배열이 어떠한 역할을 하는지 알아두셔야 합니다.

 

 

자세한 것은 코드를 참고해주세요

/////////////////////////////////////토글 스위치 변수
int buttonstate_1 = 0;
int lastbutton_1 = 0;
int cnt_1 = 0;
int buttonstate_2 = 0;
int lastbutton_2 = 0;
int cnt_2 = 0;
/////////////////////////////////////
int Led[2] = {12, 13}; 
int Round = 1;           // 1~10 라운드
int point = 0;           // 총 점수
int combo = 0;           // 몇번 이어서 맞았는가?
int Answer[100] = {0,};  // 맞은 스위치를 누른 시간을 기록
int Check[100] = {0,};   // 문제를 맞았는지 기록 1->O , 2->X
int sw_time[100] = {0,}; // 스위치 누른 시간 기록
int Size = 0;            // Answer 배열과 함께 사용, 맞은게 몇개인가?
long long previous = 0;  // millis를 사용하기 위해 이전 시간을 기록
int time_ = 0;           // 1ms 단위로 증가
/////////////////////////////////////

void setup() {
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  randomSeed(analogRead(0));  // 완전한 random을 만들기 위함
  Serial.begin(9600);
}

void Sw_1() {  // 토글 스위치 사용
  buttonstate_1 = digitalRead(2);
  if (buttonstate_1 != lastbutton_1) {
    if (buttonstate_1 == HIGH) {
      cnt_1++;
    }
  }
  lastbutton_1 = buttonstate_1;
}

void Sw_2() {  // 토글 스위치 사용
  buttonstate_2 = digitalRead(3);
  if (buttonstate_2 != lastbutton_2) {
    if (buttonstate_2 == HIGH) {
      cnt_2++;
    }
  }
  lastbutton_2 = buttonstate_2;
}

void right_sound(){ // 올바른 선택을 위한 소리
  noTone(8);
  tone(8, 440, 200);
  delay(200);
}

void reverse_sound(){ // 반대로 선택하기 위한 소리
  noTone(8);
  tone(8, 600, 500);
  delay(200);
}

void return_time() { // 스위치를 누르는데 걸리는 시간을 구한다
  long long current = millis();
  if (current - previous >= 10) {
    previous = current;
    time_++;
  }
}

void get_point(int x, int y) { // 콤보 점수를 포함해 맞았을 경우 얻는 점수
  if (x < 20) point += (10 + (y-1) * 5);
  else if (x < 40) point += (8 + (y-1) * 5);
  else if (x < 60) point += (6 + (y-1) * 5);
  else if (x < 80) point += (4 + (y-1) * 5);
  else if (x < 100) point += (2 + (y-1) * 5);
  else point += (1 + (y-1) * 5);
}

void check_answer(int sw1, int sw2, int x, int reverse) { // 정답이 맞는지를 구하는 코드. 어떤 스위치가 눌렸으며 반대로 눌러야 하는지 조건문으로 확인
  if (sw1 > 0) { // 1번 스위치가 눌렸을 때
    if (x == 1 && reverse == 0) { // 바르게 눌러야하며 1번 led가 커졌을 경우
      if(Check[Round-1] == 1) combo++;
      else combo = 1;
      get_point(time_, combo);
      Answer[Size] = time_;
      Check[Round] = 1;
      sw_time[Round] = time_;
      digitalWrite(11, HIGH);
      Size++;
    }
    else if(x == 2 && reverse == 1){ // 다르게 눌러야하며 2번 led가 커졌을 경우
      if(Check[Round-1] == 1) combo++;
      else combo = 1;
      get_point(time_, combo);
      Answer[Size] = time_;
      Check[Round] = 1;
      sw_time[Round] = time_;
      digitalWrite(11, HIGH);
      Size++;
    }
    else{ // 그외 경우는 모두 틀린 경우이다.
      Check[Round] = 2;
      combo = 0;
      sw_time[Round] = time_;
      digitalWrite(11, LOW);  
    }
  }
  else if (sw2 > 0) { // 2번 스위치가 눌렸을 때
    if (x == 2 && reverse == 0) { // 바르게 눌러야하며 2번 led가 커졌을 경우
      if(Check[Round-1] == 1) combo++;
      else combo = 1;
      get_point(time_, combo);
      Answer[Size] = time_;
      Check[Round] = 1;
      sw_time[Round] = time_;
      Size++;
      digitalWrite(11, HIGH);
    }
    else if(x == 1 && reverse == 1){ // 반대로 눌러야 하며 1번 led가 커졌을 경우
      if(Check[Round-1] == 1) combo++;
      else combo = 1;
      get_point(time_, combo);
      Answer[Size] = time_;
      Check[Round] = 1;
      sw_time[Round] = time_;
      Size++;
      digitalWrite(11, HIGH);
    }
    else{ // 그 외 경우는 전부 틀린 경우이다.
      Check[Round] = 2;
      combo = 0;
      sw_time[Round] = time_;
      digitalWrite(11, LOW);  
    }
  }
}

void led_on(int x, int reverse) { // 1번 혹은 2번 led를 킨다.
  for (int i = 0; i < 2; i++) { // 랜덤하게 선택된 led를 킨다.
    if (i + 1 == x) digitalWrite(Led[i], HIGH);
    else digitalWrite(Led[i], LOW);
  }
  while (1) {
    Sw_1();
    Sw_2();
    return_time();
    if (cnt_1 > 0 || cnt_2 > 0) { // 어떤 스위치든 눌렀을 경우
      check_answer(cnt_1, cnt_2, x, reverse); // 스위치가 맞게 눌렸는지를 확인한다.
      break; // 스위치를 눌렀으니 다음 문제로 넘어가기 위해 반복문 탈출
    }
  }
}

void Sort() { // 오름차순 정렬
  for (int i = 0; i < Size; i++) {
    for (int j = i + 1; j < Size; j++) {
      if (Answer[i] > Answer[j]) {  //현재 나보다 뒤에 있는 수가 나보다 작을 때 값을 바꿔준다.
        int tmp = Answer[i];
        Answer[i] = Answer[j];
        Answer[j] = tmp;
      }
    }
  }
}

void reset_Answer() {
  for (int i = 0; i < 100; i++) {
    Answer[i] = 0;
    Check[i] = 0;
  }
}

void loop() {
  if (Round <= 10 && Round >= 1) {
    Serial.print("Round : ");
    Serial.println(Round);
    int Random = random(1, 3); // 1번과 2번 led중에서 무작위로 하나 킨다.
    int reverse = random(0,2); // 정방향, 반대로 할지 구한다.
    if(reverse == 0) right_sound(); // 만약 올바르게 눌러야한다면
    else reverse_sound();
    led_on(Random, reverse); // 해당하는 값을 킨다.
    Serial.println("////////////////////////////////////");
    delay(1000);
    Round++; // 다음 라운드
    cnt_1 = 0; // 다음 라운드를 위해 눌렀던 스위치와 시간을 모두 초기화
    cnt_2 = 0;
    time_ = 0;
    digitalWrite(11, LOW);
  }
  if (Round == 11) { // 라운드가 끝났다면
    digitalWrite(12, LOW);
    digitalWrite(13, LOW);
    Sort();
    for(int i = 1; i <= 10; i++){
      Serial.print("Round");
      Serial.print(i);
      Serial.print(" : ");
      if(Check[i] == 1) Serial.print("O       ");
      else Serial.print("X       ");
      Serial.print(sw_time[i]);
      Serial.println("ms");
    }
    Serial.print("Point : ");
    Serial.println(point);
    Serial.print("1st : ");
    Serial.print(Answer[0]);
    Serial.println("ms");
    Serial.print("2nd : ");
    Serial.print(Answer[1]);
    Serial.println("ms");
    Serial.print("3rd : ");
    Serial.print(Answer[2]);
    Serial.println("ms");
    reset_Answer();
    Size = 0;
    point = 0;
    Round = -1;
  }
}