copy pasting the rules from last year’s thread:

Rules: no spoilers.

The other rules are made up aswe go along.

Share code by link to a forge, home page, pastebin (Eric Wastl has one here) or code section in a comment.

  • 2-1: I have quickly run out of hecks to give. This is the sort of problem that gives prolog programmers feelings of smug superiority.

    spoiler
    #include 
    #include 
    #include 
    
    int main() {
      int safe = 0;
      std::string s;
      while (std::getline(std::cin, s)) {
        std::istringstream iss(s);
        int a, b, c;
        if (!(iss >> a >> b)) {
          safe++; continue;
        }
        if (a == b || std::abs(a-b) > 3) continue;
        bool increasing = b > a;
        while (iss >> c) {
          if (b == c || std::abs(b-c) > 3) goto structuredprogrammingisfornerds;
          switch (increasing) {
            case false:
              if (c < b) { b = c; continue; }
              goto structuredprogrammingisfornerds;
            case true:
              if(c > b) { b = c; continue; }
              goto structuredprogrammingisfornerds;
          }
        }
        safe++;
        structuredprogrammingisfornerds:;
      }
      std::cout << safe << std::endl;
    }
    

    As usual the second part has punished me for my cowboy code, so I’ll have to take a different more annoying tack (maybe tomorrow). Or you know I could just double down on the haphazard approach…

    • I decided to double down on 2-2, since bad code is one of life’s little pleasures. Where we’re going we won’t need big-oh notation

      spoiler
      #include 
      #include 
      #include 
      #include 
      #include 
      
      template 
      bool seemslegit(It begin, It end) {
          if (std::distance(begin, end) == 1) {
            return true;
          }
          int a = *begin++;
          int b = *begin++;
          if (a == b || std::abs(a-b) > 3) return false;;
          bool increasing = b > a;
          while (begin != end) {
            int c = *begin++;
            if (b == c || std::abs(b-c) > 3) return false;;
            switch (increasing) {
              case false:
                if (c < b) { b = c; continue; }
                return false;
              case true:
                if(c > b) { b = c; continue; }
                return false;
            }
          }
          return true;
      }
      
      template 
      void debug(It begin, It end) {
        bool legit = seemslegit(begin, end);
        while (begin != end) {
          std::cout << *begin++ << " ";
        }
        //std::cout << ": " << std::boolalpha << legit << std::endl;
      }
      
      int main() {
        int safe = 0;
        std::string s;
        while (std::getline(std::cin, s)) {
          std::istringstream iss(s);
          std::vector report((std::istream_iterator(iss)),
                                  std::istream_iterator());
          debug(report.begin(), report.end());
          if (seemslegit(report.begin(), report.end())) {
            safe++;
            std::cout << "\n\n";
            continue;
          }
          for (int i = 0; i < report.size(); ++i) {
            auto report2 = report;
            auto it = report2.erase(report2.begin()+i);
            debug(report2.begin(), report2.end());
            if (seemslegit(report2.begin(), report2.end())) {
              safe++;
              break;
            }
          }
          std::cout << "\n\n";
       }
        std::cout << safe << std::endl;
      }
      
      Commentary

      Doing this “efficiently” should be possible. since you only need ~2-ish look-back you should be able to score reports in O(n) time. One complication is you might get the direction wrong, need to consider that erasing one of the first two elements could change the direction. But that requires thinking, and shoving all the permutations into a function with ungodly amounts of copying does not.

        •  gerikson   ( @gerikson@awful.systems ) 
          link
          fedilink
          English
          arrow-up
          5
          ·
          1 year ago
          re: 2-2

          I was convinced that some of the Perl gods in the subreddit would reveal some forgotten lore that solved this in one line but looks like my brute force method of removing one element at a time was the way to go.

          • I am now less sleep deprived so can say how to do better somewhat sensibly, albeit I cannot completely escape from C++s verbosity:

            2-2
            1. Don’t worry about the sequences changing direction. Just call the check function both assuming it is increasing and assuming it is decreasing. This is cheap enough because the wrong branch will fail after 3 elements or so.
            2. When encountering an element that fails, you only need to consider removing the previous element, or the current element. If you can get to the next element removing one of those then you can continue on without any real backtracking.

            Updated code:

            2-2
            #include 
            #include 
            #include 
            #include 
            #include 
            
            bool valid_pair(const std::vector &arr, int i, int j, bool direction) {
              if (i < 0) return true;
              if (j == arr.size()) return true;
              return    !(arr[i] == arr[j])
                     && (direction ? arr[i] < arr[j] : arr[j] < arr[i])
                     && (std::abs(arr[j]-arr[i]) <= 3);
            }
            
            bool valid(const std::vector &arr, bool direction) {
              int checks = 1;
              for (int i = 1; i < arr.size(); ++i) {
                if (valid_pair(arr, i-1, i, direction)) continue;
                if (checks == 0) return false;
                if (   valid_pair(arr, i-2,  i, direction)
                    && valid_pair(arr, i,  i+1, direction)) {
                  checks -= 1; i += 1;
                } else if (valid_pair(arr, i-1, i+1, direction)) {
                  checks -= 1; i += 1;
                } else return false;
              }
              return true;
            }
            
            int main() {
              int safe = 0;
              std::string s;
              while (std::getline(std::cin, s)) {
                std::istringstream iss(s);
                std::vector report((std::istream_iterator(iss)),
                                        std::istream_iterator());
                safe += (valid(report, true) || valid(report, false));
              }
              std::cout << safe << std::endl;
            }