HW02 - james-bern/CS136 GitHub Wiki

image

README

In this challenging homework, we will learn how to use arrays and for loops by implementing a text input field.

Background

A text input field allows a user to type a message inside of a computer program. You've used these things your whole life, but probably haven't given them much thought.

Let's change that. 🙂👍

  • Try playing around with one of the search bars on this web page.
    • What happens when you...
      • press the B key on your keyboard?
      • press SHIFT + B?
      • press the LEFT_ARROW_KEY?
      • press the RIGHT_ARROW_KEY?
      • press BACKSPACE?
      • press COMMAND + A (or CONTROL + A on Windows)?
      • press the left mouse button?
      • hold the mouse and drag?
      • press B while some text is highlighted?
      • press BACKSPACE while some text is highlighted?
      • double-click?

We need to store a sequence of characters that we'll be changing a lot.

We will use an array, specifically an array of characters (char[]).

Java

arrays

  • char[] buffer = new char[8]; is an array of 8 char's called buffer
    • buffer.length will be 8
  • for (int i = 0; i < array.length; ++i) { ... } iterates over array forwards
  • for (int i = array.length - 1; i >= 0; --i) { ... } iterates over array backwards

Pro-tips

  • I highly recommend drawing simple little pictures of your array for this assignment
  • This will be very useful to work out carefully by hand what should happen to your array, rather than just guessing

Data

  • char[] buffer; stores the user's message as an array of characters
    • buffer can store a message of length at most buffer.length
  • int length; is the length of the current message stored in buffer
    • if (length == 0) then message is empty
    • if (length == buffer.length) then the message completely fills the buffer
  • int cursor; is the current cursor position
    • 0 means all the way to the left
    • 1 means in between buffer[0] and buffer[1]

Geometry

  • the left side of the canvas is $x = 0.0$
  • the right side of the canvas is $x = \texttt{buffer.length}$
  • we are using a monospaced font; this means each character is the same width;
    • for simplicity, we have each character be $1.0$ unit wide
    • buffer[0] is drawn from $x = 0.0$ to $x = 1.0$
    • cursor should be drawn at $x = \texttt{cursor}$
  • example
    • here is the message COW written in a monospaced font, with the cursor all the way to the left
      • buffer.length is 4
      • length is 3
      • cursor is 0
    | #####   #####   #   # 
    | #       #   #   #   # 
    | #       #   #   # # # 
    | #####   #####    # #  
    0       1       2       3       4   -> x
    
  • the bottom of the canvas is $y = -1.0$ and the top is $y = 2.0$ (NOTE: you don't need this fact except for the A++, at which point you'll probably want to write your own text drawing function(s) anyway)

User Interface

  • All features must match the behavior of a typical text input field
    • For example, pressing BACKSPACE should turn CO|W (length 3) into C|W (length 2); NOTE: the | is the cursor
    • You are responsible for discovering what the correct behavior of all commands is by experimenting with a real-world text input field

Reference

YouTube Link: https://www.youtube.com/watch?v=HTEWeeOiI3s

HW02S

NOTE's

  • You may NOT use any fancy Java standard library functions
    • Use for loops, if statements, and the functions inside Cow.java
  • You may NOT use the Java String class anywhere.
  • You may NOT create any new arrays (just modify the contents of buffer)
  • You may NOT use excessive repetition (for example, don't use separate if statements for c == 'A', c == 'B', c == 'C', ...)
  • You may NOT have any out of bounds errors

TODO's

  • A-

    • Update Cow
    • User can press A-Z (any of the keys A, B, ...)
    • Draw the cursor bar (location of cursor as a vertical line)
    • User can press 0-9
    • User can press SHIFT + A, SHIFT + B ...
    • User can press the space bar
      • HINT: this is the character ' '
    • User can press LEFT_ARROW
    • User can press RIGHT_ARROW
    • User can press BACKSPACE
  • A

    • Make the cursor bar blink
      • HINT: You will want to introduce a frame or time variable to keep track of the current frame / time
      • NOTE: Making the cursor bar not blink for a bit after keyAnyPressed is an optional good idea
    • Click the mouse to move cursor to the closest int
    • If the user presses ENTER while the buffer contains Passw0rd, replace the contents of the buffer with accepted
      • HINT: some repetition here is OK
  • A+

    • Click and drag the mouse to select/highlight a sequence of characters
      • HINT: int select = 0; can be the "selection cursor"; if (cursor == select) is true, then nothing is selected (and the cursor should be blink as usual); it it is false, then the characters in between the two numbers are selected
        • MIN(...) and MAX(...) may be useful
      • NOTE: pressing BACKSPACE while characters are selected must do the right thing
      • NOTE: pressing A, B, ... should also do the right thing
    • Press COMMAND + A or CONTROL + A to select all characters
      • NOTE: we want our app to be "cross platform" (work on both Mac and Windows)
    • (Optional, but put in free response if you did it) Double-click the mouse to select all characters
      • HINT: Be careful about the built-in mouseHeld (NOTE: mouseHeld is true for the first frame mousePressed is true--and likely for a few frames after that as well)
    • Improve the animations of the cursor; Inspo: https://diskvoyager.com; Additional very important inspo: https://www.youtube.com/watch?v=emjuqqyq_qc
  • A++ (105)

    • Build a full raw text editor like TextEdit/Notepad
      • Copy and paste from system clipboard
      • Multiple lines

Starter Code

class HW02 extends Cow {
    public static void main(String[] arguments) {

        char[] buffer = new char[8];
        int length = 0;
        int cursor = 0;

        canvasConfig(0.0, -1.0, buffer.length, 2.0, WHITE, 512);
        while (beginFrame()) {

            // TODO

            // NOTE: This function draws the first length-many characters of the buffer
            HW02_drawText(buffer, length, BLACK);
        }
    }
}

Hints

Iterate over the characters A-Z
for (char c = 'A'; c <= 'Z'; ++c) { ... }
Convert char from uppercase to lowercase
(char)('a' + (c - 'A'))
  • Example: ('D' - 'A') -> 3 and (char) ('a' + 3) -> 'd'
How can I make my code for typing letters, numbers and spaces less repetitive?

If you're finding your code looks like this...

for (char c = 'A'; c <= 'Z'; ++c) {
    if (keyPressed(c)) {
         ... // Complicated logic for inserting a character
    }
}

for (char c = '1'; c <= '9'; ++c) {
    if (keyPressed(c)) {
        ... // Complicated logic for inserting a character
    }
}

if (keyPressed(' ')) {
    ... // Complicated logic for inserting a character
}

Maybe instead consider something like this!

char newCharacter = 0; // initialize to the null (0) character

for (char c = 'A'; c <= 'Z'; ++c) {
    ... // Simple logic to setting newCharacter
    // NOTE: this one also has to handle shift
}

for (char c = '0'; c <= '9'; ++c) {
    ... // Simple logic for setting newCharacter
}

if (keyPressed(' ')) {
    ... // Simple logic for setting newCharacter
}


if (newCharacter != 0) {
    ... // Complicated logic for inserting a character
}

Solution

class HW02A extends Cow {
    
    public static void main(String[] arguments) {
        
        final char[] buffer = new char[8];
        int length = 4;
        int cursor = 0;
        
        // NOTE: each character is 1 unit wide
        canvasConfig(0.0, -1.0, buffer.length, 2.0, WHITE, 512);
        
        int blinkCounter = 0;
        
        while (beginFrame()) {
            boolean insertCharacterValid = (length != buffer.length);
            boolean backspaceValid = ((length != 0) && (cursor != 0));
            boolean leftArrowKeyValid = (cursor != 0);
            boolean rightArrowKeyValid = (cursor != length);
            
            if (keyAnyPressed) {
                blinkCounter = 0;
            }
            
            if (insertCharacterValid) {
                char newCharacter; {
                    newCharacter = 0;
                    for (char c = 'A'; c <= 'Z'; ++c) {
                        if (keyPressed(c)) {
                            if (!keyHeld(SHIFT)) {
                                newCharacter = (char)('a' + (c - 'A'));
                            } else {
                                newCharacter = c;
                            }
                        }
                    }
                    for (char c = '0'; c <= '9'; ++c) {
                        if (keyPressed(c)) {
                            newCharacter = c;
                        }
                    }
                    if (keyPressed(' ')) {
                        newCharacter = ' ';
                    }
                }
                if (newCharacter != 0) {
                    for (int i = length; i > cursor; --i) buffer[i] = buffer[i - 1];
                    buffer[cursor] = newCharacter;
                    ++cursor;
                    ++length;
                }
            }
            
            if (backspaceValid && keyPressed(BACKSPACE)) {
                for (int i = cursor; i < length; ++i) buffer[i - 1] = buffer[i];
                --cursor;
                --length;
            }
            
            if (leftArrowKeyValid && keyPressed(LEFT_ARROW)) {
                --cursor;
            }
            
            if (rightArrowKeyValid && keyPressed(RIGHT_ARROW)) {
                ++cursor;
            }
            
            if (mousePressed) {
                cursor = length;
                for (int i = 0; i < length; ++i) {
                    if (mouseX < i + 0.5) {
                        cursor = i;
                        blinkCounter = 0;
                        break;
                    }
                }
            }
            
            if (keyPressed(ENTER)) {
                if (true
                        && (buffer[0] == 'P')
                        && (buffer[1] == 'a')
                        && (buffer[2] == 's')
                        && (buffer[3] == 's')
                        && (buffer[4] == 'w')
                        && (buffer[5] == '0')
                        && (buffer[6] == 'r')
                        && (buffer[7] == 'd')) {
                    buffer[0] = 'a';
                    buffer[1] = 'c';
                    buffer[2] = 'c';
                    buffer[3] = 'e';
                    buffer[4] = 'p';
                    buffer[5] = 't';
                    buffer[6] = 'e';
                    buffer[7] = 'd';
                }
            }
            
            { // draw
                if ((blinkCounter++ % 14) < 7) {
                    drawLine(cursor, -0.5, cursor, 1.5, PURPLE, 5.0);
                }
                HW02_drawText(buffer, length, BLACK);
            }
        }
        
    }
}
⚠️ **GitHub.com Fallback** ⚠️