For many purposes, however, the HSV representation is more suitable. It represents a color using three components:
Our first program will display a window like this:
We first need to learn how to display a window. You need to have the CS109UI module installed, see the installation instructions.
Download the example script uitest1.scala. You can run the example from the command line by saying:
$ scala uitest1.scala CS109 UI version 2015/03/31
Read the section "Basic Usage" of the cs109ui documentation.
Our program rainbow.scala will take one command line parameter, the value v (if the command line parameter is omitted, use v = 255). It should then create a BufferedImage of width 360 and height 256, and fill pixel \((x,y)\) of this image with the color with hue \(x\), saturation \(y\), and value v. To set the pixel, use the setRGB method of BufferedImage.
Here is a function that converts from HSV representation to RGB representation:
// Input h in [0,359], s in [0,255], v in [0,255] // Output r,g,b in [0,255] def hsvtorgb(h: Int, s: Int, v: Int): (Int, Int, Int) = { if (s == 0) { // no color, just grey (v, v, v) } else { val sector = h / 60 val f = (h % 60) val p = v * ( 255 - s ) / 255 val q = v * ( 15300 - s * f ) / 15300 val t = v * ( 15300 - s * ( 60 - f )) / 15300 sector match { case 0 => (v, t, p) case 1 => (q, v, p) case 2 => (p, v, t) case 3 => (p, q, v) case 4 => (t, p, v) case 5 => (v, p, q) } } }
Remember to include the cs109ui module when you run your program, like this:
$ scala rainbow.scala 180 CS109 UI version 2015/03/31
Here is the output for a few different v-values:
Now read the section "Updating the display" of the cs109ui documentation, and change the program as follows: It no longer takes a command line parameter. Instead the v-value starts with v = 255, but then it continuously changes until it reaches v = 0. The program should terminate automatically after that.
Change the v-value by one every time you call show, and wait for 100 milliseconds. You should also change the title of the window so that it always shows the current v-value.
Let's now write a program that can test your color vision. It displays a window like this:
$ scala colorguess.scala CS109 UI version 2015/03/31 Which square has a different color? (x to exit) 3a That is correct You answered 1 of 1 tests correctly. Which square has a different color? (x to exit) 1b That is correct You answered 2 of 2 tests correctly. Which square has a different color? (x to exit) 3a That is correct You answered 3 of 3 tests correctly. Which square has a different color? (x to exit) 2b That is correct You answered 4 of 4 tests correctly. Which square has a different color? (x to exit) 1d That is correct You answered 5 of 5 tests correctly. Which square has a different color? (x to exit) 3b That is not correct. Square 4c has a different color. Press Enter for the next question> You answered 5 of 6 tests correctly. Which square has a different color? (x to exit) 2d That is not correct. Square 2c has a different color. Press Enter for the next question> You answered 5 of 7 tests correctly. Which square has a different color? (x to exit) 1c That is correct You answered 6 of 8 tests correctly. Which square has a different color? (x to exit) x
Note that when the answer is correct, the program immediately displays the next test. When the answer is not correct, however, we need to give the user the chance to look at the colors again after revealing the correct answer—that's why the program says "Press Enter for the next question".
Your program should have one command line parameter, an integer that we will call delta. It indicates the distance between the different color and the standard color. If no command line argument is given, use the value delta = 20.
The following function generates a random color in HSV space:
def randomHSV(): (Int, Int, Int) = { ((math.random * 360).toInt, 128 + (math.random * 128).toInt, 128 + (math.random * 128).toInt) }
(Note that I'm excluding colors that are too dark or too grayish.)
The special color differs only in its hue from the standard color (saturation and value are the same). Flip a coin (for instance, using (math.random * 2).toInt). With probability \(1/2\), add delta to the hue, otherwise add 360 - delta to the hue (don't forget to do this operation modulo 360).
Keep showing colors to the user until the user types "x".
Here is an example for delta = 5. Can you distinguish the different color?