Deprecated: Creation of dynamic property wpdb::$categories is deprecated in /var/www/twodee/blog/wp-includes/wp-db.php on line 668

Deprecated: Creation of dynamic property wpdb::$post2cat is deprecated in /var/www/twodee/blog/wp-includes/wp-db.php on line 668

Deprecated: Creation of dynamic property wpdb::$link2cat is deprecated in /var/www/twodee/blog/wp-includes/wp-db.php on line 668

Deprecated: Return type of WP_Theme::offsetExists($offset) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-theme.php on line 554

Deprecated: Return type of WP_Theme::offsetGet($offset) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-theme.php on line 595

Deprecated: Return type of WP_Theme::offsetSet($offset, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-theme.php on line 535

Deprecated: Return type of WP_Theme::offsetUnset($offset) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-theme.php on line 544

Deprecated: Return type of WP_REST_Request::offsetExists($offset) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/rest-api/class-wp-rest-request.php on line 960

Deprecated: Return type of WP_REST_Request::offsetGet($offset) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/rest-api/class-wp-rest-request.php on line 980

Deprecated: Return type of WP_REST_Request::offsetSet($offset, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/rest-api/class-wp-rest-request.php on line 992

Deprecated: Return type of WP_REST_Request::offsetUnset($offset) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/rest-api/class-wp-rest-request.php on line 1003

Deprecated: Return type of WP_Block_List::current() should either be compatible with Iterator::current(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 151

Deprecated: Return type of WP_Block_List::next() should either be compatible with Iterator::next(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 175

Deprecated: Return type of WP_Block_List::key() should either be compatible with Iterator::key(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 164

Deprecated: Return type of WP_Block_List::valid() should either be compatible with Iterator::valid(): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 186

Deprecated: Return type of WP_Block_List::rewind() should either be compatible with Iterator::rewind(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 138

Deprecated: Return type of WP_Block_List::offsetExists($index) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 75

Deprecated: Return type of WP_Block_List::offsetGet($index) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 89

Deprecated: Return type of WP_Block_List::offsetSet($index, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 110

Deprecated: Return type of WP_Block_List::offsetUnset($index) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 127

Deprecated: Return type of WP_Block_List::count() should either be compatible with Countable::count(): int, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 199

Deprecated: Creation of dynamic property Automattic\Jetpack\Connection\Manager::$error_handler is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/vendor/automattic/jetpack-connection/src/class-manager.php on line 91

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Instagram_Gallery::$is_wpcom is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-instagram-gallery.php on line 23

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Mailchimp::$wpcom_is_wpcom_only_endpoint is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-mailchimp.php on line 17

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Tweetstorm_Gather::$wpcom_is_wpcom_only_endpoint is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-tweetstorm-gather.php on line 21

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Tweetstorm_Gather::$is_wpcom is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-tweetstorm-gather.php on line 22

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Gutenberg_Available_Extensions::$wpcom_is_site_specific_endpoint is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/gutenberg-available-extensions.php on line 20

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Memberships::$wpcom_is_wpcom_only_endpoint is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/memberships.php on line 23

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Memberships::$wpcom_is_site_specific_endpoint is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/memberships.php on line 24

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Subscribers::$wpcom_is_wpcom_only_endpoint is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/subscribers.php on line 15

Deprecated: Creation of dynamic property Automattic\Jetpack\Sync\Queue::$random_int is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/vendor/automattic/jetpack-sync/src/class-queue.php on line 38

Deprecated: Creation of dynamic property Automattic\Jetpack\Sync\Queue::$random_int is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/vendor/automattic/jetpack-sync/src/class-queue.php on line 38

Deprecated: Creation of dynamic property WPCOM_Widget_Goodreads::$shelves is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/modules/widgets/goodreads.php on line 33

Deprecated: DateTime::__construct(): Passing null to parameter #1 ($datetime) of type string is deprecated in /var/www/twodee/blog/wp-includes/script-loader.php on line 348

Deprecated: Creation of dynamic property Advanced_Editor_Tools::$toolbar_classic_block is deprecated in /var/www/twodee/blog/wp-content/plugins/tinymce-advanced/tinymce-advanced.php on line 347

Deprecated: Creation of dynamic property Advanced_Editor_Tools::$toolbar_block is deprecated in /var/www/twodee/blog/wp-content/plugins/tinymce-advanced/tinymce-advanced.php on line 349

Deprecated: Creation of dynamic property Advanced_Editor_Tools::$toolbar_block_side is deprecated in /var/www/twodee/blog/wp-content/plugins/tinymce-advanced/tinymce-advanced.php on line 350

Deprecated: Creation of dynamic property Advanced_Editor_Tools::$panels_block is deprecated in /var/www/twodee/blog/wp-content/plugins/tinymce-advanced/tinymce-advanced.php on line 351

Deprecated: Creation of dynamic property Advanced_Editor_Tools::$used_block_buttons is deprecated in /var/www/twodee/blog/wp-content/plugins/tinymce-advanced/tinymce-advanced.php on line 354

Deprecated: Creation of dynamic property WP_Block_Type::$plan_check is deprecated in /var/www/twodee/blog/wp-includes/class-wp-block-type.php on line 333

Deprecated: Creation of dynamic property WP_Block_Type::$plan_check is deprecated in /var/www/twodee/blog/wp-includes/class-wp-block-type.php on line 333

Deprecated: Creation of dynamic property WP_Block_Type::$plan_check is deprecated in /var/www/twodee/blog/wp-includes/class-wp-block-type.php on line 333

Deprecated: Creation of dynamic property WP_Block_Type::$plan_check is deprecated in /var/www/twodee/blog/wp-includes/class-wp-block-type.php on line 333

Deprecated: Creation of dynamic property WP_Block_Type::$plan_check is deprecated in /var/www/twodee/blog/wp-includes/class-wp-block-type.php on line 333

Deprecated: Creation of dynamic property WP_Block_Type::$plan_check is deprecated in /var/www/twodee/blog/wp-includes/class-wp-block-type.php on line 333

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198
» CS 1: Lecture 12 – Testing and Graphics

teaching machines

CS 1: Lecture 12 – Testing and Graphics

October 2, 2017 by . Filed under
Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383

Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383

Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383

Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383

Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383
cs1, cs145, cs148, fall 2017, lectures.

Dear students,

Is there anything like charAt for integers? For instance, given a number and an “index” representing the place, can we get back the digit at that place? Not exactly, but there’s nothing stopping us from writing our own method to accomplish this task!

But before we do that, let me share with you a quotation from Maurice Wilkes, one of the developers of the first computers:

By June 1949 people had begun to realize that it was not so easy to get programs right as at one time appeared. I well remember when this realization first came on me with full force. The EDSAC was on the top floor of the building and the tape-punching and editing equipment one floor below… It was on one of my journeys between the EDSAC room and the punching equipment that “hesitating at the angles of stairs” the realization came over me with full force that a good part of the remainder of my life was going to be spent in finding errors in my own programs.

That “hesitating at the angles of stairs” is Wilkes alluding to the poetry of T.S. Eliot.

If we are going to be an inventor—even an inventor of software—we must care to do it right. We must make sure our software does its task well. To ease this burden, we’ll talk a little bit about test-driven development.

Here’s a recipe to follow when writing a method to accomplish some task:

  1. Accept that you will not write the method perfectly in the first draft, and that this imperfection doesn’t mean you are not cut out to write code.
  2. Determine the method name and its inputs and outputs.
  3. Write the method so that it does nothing but compile. Have it immediately return 0 or false or null.
  4. Write a test thats feeds certain values to the method. Pit the expected results from running the method on these values against the actual results.
  5. Fix the method so that the test passes.
  6. Clean up any code that needs cleaning up, making sure the tests continue to pass as you make changes.
  7. Repeat step 3.

This process is called red-green-refactor—red for erroring test, green for passing test, and refactor for that beautiful moment when you know you code is working and where edits can be made without fear. The process is intended to minimize headache. Writing software can be an enjoyable intellectual activity, but only when you anticipate your mistakes. When you bounce from error to error and each one surprises you, you will start to think you aren’t fit to write code. But really the problem is your blundersome technique.

So, here we are at step 2. Let’s call the method digitAt, give it the number and place index, and have it return the digit, which will be an int in [0-9]:

public static int digitAt(int n, int place) {
  // ...
}

Step 3 is about doing the least you can to make the code compile:

public static int digitAt(int n, int place) {
  return 0;
}

Step 4 is to write a test. We could do this in a little main:

public static void main(String[] args) {
  int expected = 7;
  int actual = digitAt(8752, 2);
  System.out.printf("%d == %d | place 2 from 8752%n", expected, actual);
}

Step 5 is to fix the code so the test passes. A purist of test-driven development might tell you to do the simplest thing possible to make the test pass:

public static int digitAt(int n, int place) {
  return 2;
}

The test should pass now.

Let’s jump back to step 3 and add another test:

public static void main(String[] args) {
  int expected = 7;
  int actual = digitAt(8752, 2);
  System.out.printf("%d == %d | place 2 from 8752%n", expected, actual);
  expected = 5;
  actual = digitAt(8752, 1);
  System.out.printf("%d == %d | place 1 from 8752%n", expected, actual);
}

But if we are going to consistently test code, we want to make writing tests as simple and brief as possible. Let’s create a new abstraction in a separate class that we will expect to reuse:

public class Certainly {
  public static void same(int expected, int actual, String message) {
    System.out.printf("%d == %d | %s%n", expected, actual, message);
  }
}

Then in main I can simply say this:

Certainly.same(7, digitAt(8752, 2), "place 2 from 8752");
Certainly.same(5, digitAt(8752, 1), "place 1 from 8752");

When I run this, the first test passes but the second fails. Now we must attend to the deeper logic issues we have going on in digitAt. We’ll sort out the implementation together in class. But after we get something working, we keep adding tests to try and break it. We should test on negative numbers, we should test place indices that reach beyond the number.

Here’s how I’d implement it:

public static int digitAt(int n, int place) {
  int withoutRightDigits = n / (int) Math.pow(10, place);
  int onesPlace = withoutRightDigits % 10;
  return onesPlace;
}

We could do some magic with String too, but that solution requires an if statement to avoid out-of-bounds errors. I guess we could write it like this:

public static int digitAt(int n, int place) {
  n = Math.abs(n);
  String s = "0" + n;
  return s.charAt(Math.max(0, s.length() - 1 - place)) - '0';
}

But this solution seems obtuse to me.

Here’s your TODO list to complete before we meet again:

See you next class!

Sincerely,

P.S. It’s time for a haiku!

Red is no stop sign
It is the color of fire
Swing your hammer there

P.P.S. Here’s the code we wrote together in class…

Digits.java

package lecture1002;

public class Digits {
  public static void main(String[] args) {
//    System.out.printf("%d == %d | %s%n", 2, digitAt(12, 0), "place 0 of 12");
//    System.out.printf("%d == %d | %s%n", 1, digitAt(12, 1), "place 1 of 12");
    Certainly.samesies(2, digitAt(12, 0), "place 0 of 12");
    Certainly.samesies(1, digitAt(12, 1), "place 1 of 12");
    Certainly.samesies(0, digitAt(12, 1000), "place 1000 of 12");
    Certainly.samesies(4, digitAt(-734, 0), "place 0 of -734");
    Certainly.samesies(3, digitAt(-734, 1), "place 1 of -734");
    Certainly.samesies(7, digitAt(-734, 2), "place 2 of -734");
    Certainly.samesies(0, digitAt(-734, 3), "place 3 of -734");

  }
  
  public static int digitAt(int n, int placeIndex) {
    int withoutRightestDigits = Math.abs(n) / (int) Math.pow(10, placeIndex);
    int digit = withoutRightestDigits % 10;
    return digit;
  }
}

Certainly.java

package lecture1002;

public class Certainly {
  public static void samesies(int expected, int actual, String message) {
    System.out.printf("%d == %d | %s%n", expected, actual, message);
  }
   
  
  public static void main(String[] args) {
    System.out.println("Foo");
  }
}

Drawer.java

package lecture1002;

import java.awt.Color;
import java.awt.Graphics2D;
import java.util.Random;

public class Drawer {
  public static void main(String[] args) {
    Canvas canvas = new Canvas(1024, 768);
    Graphics2D g = canvas.getGraphics();
    
//    g.setColor(Color.ORANGE);
//    g.fillRect(23, 17, 120, 500000);
    g.setColor(Color.CYAN);
    g.fillRect(0, 0, 1024, 768);
    
    Random generator = new Random();
    for (int i = 0; i < 100; ++i) {
      drawSun(generator.nextInt(1024), generator.nextInt(768), generator.nextInt(50), g);
    }
    
    canvas.show();
  }
  
  public static void drawSun(int ox, int oy, int radius, Graphics2D g) {
    g.setColor(Color.YELLOW);
    g.fillOval(ox - radius, oy - radius, 2 * radius, 2 * radius);
  }
}

Digits.java

package lecture1002;

public class Digits {
  public static void main(String[] args) {
//    System.err.printf("%d == %d | %s%n", 4, digitAt(74, 0), "place 0 of 74");
//    System.err.printf("%d == %d | %s%n", 7, digitAt(74, 1), "place 1 of 74");
    Certainly.samesies(4, digitAt(74, 0), "place 0 of 74");
    Certainly.samesies(7, digitAt(74, 1), "place 1 of 74");
    Certainly.samesies(5, digitAt(83245, 0), "place 0 of 83245");
    Certainly.samesies(4, digitAt(83245, 1), "place 1 of 83245");
    Certainly.samesies(2, digitAt(83245, 2), "place 2 of 83245");
    Certainly.samesies(3, digitAt(83245, 3), "place 3 of 83245");
    Certainly.samesies(8, digitAt(83245, 4), "place 4 of 83245");
//    Certainly.samesies(0, digitAt(83245, -1), "place -1 of 83245");

    Certainly.samesies(1, digitAt(-1, 0), "place 0 of -1");

  }
  
  public static int digitAt(int n, int placeIndex) {
    int withoutRightmost = Math.abs(n) / (int) Math.pow(10, placeIndex);
    int digit = withoutRightmost % 10;
    return digit;
  }
}

Certainly.java

package lecture1002;

public class Certainly {
  public static void samesies(int expected, int actual, String message) {
    System.err.printf("%d == %d | %s%n", expected, actual, message);
  }
}

Scene.java

package lecture1002;

import java.awt.Color;
import java.awt.Graphics2D;
import java.util.Random;

public class Scene {
  public static void main(String[] args) {
    Canvas canvas = new Canvas(1000, 800);
    Graphics2D g = canvas.getGraphics();

    g.setColor(Color.CYAN);
    g.fillRect(0, 0, 1000, 800);
    
    Random gen = new Random();
    for (int i = 0; i < 100; ++i) {
      drawSun(gen.nextInt(1000), gen.nextInt(800), gen.nextInt(60) + 10, g);
    }

    canvas.show();
  }

  public static void drawSun(int ox, int oy, int radius, Graphics2D g) {
    g.setColor(Color.ORANGE);
    g.fillOval(ox - radius, oy - radius, radius * 2, radius * 2);
    for (int degrees = 0; degrees < 360; degrees += 10) {
      drawRay(degrees, ox, oy, radius * 1.1, radius * 1.5, g);
    }
  }

  public static void drawRay(int degrees, int ox, int oy, double iRadius, double oRadius, Graphics2D g) {
    int x1 = (int) (ox + iRadius * Math.cos(Math.toRadians(degrees)));
    int x2 = (int) (ox + oRadius * Math.cos(Math.toRadians(degrees)));
    int y1 = (int) (oy + iRadius * Math.sin(Math.toRadians(degrees)));
    int y2 = (int) (oy + oRadius * Math.sin(Math.toRadians(degrees)));
    g.drawLine(x1, y1, x2, y2);
  }
}

Canvas.java

package lecture1002;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Canvas {
  private JFrame frame;
  private BufferedImage image;

  public Canvas(int width, int height) {
    image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

    SwingUtilities.invokeLater(() -> {
      frame = new JFrame("Canvas");
      frame.add(new CanvasPanel());
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setSize(width, height);
    });
  }

  public Graphics2D getGraphics() {
    return image.createGraphics();
  }

  public void show() {
    SwingUtilities.invokeLater(() -> {
      frame.setVisible(true);
    });
  }

  private class CanvasPanel extends JPanel {
    @Override
    public void paintComponent(Graphics g) {
      g.drawImage(image, 0, 0, null);
    }
  }

  public static void main(String[] args) {
    Canvas c = new Canvas(512, 512);
    Graphics2D g = c.getGraphics();
    g.setColor(Color.RED);
    c.show();
  }
}