7
\$\begingroup\$

Odd prime numbers are either in the form of 4k+1 or 4k+3 where k is a non-negative integer. If we divide the set of odd prime numbers into two such groups like this:

4k+3  |   3     7  11          19  23      31          43  47      59      67  71    
      |
4k+1  |      5         13  17          29      37  41          53      61          73

we can see that the two groups are kind of racing with each other. Sometimes the so-called 'upper' group wins and sometimes the 'lower' one is on track. In fact, Chebyshev discovered that in this race, the upper group wins slightly more often.

The problem

Let's assume that we are interested in knowing the shape of this race track up to a certain number. Something like this:

prime race track

The upper and lower horizontal lines indicate that the next prime stays in the same group, while the slanted lines indicate a 'jump' from one group to the other.

Now assume that the underline character _ represents a lower horizontal line and the overline character (U+203E) represents an upper one. The slanted lines are represented by slash / or backslash \ characters.

Challenge

Write a program or function that gets a number N as input, and draws this prime race track up to N, in a kind of ASCII-art-form described as above (Well, it's not an actual ASCII-art since it would contain a non-ASCII character).

Rules

  • N is an integer and not necessarily a prime number. Draw the race path for the primes up to, (and maybe including) N.
  • For a valid N as input, the output shall only be composed of these four characters ‾_/\. No other character, space or separator is allowed (except maybe at the end of output).
  • The output can either be in a text file or stdout or wherever supports displaying those characters. But an actual plot (like the blue figure above) is not desired.
  • This is , so the shortest code in bytes wins.

Examples

Here is a list of possible inputs and their acceptable outputs.

N < 5        no output or maybe an error message whatsoever
N = 5        \
N = 20       \/‾\_/
N = 100      \/‾\_/‾\/\_/‾\/\/‾\/‾\_

Trivia

The resulting plots of this challenge may actually resemble the derivative of the plots shown in there.

\$\endgroup\$
  • 1
    \$\begingroup\$ Do we really have to use a non-ASCII character? Can we replace by -? \$\endgroup\$ – Luis Mendo Apr 14 at 16:08
  • 1
    \$\begingroup\$ @LuisMendo Don't you agree that it would be ugly? \$\endgroup\$ – polfosol ఠ_ఠ Apr 14 at 16:09
  • 4
    \$\begingroup\$ Yes, - is uglier than in this context. But to me it's even worse to require a non-ASCII character, especially for ASCII-art \$\endgroup\$ – Luis Mendo Apr 14 at 16:14
  • 3
    \$\begingroup\$ Something you might not be aware of is that challenges about primes have been way overdone over the course of this site. So, while I think the ASCII art visualization based on modulus is a nice idea for a challenge, the fact that a solution needs to start with either generating primes or calling a primes built-in means that writing a solution will feel somewhat samey to many past challenges. \$\endgroup\$ – xnor Apr 14 at 16:23
  • 5
    \$\begingroup\$ As others have mentioned, I would indeed advice to use - or ~ instead of . Here another challenge using those same characters where the same is done. The main reason to allow this is to open up the challenge to more languages, because there are quite a few languages that can't even use non-ASCII characters, so they would be unable to complete just because of that single character in an otherwise good challenge. \$\endgroup\$ – Kevin Cruijssen Apr 14 at 16:46
6
\$\begingroup\$

Python 2 (IronPython), 87 bytes

I'm using IronPython here to display the unicode character , since Python can't print it.

P=a=b=1
s=''
exec"if P%a:s+='\/‾_'[b%4/2-a%4];b=a\nP*=a*a;a+=1\n"*input()
print s[2:]

Try it online!

Explanation

The idea of calculating primes comes from this answer, which uses Wilson's theorem. To figure out which character to print, we use the following formula: \$ \frac{b \bmod 4} 2 - a \bmod 4 \$, where \$ a \$ and \$ b \$ represent the current and previous prime numbers. Here is a table to show how this works:

 a mod 4 | b mod 4 | a'/2-b'
---------+---------+---------
    1    |    1    |   -1
    1    |    3    |   -3
    3    |    1    |    0
    3    |    3    |   -2

And in Python negative indices wrap around to the end of the string, so each index maps to its own character.

| improve this answer | |
\$\endgroup\$
5
\$\begingroup\$

05AB1E, 31 26 19 bytes

…\/_ŽW ç«ÀIÅP¦4%üeè

-5 bytes by taking inspiration from @HyperNeutrino's Jelly answer.
-7 bytes thanks to @Grimmy.

Outputs as a list of characters.

Try it online (the J in the footer is to join the list together to pretty-print it).

Explanation:

…\/_                 # Push the string "\/_"
    ŽW               # Push compressed integer 8254
       ç             # Convert it to a character with this codepoint: "‾"
        «            # Append it to the earlier string: "\/_‾"
         À           # And rotate it once to the left: "/_‾\"
          IÅP        # Push a list of all primes <= the input-integer
                     #  i.e. 50 → [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47]
             ¦       # Remove the first value
                     #  → [3,5,7,11,13,17,19,23,29,31,37,41,43,47]
              4%     # Take modulo-4 on each value
                     #  → [3,1,3,3,1,1,3,3,1,3,1,1,3,3]
                ü    # For each overlapping pair:
                     #  → [[3,1],[1,3],[3,3],[3,1],[1,1],[1,3],[3,3],[3,1],[1,3],[3,1],[1,1],[1,3],[3,3]]
                 e   #  Get the number of permutations; short for ⌊a!/|a-b|!⌋
                     #   → [3,0,6,3,1,0,6,3,0,3,1,0,6]
                  è  # And index each into the earlier created string
                     # (0-based and with wraparound, so the 6 is index 2 in this case)
                     #  → ["\","/","‾","\","_","/","‾","\","/","\","_","/","‾"]
                     # (after which the result is output implicitly as result)

See this 05AB1E tip of mine (section How to compress large integer?) to understand why ŽW is 8254.

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

Wolfram Language (Mathematica), 102 bytes

TIO doesn't display U+203E...

""<>(Partition[Prime@Range[2,PrimePi@#]~Mod~4,2,1]/.{{3,1}->"\\",{3,3}->"‾",{1,1}->"_",{1,3}->"/"})&

Try it online!

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

J, 50 bytes

1('/^\_'{~[:(+_1&|.*1&=)1+2*@-/\4&|)@}.(#~1&p:)@i.

Try it online!

Had to replace with ^ because the formatting on TIO screws up otherwise.

This uses < N convention.

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

JavaScript (ES6), 86 bytes

n=>(g=x=>x>n?'':['\\_/‾'[(P=n=>n%--d?P(n):d<2)(d=x)&&(q==(q=x%4))|q&2]]+g(x+1))(q=4)

Try it online!

Commented

n => (                  // n = input
  g = x =>              // g is a recursive function taking the current integer x
    x > n ?             // if x is greater than n:
      ''                //   stop recursion
    :                   // else:
      [                 //   make sure to turn undefined into an empty string
        '\\_/‾'[        //     pick the relevant character:
          ( P = n =>    //       P is a helper function taking n:
              n % --d ? //         decrement d; if d does not divide n:
                P(n)    //           try again until it does
              :         //         else:
                d < 2   //           return true if d = 1 (i.e. n is prime)
          )(d = x)      //       initial call to P with n = d = x
          &&            //       if x is not prime, ['\\_/‾'[false]] ~> empty string
          (             //       if x is prime:
            q ==        //         yield 1 if q is equal to ...
            (q = x % 4) //         ... the new value of q which is x mod 4
          ) | q & 2     //         bitwise OR with q & 2 for the direction
        ]               //     end of character lookup
      ] + g(x + 1)      //   add the result of a recursive call with x + 1
)(q = 4)                // initial call to g with x = q = 4
| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Python 3.8, 105 103 96 89 88 bytes

f=lambda n,i=3,j=5,t=24:n//j*" "and"\/‾_"[i%4//2-j%4]*(P:=t%j>0)+f(n,[i,j][P],j+1,t*j)

Try it online!

-1 byte thanks to @xnor!

Explanation:

This is a recursive function that increases j from 5 to n. If j is prime, the function compares it to the previous prime i to determine the race track character.

The following expression evaluates to 1 or 0 depending on whether j is prime or not:

t%j>0

where t is factorial(j-1). This uses Wilson's theorem, taken from @xnor's answer on another prime problem.

Given 2 consecutive prime i and j, the following code determines the character (shamelessly stolen from @dingledooper's answer):

"\/‾_"[i%4//2-j%4]
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ A one-byte shorter way to handle the base case here is n//j*"?"and. \$\endgroup\$ – xnor Apr 14 at 19:31
  • \$\begingroup\$ Thanks @xnor! I tried that before and somehow confused myself into thinking that it doesn't work. :( \$\endgroup\$ – Surculose Sputum Apr 14 at 19:34
2
\$\begingroup\$

Retina 0.8.2, 65 bytes

.+
$*
1
_1$`
^.{6}|_(11+)\1+(?!1)|1111|1(1?)
$2
_1
/1
1/
‾
1_
\

Try it online! Explanation:

.+
$*

Convert N to unary.

1
_1$`

Count up to N, using _ to separate the unary values, thus assuming all odd primes have a remainder of 1 (modulo 4) by default.

^.{6}|_(11+)\1+(?!1)|1111|1(1?)
$2

Delete 1, 2 and their separators; delete all composite numbers and their separators; reduce the odd primes modulo 4, and identify the primes with a remainder of 3 (modulo 4).

_1
/1

Still assuming that the prime previous to a prime with a remainder with 3 has a remainder of 1, change the _ to a /.

1/
‾

But if it turns out that the previous prime also has a remainder of 3, then change the / to a .

1_
\

Any remaining primes with a remainder of 3 must have a next prime with a remainder of 1, so change the _ to a \\.

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Jelly, 20 bytes

ÆRḊ%4ḄƝṣ9ị“\/_”j⁽ø¤Ọ

Try it online!

-3 bytes thanks to Jonathan Allan

Explanation

ÆRḊ%4ḄƝṣ9ị“\/_”j⁽ø¤Ọ  Main Link
ÆR                    Primes up to N
  Ḋ                   All but the first (3, 5, 7, 11, ...)
   %4                 Modulo 4
     ḄƝ               Convert each pair (overlapping run of 2) to binary (even though the digits are 1 and 3, this still works because it's just 2 x first digit + second digit) - 1,1: 3; 1,3: 5; 3,1: 7; 3,3: 9
       ṣ9             Split on 9 (the upper bar)
         ị“\/_”       Index into "\/_" (3 is _, 5 wraps around to /, 7 wraps around twice to \)
               j⁽ø¤   Join on 8254
                   Ọ  Convert from char code to character; doesn't affect characters, only the 8254s
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ 8254 can be written as ⁽ø¤ (converter - link also in the tutorial on the wiki) \$\endgroup\$ – Jonathan Allan Apr 15 at 18:43
  • \$\begingroup\$ You can also avoid testing for less than three like this. \$\endgroup\$ – Jonathan Allan Apr 15 at 19:05
  • \$\begingroup\$ @JonathanAllan Oh, that's clever. Also thanks, I keep forgetting about that thing lol. \$\endgroup\$ – HyperNeutrino Apr 15 at 19:48
1
\$\begingroup\$

Erlang (escript), 118 bytes

Erlang doesn't support negative indices so I had to do my own. (Also it doesn't display , so it's replaced with ^.)

p([_])->[];p([H|T])->[lists:nth(H rem 4+1rem(hd(T)rem 4),"_/\\^")|p([A||A<-T,A rem H>0])];p(X)->tl(p(lists:seq(2,X))).

Try it online!

Replaced formula

  a % 4  |  b % 4  | a + 1%b
---------+---------+---------
    1    |    1    |   1
    1    |    3    |   2
    3    |    1    |   3
    3    |    3    |   4
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.