Only this pageAll pages
Powered by GitBook
Couldn't generate the PDF for 174 pages, generation stopped at 100.
Extend with 50 more pages.
1 of 100

Computer Science

Our Curriculum and Department

This page will introduce you to the course material we're building and how the Computer Science Department at Gilmour Academy operates.

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

2D Game Design

Developing games using GameMaker Studio 2 and drag and drop programming

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

3D Game Design

Developing games using the Unity framework and the C# programming language

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Milling Concerns

Robotics 7

Loading...

Loading...

Loading...

Loading...

Loading...

Robotics 8

Introduction to App Development, Kivy, and Intermediate Python.

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

CAD Examples

Elevators

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

1: Parts of a Computer

What are the parts that make up a typical computer? Let's take one apart, label its components and talk about what each does.

Expectations

Learning Targets

  • I can disassemble and reassemble a computer.

  • I can describe the function of basic PC components.

Assessments

  • You will be asked comprehension questions to identify parts of a computer from their images, what their primary purpose is, and what their common problems are

  • You will be observed disassembling and reassembling a computer and checked that you can identify all the components and that you can reassemble the machine correctly

Components

Imagine a person juggling while singing an old song from their childhood. Part of the juggler's brain is tracking the motion of each ball and the timing of each throw. Another part of the juggler's brain is recalling the song. His stomach is fueling his muscles. His nervous system is communicating controls from his brain to his arms. His eyes are taking in information. His voice is outputting the song. We'll use this as a reference as we go over hardware.

Central Processing Unit

Description

CPUs or processors do math. They are a super complex series of logic gates made unbelievably small. What are logic gates? Imagine a wire with two light switches in a row. Since both switches are on the same wire, both need to be flipped to the ON position in order for power to flow through the line. That's an AND gate. If the wire split into two instead and each fork had its own switch, that would be an OR gate as only one or the other has to be enabled for power to flow. Processors have millions and millions of these complex arrangements made in microscopic sizes.

According to our analogy, the CPU is the part of the juggler's brain that's calculating the path of each ball while also managing all the other signals through his brain. It doesn't cover all the functions of the brain in our analogy, but it is at the center of the comparison.

Problems with CPUs

CPUs use a lot of power and generate heat. Metal wires create a little resistance as electricity flows through them and that energy turns into heat. You must manage the heat that gets created by your CPU using a fan or other cooling system. If your computer collects a lot of dust, it will insolate

If a CPU is older it means it could be generating more heat while executing fewer commands. And if the CPU is slow, that means it must be connected to a whole bunch of other parts that are older and slower too.

Extra Information

Random Access Memory

Motherboard

Hard Disk Drive

Power Supply and Case

Peripheral Devices

Additional Practice

  • Create a Quizlet set and practice these terms

APIs Make Life Easier

No one writes code totally from scratch. All programmers use a variety of preexisting systems that allow for easier development. We write code that interacts with other layers. That's an API or Application Program Interface. We can interact with our operating system, helpful resources or other apps.

BIOS

The BIOS or Basic Input/Output System is firmware. It's something built right into your motherboard. It helps boot your computer up and gives something for the operating system to run off of.

Operating System

The OS is a big deal. It serves as a vital intermediary between software and hardware. Instead of having to program every little operation for each device in our computer, we can just use the commands provided by the operating system.

Interpreter

The interpreter allows us to execute our written Python code. It's our interface with the Operating System which is in turn interfacing with our hardware.

Libraries and Packages

Part of what makes Python so great are all the tools and frameworks available. Want to build a web application? Use Flask or Django and you'll be up and running in minutes. Do you want tools for data analysis? Machine learning? Robotics? There's an ocean of open-source tools ready to give your app superpowers.

5: Interactive Turtles

Expectations

Learning Targets

  • I can interpret an unfamiliar code base.

  • I can extend the code to my own project.

Assessments

  • You will create an interactive program or game based on existing turtle classes

  • You will be asked regular comprehension questions about Python.

First Class Assignment (CodeHS.com)

Adding Moving Turtle

Assignment and Rubric

Create an interactive turtle application of your own design. This can be a game or other interactive program, but it must use at least two of the three types of turtle classes we have outlined (moving turtle, keyboard turtle, clickable turtle).

  • 3 pts - Program works without errors

  • 3pts - Program uses two classes of turtle

  • 3pts - Program is interactive. Users can DO something with the program beyond what we set up in class. Make sure your theme is cohesive!

  • 1pts - Program is cleaned up (unused imports have been deleted, for example)

How do I...

...make multiple things move?

...write text on the screen?

...stop movement with walls?

...make a ball move diagonally and bounce off multiple sides of the room?

... create a background image and have it change later?

...set up and check a timer

...add a start screen

...Save a High Score in a File?

... add points from different objects to a single score?

... get objects to check each other for different properties?

...find the x and y position of my mouse on the screen?

...create a custom shaped turtle?

...create a multi-colored turtle?

In case you're curious and don't mind a little challenge, learn about the and how computer engineers have gotten around it.

Look through and read how the experts recommend you shop for components

Von Neumann Bottleneck
Tom's Hardware
from turtle import Turtle


class ClassName (Turtle):
    def __init__(self, starting_x, starting_y):
        Turtle.__init__(self)
        self.starting_x = starting_x
        self.starting_y = starting_y
        
        # General setup
        # self.color("black")
        # self.penup()
        # self.shape("turtle")
        # self.goto(self.starting_x, self.starting_y)
        
    def method_example(self):
        pass
        ## change the name and make the method work

OLD 5: Replit, GitHub, and repositories (Oh my!)

Expectations

Learning Targets

  • I can connect replit to my github repositories

  • I can clone an existing repository, fork it, and extend the code to my own project.

Assessments

  • You will submit a link to your GitHub repo.

  • You will create a game based on existing turtle classes

  • You will be asked regular comprehension questions about Python and Github.

Setup your github account.

Setup your replit account and connect your github.

Join Replit I2P team with the link below.

Fork github.com/MrVanek/Interactive-Turtles and clone repository into replit.

Adding Moving Turtle

from turtle import Turtle


class ClassName (Turtle):
    def __init__(self, starting_x, starting_y):
        Turtle.__init__(self)
        self.starting_x = starting_x
        self.starting_y = starting_y
        
        # General setup
        # self.color("black")
        # self.penup()
        # self.shape("turtle")
        # self.goto(self.starting_x, self.starting_y)
        
    def method_example(self):
        pass
        ## change the name and make the method work

Assignment and Rubric

Create an interactive turtle application of your own design. This can be a game or other interactive program, but it must use at least two of the three types of turtle classes we have outlined (moving turtle, keyboard turtle, clickable turtle).

  • 3 pts - Program works without errors

  • 3pts - Program uses two classes of turtle

  • 3pts - Program is interactive. Users can DO something with the program.

  • 1pts - Program is cleaned up (unused imports have been deleted, for example)

How do I...

...make multiple things move?

...write text on the screen?

...stop movement with walls?

...make a ball move diagonally and bounce off multiple sides of the room?

... create a background image and have it change later?

...set up and check a timer

...add a start screen

...Save a High Score in a File?

... add points from different objects to a single score?

... get objects to check each other for different properties?

...find the x and y position of my mouse on the screen?

...create a custom shaped turtle?

7: Kivy

Kivy App 2 Rubric

Create an interactive program using the kivy framework. The app should be useful to you (i.e.; not a game or a tech demo).

The program will be graded as follows:

  • Usefulness - 2pts

  • Uses a minimum of six total widgets - 3pts

  • Uses at least one widget that is not from the following list (Label, BoxLayout, Button, TextInput, Spinner) - 2pts

  • Program works as intended with no crashes- 3pts

  • main.py is commented for clarity - 1pt

  • unneeded code should be cleaned up - 1pt


How do I...

...make multiple pages in a kivy app.

3: DRY Turtle

Expectations

Learning Targets

  • I can implement the basic constructs of programming languages such as variables, conditionals, loops, and flow control.

  • I can make a class wrapper that inherits from a library's class.

  • I can call a method from a library.

Assessments

Class Videos

Class 1/24 Turtle drawing assignment:

What is DRY code?

Loops and functions allow skilled programmers to make more efficient code that's easier to maintain.

Parts of a for loop

A for loop has an iterator and a collection that it traverses.

# the range command will build a list you can traverse
for x in range(5):
    print(x)
    
# you could also write it using a literal list:
for x in [0, 1, 2, 3, 4]:
    print(x) 

Parts of a function

A function has a definition that lists any parameters and has a code block underneath that gets activated when called.

def magic_spell(target):
    target.sneeze()

# let's make Steve sneeze
magic_spell(steve)

In the example above, the magic_spell function isn't a part of a Class. It's on its own. If that ability was a part of a player in a game, we'd call it a method instead of function.

class Player(object):
    
    def magic_spell(self, target):
        target.sneeze()
        
lucy = Player()
steve = Player()
lucy.magic_spell(steve)

# fun fact: you could also write line 8 like so:
Player.magic_spell(lucy, steve)

Code Along

We're going to jump into work with a lot of advanced concepts. This is intentional. New programmers are very often intimidated by code they don't understand. I want you to get used to that early on. Enjoy tinkering with a few lines here and there and see how things change. Get comfortable swimming in the deep end.

from turtle import Turtle

class SuperTurtle(Turtle):
  
  def __init__(self, x, y, color='blue', shape='turtle'):
    Turtle.__init__(self) # run the normal Turtle constructor
    self.color(color)
    self.shape(shape)
    self.penup()
    self.goto(x,y)

This class (inherits) from the Turtle class which is available since we imported the turtle library. Instead of writing from turtle import Turtle I could have also written just import turtle in which case every time I wanted to use the Turtle class, I would have had to specify the library, such as turtle.Turtle()

The only thing that our SuperTurtle does that the regular Turtle doesn't is the way it gets constructed. When a new Turtle is created or instantiated, we initialize or __init__ with some default properties.

Follow along as we go over a couple of skills. You aren't expected to be able to do this stuff yourself quite yet.

  1. Make a loop and create a bunch of turtles

  2. Add a new method to the turtle to make it go to a random location and call that method in the constructor

  3. Make a list of colors and make each turtle randomly select a color

  4. Make an empty list and add each turtle to the collection as it's being instantiated

  5. Loop through the turtle collection and modify each

We'll spend some time experimenting with this code, learning by modifying existing code.

Building Methods

# here's where we imported the Turtle class from the turtle package
from turtle import Turtle
# now from the random package, we imported to helpful functions
from random import randint, choice

def rancolor():
  """ This method returns a string from a list of colors available to Turtle's .color() method """
  colors = ["brown", "darkorange", "maroon", "crimson", "navy", "salmon", "tomato", "khaki", "gold", "hotpink", "springgreen", "blue", "cyan", "purple", "green", "red", "pink", "yellow", "teal"]
  return choice(colors)


class SuperTurtle(Turtle):
  # our own constructor that makes Turtles more convenient
  def __init__(self, shape='turtle'):
    Turtle.__init__(self)
    self.color(rancolor())
    self.shape(shape)
    self.penup()
    self.speed(9999)
    self.goto_random()
  
  def goto_random(self):
    self.goto(randint(-200,200), randint(-200,200))
    
  # HERE'S WHERE WE WILL ADD MORE METHODS
  def triangle(self):
    pass # replace pass with real code

  def square(self):
    pass # replace pass with real code
    
  def star(self):
    pass # replace pass with real code
  

# create a collection for our turtles
gang = []

# loop through a set range of 20 and 
# add a Turtle to our collection during each iteration   
for x in range(20):
  gang.append(SuperTurtle())
  
# loop through my gang and change each one
for x in gang:
  x.shape("triangle")

A method or function is a group of commands that can be called. If I tell you to please clap, that's me activating or calling the command that's already defined in your head. I may give you additional parameters or arguments like, "clap 5 times loudly". In Python that may input("What's your name?") but that doesn't save the variable, so we write it as:

name = input("What's your name?") written as joe.clap(5, "loudly")

What's the difference between a function and a method?

They both start with def and will execute their pre-programmed commands when called. However, we'll refer to a function as something floating outside of a class and a method as an ability built within an object. For example, a method would be if an instance of the Human class, let's call him Joe, had to sneeze: joe.sneeze(). But a function would be an anonymous helper like therancolor() function programmed above that just returns a random string in a list of colors.

Novel Design

Look at the documentation, other student examples, and Google searches to modify open-source code and customize your own design. You can use one or many turtles but the end result has to have multiple colors over a fun design.

Taking Controls

Let's make our app more interactive. Just like the print("message") function we've been using, there's another one that takes a string input called input()

input("What's your name?") will work but that doesn't save the user's response anywhere. So let's create a variable that will store the answer in this example:

name = input("What's your name?")

Testing the input

if "circle" in user_input:
    tina.circle()
elif "triangle" in user_input:
    tina.triangle()

To make sure we are asked the question over again, we'll put the input within a while True: loop.

Intro to Web Design

Build web pages using HTML/CSS and WordPress all according to modern design principles.

This is so awesome!

The Internet is the largest idea exchange ever built or conceived. Learning HTML, the language of the web, gives you incredible power to represent yourself or your work, or your clients. Let's start first by gathering our resources.

Links and Resources

Required Software (install these)

Required Practice (create accounts)

Design Assets (bookmark these)

Colors

Extra Training for Extra Cool Kids

We won't study much JavaScript in this class but it's one of the best ways to take web design to the next level.

1: Internet?

What is the Internet? We need to understand some of the basics to the underlying tech so we can understand why websites work the way they do.

Expectations

Learning Targets

  • I can describe a brief history of the Internet's origin and impact.

  • I can write a professionally formatted email.

Assessments

  • You will receive comprehension questions about why the Internet was made, the very basics of its technology, how the technology grew, and its significance to society.

The Idea

The Internet is mankind's greatest achievement. Mr. Adiletta takes a dramatic position on the Internet as a basic human right. The evolution of human intelligence goes beyond the growth of our brain. and into the development of communal stories, into libraries, and then into the Internet. The Internet is a product of human evolution and is the birthright to all people.

The Internet is a part of your mind and you have the right to use your brain.

Why was the Internet created?

Did Al Gore create the Internet?

In his 2000 Presidential campaign, Al Gore rightly took some credit in the creation of the Internet. No, he did not help develop the TCP/IP network. However, after the ARPANET project was complete, the ownership of the underlying technology was in question. It was offered for sale to at least one telecommunications company but they passed on buying the Internet not knowing what it would be good for. Al Gore was a part of a congressional effort to make TCP/IP a public resource. No one owns the Internet because of that. He also helped establish support to connect people--something we have a moral obligation to continue.

Significance of the Internet

Why is this video funny?

After watching this video, take a moment to think about why this video seems silly. It's not just her rockin' hair and vest or the British perspective of the American president. It may be the many, giant screens. But more specifically it's how the changing technology has changed our impressions. She talks about shopping on the internet as a future possibility and not something that everyone does like it's no big deal. Again, take a moment to understand that the Internet is a big deal.

The Internet has a physical component that must be appreciated, too.

Vocabulary

  • OSI model: The basis of the Internet. This describes how the TCP/IP network started by the Defense Department has evolved.

  • Domain Name System (DNS): A sort of phone book that changes or resolves domain names into IP addresses

    • A Record: routes primary domains like google.com

    • C Record: routes subdomains like mail.google.com

    • MX Record: routes email addresses. That's why emails @gilmour.org go to a different server than what's hosting the website at gilmour.org

Further Exploration

There are many free tools that help you learn about domains. These are very helpful for web designers as you may want to check on the current host of a client interested in a site redesign. Try looking up the record of a few domains using one of these tools:

6: Raspberry Pi / GoPiGo

Expectations

Learning Targets

  • I can connect to my Raspberry Pi via SSH.

  • I can deploy an app to a Raspberry Pi.

  • I can compose a higher-ordered algorithm.

  • I can update code on my Raspberry Pi.

  • I can make short, descriptive commit messages.

Assessments

  • You will submit a link to your GitHub repo.

  • You will demonstrate your capacity to control your robot.

  • You will be asked regular comprehension questions about Raspberry Pis.

Terms

Printed Circuit Board (PCB)

​

Single Board Computer (SBC)

This is a PCB with all the basic components found in a personal computer (PC)

Getting Started

Fork code

  1. Open Replit and start a new project from github

  2. Use your forked github project. You should now see your code on your editor. Explore student.py and teacher.py.

  3. Open putty and enter the ip address of your robot. Click open.

    • login: pi

    • password: robots1234

  4. Remove the Piggy folder if it's already there: rm -rf Piggy

  5. Now we'll clone your project on the robot too with git clone https://github.com/YOURUSERNAME/Piggy

  6. Change to your project folder: cd Piggy

  7. Run the app: python3 student.py

Push code to GitHub

Whenyou make changes to your app and want to update the code on your robot, we first need to send the code from our computers to GitHub. This happens in the version control tab by typing in "What did you change" and hitting Commit & Push.

Pull code on robot

Now we'll remote control our robots using SSH. We'll use Linux commands to pull the updated code down from GitHub.

Open putty and enter the ip address of your robot. Click open.

  • login: pi

  • password: robots1234

Note: You will not see the password when typing. This is a security feature!

  1. Make sure you're in the right folder: cd Piggy

  2. Pull your updated code: git pull origin master

  3. Run your app: python3 student.py

  4. If it doesn't run, study the error.

Calibrate

We'll need to configure your class variables.

Midpoint

Motor Speeds

Sometimes one motor will perform faster than the other, giving the robot a noticeable veer. We can try to correct for this drift by adjusting the motor power.

Moving Your Robot

Dance Project

Check out what commands are available from the API that's provided for you. These are the commands you're inheriting.

Higher-Ordered Logic

Your dance method should read as close to regular English as possible. The nitty-gritty commands are all kept in the particular methods being called in your dance algorithm. So your dance method should just call a handful of moves. Within those moves, you'll use the specific motor commands below and get into the nitty-gritty of robot control.

  • deg_fwd(angle) - how many degrees do you want your wheels to rotate? You need to pass the angle

  • turn_to_deg(angle) - rotates to the given angle as calculated by the piggy's gyroscope

  • turn_by_deg(angle) - turns relative to it's current heading. Positive values rotate right and negative rotate left

  • fwd - powers on your robot to drive forward. You'll need to use self.stop() to power off the motors

  • right - by default, self.right() will give the left motor 90% power and the right 0% which rotates right. You can use kwargs to adjust the power such as self.right(primary=90, counter=-90), which will spin the robot in place

  • left - same as right but reversed.

  • back - same as fwd but in reverse.

  • servo - moves the servo (plugged into servo1) to the given value (use 1000 - 2000)

  • stop - sets motor power to zero

  • read_distance - returns the distance from the distance sensor (plugged into I2C port) in millimeters

  • get_heading - returns the gyroscope's value

Shutting down the robot

To shut down your robot, type: sudo shutdown now in the putty window.

Basic Movement Methods

  • Square

  • Dance

  • Add safe_to_dance() method which checks surroundings and only dances if it has enough space.

  • Move to wall and stop

  • Move to wall and turn around. Move forward again and repeat endlessly.

  • Move to box and go around it

  • Before moving around box, figure out which side of closer. If you are closer to the left end of the box, go around left. If you are closer to the right end of the box, go around to the right.

Intermediate Movement Methods

  • Write a move method which scans slightly to the left and right of the robot as it moves forward.

  • If it senses a wall straight ahead, it goes around to the closest side as above (put that move in it's own method)

  • If it senses a wall at the edges of the robot, swerve slightly to miss the wall (this swerve should again be in it's own method).

Maze Navigation

  • Coming soon.

2: Parts of Python

Expectations

We're going to take a tour of Python. You are expected to know generally what these things are, you're not yet expected to know how to use them. So no freaking out. We'll play around with some fun projects after a quick look around.

Learning Targets

  • I can make a hello world app in Python.

  • I can differentiate between compile-time, run-time, and logic errors.

  • I can describe the basic constructs of programming languages such as variables, conditionals, loops, and flow control.

Assessments

  • You will be answering comprehension questions about the layers supporting software execution.

  • You will be creating and submitting your several small Python apps using trinket.io

Let's go to trinket.io and build some simple stuff, starting with print("Hello, world")

We'll go over each of these concepts in greater detail. For now, let's skim over all the big topics.

Class Videos

The first video deals with the following concepts: Functions, Variables, Operators and Conditionals

Class 1/4

Class 1/11

Class 1 / 20: User defined functions

class 1/24: for / while loops

Key Concepts

Data Types

The first thing we'll tinker with is declaring variables and storing information. Variables in Python are dynamically typed, meaning you can store one type of information in a variable and then switch it without any fuss. Other languages are more strict and don't allow such shenanigans.

Operators

We use math symbols for most common operations. But Python has some cool operators. Read!

Conditionals

Conditionals control how the program flows based on input from the user (in an app) or sensors (on a robot.

We'll reference the idea of a person juggling as an analogy to PC components
This CPU doesn't have pins or a big metal heat sink on top of it

You will be submitting scripts demonstrating the following skills.

Avoid having to copy and paste lines of code to repeat a command

Experimenting with code given to you is fun and can be very helpful, but let's slow things down now and build some basic skills. Your app should look something like this:

Hard, smart: (select JavaScript)

Fun: (select JavaScript)

You will send a professional email () taking a position on whether the Internet is a basic human right.

(Codecademy) Get started on the

During the height of the Cold War, the threat of a Soviet attack motivated the funding of a research project to build a web of communications lines. In such a network, if one line was cut by an attack, communications would proceed uninterrupted through alternate lines in the network. The beginnings of our was produced.

Internet Protocol (IP): A system for addressing and routing communication over a network. You can make up all the addresses you want on a private network, but the is the authority of the public's IPs and domains.

Visit the and fork it

Use SSH (on Mac) or (on Windows) to connect to your robot. Install PuTTy if it is not on your computer.

If the servo wasn't mounted perfectly, the midpoint won't be 1500. But that's rarely the case. We should adjust this to fit your particular robot.

Trinket.io
Trinket.io
Visual Studio Code
Google Drive
Codecademy
SoloLearn
Google Fonts
AllTheFreeStock
ThemeForest
https://coolors.co
https://colorhunt.co/
Color wheel
https://color.hailpixel.com
https://app.codesignal.com/
https://codecombat.com/
Afraid of phone lines disrupted in a nuclear war, the military funded research of a decentralized network
Pretty complicated, right? You don't need to memorize any of this for this class.
check against this guide
first HTML unit
TCP/IP network
IANA
https://intodns.com/
http://whois.domaintools.com/
https://www.whatsmydns.net/
project
PuTTy
magic number

4: Graphics and Branding

Let's talk about the design in web design.

Learning Targets

  • I can describe the difference between raster and vector.

  • I can describe the difference between serif and sans serif.

  • I can iterate on my design.

  • I can use Photoshop's masking layers and quick select tool.

  • I can create a logo in Adobe Illustrator.

Serif vs Sans Serif

One of the first decisions to make when starting a new project is your font selection. It helps set a lot of the tone for your site. Typically, I select a header font and a body font--something fun for titles and something easy to read for my paragraphs.

Color Palette

Another key mood-setting decision to make is the type of colors you'll use around your site.

Once you've selected your colors, we're going to add a note to your custom CSS like so:

/**

COLORS
https://coolors.co/05a8aa-b8d5b8-d7b49e-dc602e-bc412b
Blue: 05a8aa
Green: b8d5b8
Red: bc412b
Orange: dc602e

**/

Adjust your colors!

Choosing a hero image isn't just about visual impact; it sets the color palette for your entire website. Remember that initial color inspiration you had? Time to revisit it! Once your hero image is finalized, re-evaluate your chosen color scheme. Does it complement the image's tones and moods? Can you pull color accents directly from the image itself? Aligning your color scheme with your hero image fosters visual cohesion, ensuring a seamless and aesthetically pleasing browsing experience for your visitors. Don't let your hero stand alone; let its colors sing throughout your website's design.

Call to Action

Raster VS Vector

If your image has been zoomed in or stretched too far, and it's a rasterized image, you'll notice the pixels that make up the image. That's a problem. But the solution is not to use a super high-resolution image with a big file size. That'll just make your webpage take forever to load. We need the right resolution each time.

Use vector where you can. Raster, if the image is the right resolution, looks great. The image below can confuse students into thinking raster is always blurry.

Design Principles

Common Mistakes

  1. Navigation that isn't simple, logical and explanitory

  2. No clear calls to action

  3. Insufficient contrast between text and background or clashing colors

  4. Jumbled, unengaging, or unorganized content

  5. Clutter

Mostly Boring

Backgrounds and most colors should NOT try to grab your attention. Most of it should be steady, comfortable patterns. Subtly is hard for students eager to splash bright colors on the page. That's why we study examples of great pages. Look how chill most of their decisions are... it makes the touches of bright color really exciting.

Parallelism

Brains love patterns and it can hurt when they're broken. Patterns exist in grammar, color, lines and all sorts of other things too.

Keep Room to Digest

Less is more.

When something is considered "clean" design

Metro, Material and Flat Trends

There is a constant variation in what's trending in web design styles. Here are three of the most popular. The last, flat, is more related to colors and icons and less known as a style.

Photoshop

Photoshop works with rasterized images (as opposed to vector images). Let's discuss the difference first.

We're going to learn about three basic skills:

Layer Masks

Resizing

Our themes typically come with images perfectly formatted for the area. Instead of taking a new image and trying to crop and adjust it into the right size, I simply edit the original image in Photoshop. Once it's open, I'll drag and drop the new one on top of that.

Color Correction

We add in new adjustment layers to tweak colors. Turning down the brightness on a hero image so that it lets your CTA stand out more is a common technique.

Logo Design in Illustrator

Requirements of a Logo Package

  • PNG and JPG images

  • Wide but thin logos (banner format)

  • Square shaped logos

  • Large, medium and small file types

  • Original .ai files as well as exported versions

  • Reversed colors for dark backgrounds as well as light backgrounds

Find a Tutorial

Find a tutorial that gets close to the effect you want. Follow along and then try to tweak and customize it.

AP Computer Science

A deep dive into Java programming in preparation for the College Board's Advanced Placement test.

About the Test

  1. Multiple choice: 40 questions, 90 minutes, 50% of your score

  2. Free response: 4 questions, 90 minutes, 50% of your score

Links and Resources

Software

Great Books

Online Courses

Practice Problems

Java Tutorials and References

Serifs helped printers stamp ink onto the page
Let's start by picking colors that match our intended mood

Webpages have agendas. The author wants the reader to do something, read something, buy something. Especially on a , you need to make the key action item into an exciting call to action button.

There's an irony here

Check out about the top five mistakes most common in small companys' websites.

Is this a happy or a sad picture? There are more frowns than smiles but it still feels happy
Notice this picture has a thick border around it unlike any other?

Lots of clear space with well-organized boundaries can create a "clean" feel. .

Metro style is angular, often monochromatic

Let's learn a little about . Now we'll practice masks.

Consistency in colors, branding across all your emails and publications (attention to things like ).

If I can't hire a graphic designer for my client, I start with a template purchased from .

Check out the description from including the . For the technical folks (it'll be more useful later in the year), about the features of Java that the test uses. As of the time of this writing, there are two sections:

(install latest JDK, then install the VS Code Java Extension Pack)

(learn by doing. Loads of mini problems)

best break-down of skills)

hero
this article
Example
types of images
favicon
GraphicRiver
LogoGitHub: Where the world builds softwareGitHub
https://replit.com/teams/join/hgeffnguajivskqklikdnrmvtzpeffxb-intro-to-programming-2023replit.com
LogoThe collaborative browser based IDEreplit
Python Material, Class 1
Python Material, Class 2
LogoPython - Basic Operators
LogoCoolors - The super fast color palettes generator!Coolors.co
LogoThe 7 types of logos (and how to use them) - 99designs99designs
LogoHow to design a logo
LogoHow to Create a Cool Cut-Out Text Effect in IllustratorDesign & Illustration Envato Tuts+
College Board
description of the test
this is also a handy document
Visual Studio Code
Google Drive
Be Prepared for the AP Computer Science Exam in Java
Barron's AP Computer Science A
Bill Barnum's YouTube collection
MistaPotta's YouTube collection
https://www.albert.io/ap-computer-science-a
https://courses.edx.org/courses/CooperUnion/CS.1x/1T2015/course/
http://www.whs.wwusd.org/page/3154
https://codehs.com/info/curriculum/apjava
https://www.udemy.com/ap-computer-science-a-java-programming-essentials/
Official APCS walk-throughs and reviews
http://codingbat.com/java/AP-1
Runestone Academy
https://www.varsitytutors.com/ap_computer_science_a-practice-tests
http://www.danshuster.com/apcs/java_tests.htm
https://www.codestepbystep.com/
https://practiceit.cs.washington.edu/
https://www.khanacademy.org/computing/computer-programming
https://codesignal.com/arcade
https://www.sololearn.com/Course/Java/
https://www.codecademy.com/learn/learn-java

2: How Java Works

We will review the basics of object-oriented programming and how Java is configured. This is primarily a build-up of vocabulary. This unit moves quickly as there are limited practical applications.

Learning Targets

  • I can describe the benefits of using the JRE.

  • I can identify the three types of errors when programming.

  • I can describe the attributes of Java’s main function, including scope, instantiation, and return value.

Java is Portable

Java's strength is also its greatest weakness. The JVM allows the same Java code to run on almost any machine. It does this by hosting a virtual machine, a simulated computer system that facilitates the interpretation of your code.

Respect to Dennis Ritchie

With his partner Ken Thompson, Dennis Ritchie solved a very big program for programmers. It's hard enough for programmers to design an app. It's just crazy if you have to program an app in assembly, telling the CPU and RAM how to handle each and every little operation. Programming languages like Ritchie's C allow coders to focus more on the app and less on how it has to interact with the machine. It's like the first, really powerful book of spells made for magicians.

Just in Time

When you install an app on your computer, the JIT will interpret the developer's code and set it up to run on the given machine. The install process takes longer and it might not be compatible with every machine, but then the app is ready to run very quickly. Java doesn't play like that. Instead, it interprets the code in real-time while running through a virtual machine. So while it can run pretty much everywhere, there's a bottleneck in how fast it can perform.

Extra Information

Editing Code

Three types of errors

  1. Syntax or Compile-time: You can't compile this code. Something is way off and Java won't touch your mess.

  2. Runtime or crash: Something breaks while it's running as if you asked the computer to divide a number by zero.

  3. Logic: Everything runs okay. Nothing crashes. However, the answer you get is just wrong. If your app says 4+4 is 10, you've got a logic error.

Java's Code Structure

In Java, all code must be written inside methods, and all methods belong to a class. This means that every Java program is essentially a collection of classes, each containing methods that define the behavior of your program.

  • Classes must be defined inside a file that shares the exact same name as the class. For example, if your class is called MyProgram, then the file must be named MyProgram.java.

  • The entry point of every Java program is the main method, which tells Java where to begin executing your code.

Exceptions

While every class usually matches its file name, there are a few exceptions:

  • You can define inner classes within another class.

  • Files may contain more than one class, but only one can be public and match the file name.

Java's Main Method

Every Java app starts the same way, from a static method that returns nothing. Let's introduce these concepts now. Many of these ideas will seem strange, but they'll make more sense as you build up your background knowledge. You'll come back to this section later on and smile. But for right now, let's take a plunge into the deep end of the pool. We'll hurry right back to the basics but let's take a peek at how all Java apps start. public static void main(String[] args){} <=[ all Java apps start from that method! ]

Scope

Who can access this method or this variable? The main method must always be public because it's being triggered from outside the class.

Instantiation

Does this method belong to an instance of the class? What's the difference between an instance and a static class? Imagine we're building a game. We've got one file or class that describes a player and another that has helpful functions like drawing a random number. Every person that plays the game gets their own instance of the player class. It tracks each player's health and abilities in the computer's memory. But the helper class can be static, just one master copy--no instance needed.

Return Type

As the method closes, does it return anything? If so, what type of data is returned? The main method must always return void because it's the point of origin--there's nothing to return data to.

3: Bootstrap Template

Use a Bootstrap template to produce a stunning webpage.

Learning Targets

  • I can build a hero with a call to action.

  • I can implement a color palette via CSS.

  • I can build a responsive Bootstrap website.

  • I can implement Bootstrap classes and components into a website.

What is Bootstrap?

What is responsive?

Responsive design isn't just about websites looking good on different screens; it's about delivering an optimal user experience on any device. Imagine navigating a complex website on a tiny phone instead of a spacious desktop – the frustration is real! Responsive design solves this by adapting the website's layout, content, and functionality to various screen sizes, ensuring a seamless user journey.

Bootstrap's Grid System:

Bootstrap, a popular framework, makes responsive design accessible. Based on 12 columns, its grid system provides a flexible layout structure. In your example, <div class="col-md-6"> and <div class="col-lg-6"> define elements that occupy 6 columns on medium and large screens, respectively.

Breakpoints and Device Adaptation:

The magic happens with breakpoints and specific screen widths where the layout adjusts. Bootstrap uses predefined breakpoints for @media queries, essentially saying, "When the screen size reaches X, apply these styles." Your task with the inspector window is to find these breakpoints! Look for @media rules defining styles for lg, md, and sm (small) screens. Notice how Bootstrap adjusts the number of columns these classes occupy at each breakpoint.

Exploring Device-Specific Adjustments:

While Bootstrap offers a solid foundation, sometimes device-specific tweaks are necessary. For example, on smaller screens, you might:

  • Collapse content sections by default and use buttons or icons to reveal them.

  • Increase font sizes for better readability.

  • Simplify navigation menus or switch to hamburger menus for better accessibility.

  • Optimize images for faster loading times.

Beyond Bootstrap:

Remember, Bootstrap is a tool, not a silver bullet. You might need to go beyond its base styles as your projects evolve. This is where understanding CSS media queries and flexbox becomes crucial for more granular control over responsive layouts.

Beyond Screen Size:

While the screen size is the primary factor, a responsive design also considers other aspects:

  • Device orientation: Portrait and landscape modes on phones and tablets require different layouts.

  • Resolution: High-resolution displays might necessitate adjustments for image quality and text sizes.

  • Network speed: Consider loading optimizations for users with slower connections.

The Importance of Testing:

Responsive design isn't a one-and-done task. Rigorous testing on various devices and screen sizes is crucial. Use browser emulators and real devices to identify and fix any layout issues and ensure a consistent user experience across platforms.

Optional Button Drill

Bootstrap 2 Project

Replit: Our Cloud-Based IDE

  • What is Replit? Replit is an online platform that acts as an Integrated Development Environment (IDE). Think of it as a workspace in your browser where you can write code, run your website, and collaborate with others in real time.

  • How does it work in class? Instead of downloading templates, each student will have a pre-provisioned copy of the chosen StartBootstrap template ready to use in Replit. This eliminates the need for individual downloads and setups.

  • Pros of using Replit:

    • Convenience: No setup required, access your project from any device with internet.

    • Collaboration: Work with classmates on your website in real time.

    • Pre-configured environment: Everything you need to start coding is already set up.

    • Cloud storage: No need to worry about losing your work; it's automatically saved online.

  • Cons of using Replit:

    • Limited customization: Replit may have limitations compared to desktop IDEs like VS Code in terms of customization and plugin options.

    • Offline access: You need an internet connection to access your project in Replit.

,VS Code with Downloaded Template:

  • What is VS Code? VS Code is a popular, downloadable code editor for your computer. It provides powerful features like syntax highlighting, code completion, and debugging tools.

  • Using VS Code: You can download the StartBootstrap template yourself and open it in VS Code for editing.

  • Pros of using VS Code:

    • More customization: VS Code offers extensive customization options with plugins and themes, catering to your preferred development style.

    • Offline access: Work on your website even without an internet connection.

    • Advanced features: Powerful debugging tools and code analysis features for more in-depth development.

  • Cons of using VS Code:

    • Setup required: You must download and install VS Code and the template.

    • No real-time collaboration: Working with classmates requires additional tools or sharing downloaded files.

    • Storage management: You're responsible for saving and backing up your project files.

The Choice is Yours!

Both options have their merits, and the best choice depends on your personal preferences and learning style.

  • For beginners: Replit's easy access and collaboration features might be ideal.

  • For experienced programmers: VS Code's customization and offline capabilities could be more appealing.

Download a StartBootstrap Template:

  • Choose a template that suits your project's needs.

  • Click on the template's preview page and find the download button.

  • Select the option to download the zipped file.

  • Save the downloaded file to a convenient location on your computer.

Open the Template in VS Code:

  • Open VS Code.

  • Go to File > Open Folder.

  • Select the unzipped folder containing the downloaded template.

  • Click Open. This will open the entire template structure within VS Code.

Create a Custom CSS File:

  • Within VS Code:

    • Go to File > New File.

    • Name the file custom.css.

    • Save the file in the appropriate location within your project folder (usually the root directory).

Open a Preview of the Site:

  • In VS Code:

    • Right-click on the index.html file and select Open with > Live Server.

  • This will launch a local preview of the website in your default browser.

Make Changes and Refresh:

  • Edit the HTML and CSS files directly within VS Code to customize the website.

  • Update your custom.css file with desired styles.

  • Save your changes.

  • The Live Server preview will automatically refresh, reflecting your latest edits.

Continue Building:

  • Use the template's structure and provided classes as a starting point.

  • Add your own content and modify the HTML as needed.

  • Refer to the template's documentation for available components and their usage.

  • Use your custom.css file to personalize the design further.

  • Keep making changes, saving, and refreshing to see your progress unfold.

Additional Tips:

  • Regularly save your project folder to Google Drive for backup and collaboration.

  • Explore Bootstrap's extensive documentation and online resources to learn more about its features and customization options.

  • Remember, practice makes perfect! Start with this guide, experiment, and have fun creating your unique website!

In the same folder, create a new file: custom.css. Next we'll need to connect the css file to the folder html file.

Video Walkthroughs

1: Logic & Instances

We start with the fundamentals of logic gates and logical expressions using De Morgan's Law. By looking at transistors, the most granular aspect of CS, we can steadily add layers of abstraction.

Learning Targets

  • I can explain the connection between electricity and logic.

  • I can interpret logical statements with all common operators, (i.e. and, or, nor, xor, if, iff).

  • I can simplify a logical expression according to De Morgan's Laws.

  • I can convert numbers from decimal to binary and to hexadecimal.

  • I can describe the purpose of instantiation.

  • I can decide when to instantiate an object or when to use a static class.

Logic Gates

I'm absolutely fascinated in how people build logic, systems that react to conditions, into physical devices.

We start with two tricks with circuits: 1) and && 2) or ||

With tiny transistors and these building blocks, we can assemble our modern technological era. Let's just take a peak:

De Morgan's Law

You'll need to know how to distribute the ! when simplifying logical expressions. This will make more sense as we get into more practical examples.

A "promise" or an "if" within logic is something like:

Practicing Boolean Logic

Let's simplify these statements. Reduce them down to just true or false

  • true != true || (true || false)

  • false && true || true && false || true && false || true

  • !(true && false)

  • !(5 > 5)

  • !(5 <= 5)

  • 5 == 5 && true

Binary

Can you see how false and true could also be considered to be 0 and 1? All the sudden, we can make these logic gates, these electrical transistors, store binary data. Computers are pretty cool.

Instantiation

This is an important concept that's most easily introduced when we're not thinking about the code. If you have a recipe to make a cake, that's similar to a class definition. Each time you bake a cake, you're creating a new instance of that cake.

Another example of instance VS static classes

This is by no means a perfect example as things are more complicated... but let's consider Fortnite for a moment. There's just one map. Programmers might refer to this map by its class. If I wanted to call a tornado, at Coney Crossroads, I might type something like, Map.createTornado("Coney Crossroads");

Now let's imagine a programmer wanted to provide a player with some individual powers. I wouldn't want to be so broad as to call the whole Player class as each player is an individual. I'd want to specify which individual player, something like lancerGuy99.upgradeWeapon();

Intro to Programming

A review of the basics of computing, programming and robotics. We'll build simple Python apps and play with Raspberry Pi's.

We program little turtles to dance on the screen then we play with real robot cars. Learning how to program is an awesome time. I love my job.

Acceptable Layer of Abstraction

For the people that say "I'm not good with computers"

Computer Science may be intimidating but like any other field of study, you don't have to learn it all at once. We're skipping so much in this class. Don't worry about it. You'll have enough tools to figure out if you want to invest the time to learn the deeper, more challenging (and more powerful) stuff.

In any line of questioning, you can keep asking "Why?" Eventually, you just stop when you think you've learned enough. For example, you can legitimately claim you know how a car works (you put gas in, turn a key, etc) even if you're hopeless as a mechanic. You've got a different acceptable layer of abstraction than a mechanic claiming too that she knows how a car works. The inner-workings of a car engine may just be an abstract idea that you only broadly understand (something about spark plugs). The point: You can start learning really cool tech without having to shift your acceptable layer of abstraction too much. It'll be fun.

You need to know about the pieces, even if you don't know exactly how they work.

In order to understand basic computer programming, you will need to understand some of the components in your computer. If you understand the basic shape of the environment, the behavior of programming languages will have better context. You won't need to understand exactly how a processor works, but you'll need to know roughly how it fits into the picture so you can solve some common problems.

Links and Resources

Software

Free Code Training

  • Solid: https://sololearn.com

2: Websites?

What's happening under the surface of a web page?

Expectations

Learning Targets

  • I can describe how web pages are displayed on my browser using HTTP and HTML.

  • I can create a basic HTML page.

Assignments

  • You will construct an HTML page from scratch in a guided class activity.

  • You will complete HTML and CSS courses on codecademy.com

World Wide Web

Tim Berners-Lee

The "Internet" we think of is primarily the contents of our web browser. Trying to find information by tediously scanning film after film was not fun. People like Tim Berners-Lee wanted to link text together. So touching one word might connect you to relevant information without having to manually search for hours.

HTTP sends HTML

HyperText Transfer Protocol is a set of rules to pass information (like the HTML layout of a web page) over a network. HTML is a markup language. It describes the structure and content of a page. So when you type in an web address like google.com into your browser, you're sending a GET request to the Google server. It responds with an HTML package that your browser renders into a familiar display.

Structure of HTML

Tags and Elements

A tag looks like this: <tag> </tag> The stuff that's between the opening <tag> and the closing </tag> is what's inside that element. The first and most important element in a web page is a hypertext link. If I wanted to make a link that went to Google.com, it would look like this: <a href="google.com">this is my link</a>

The term tag describes the structure of the <opening> and </closing>. The element is what type of object is being built by the tag, (an a is a hyperlink). The contents of an element is whatever is between the open and closing tag of an element. The property="value" pair that goes inside of an HTML tag is called an attribute.

Page Structure

Every web page has to have a <!DOCTYPE html> at the very start to tell your browser that yes, this block of text is HTML and it should render it into a display. The <html> element does something very similar. Every page you've ever seen online has been the contents of an HTML tag.

BlankPage
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>

<h1>My First Heading</h1>
<p>My first paragraph.</p>

</body>
</html>

The <head> element isn't seen by the user. The contents of the head allow you to connect other resources to the page, such as fonts or CSS.

CSS is HTML's Sidekick

CSS has its own style rules. But you drop it into an HTML head like any other HTML, <style> css goes here </style>. You can put the CSS in the HTML file, but the better way is to keep your CSS in a separate file. In that case, you use a <link> element instead to connect the .css file.

Practice

Additional Training

9: Review

Acing your AP test is about testing for bugs in your understanding, studying the fix, then practicing the solution.

Review the concepts:

Get your speed up:

Watch Videos:

Going Pro:

We use the JDK so the JVM and its JIT will show us our code in the final result we call the JRE.

If you'd like to learn more about the history of Computer Science, I to be very charming.

Who made the Java programming language? When and why?.

The JDK is a type of . We'll use tools to build apps like an and an . We're going to have lots of bugs or errors in our code. They will take three different forms...

Bootstrap has tons of helpful styles and tools built in, but most importantly, it makes your page responsive

. Twitter publishes a front-end framework that has significantly impacted web designers. It's great, and you'll spend a lot of time with .

Here's another fun exercise. Let's open up again, set up Bootstrap, and customize a button. Check out some simple examples from the ever-helpful W3schools:

Look at some of the .

Visit StartBootstrap () and browse their collection of free templates.

De Morgan's Laws essentially describes the distributive property of "not" or !
It's only false if the condition was met (you studied) but you did not get the promised result.
iff means they both have to be the same for <-> to be true
One cake recipe produced many objects
A whiteboard has functions but is not replicable. It's a static resource
One map and globally accessible resources. An potential example of a static class
Each person controls an instance of the Player class. Each copy of stores the user's skin, current health, etc.

Best intro: (Python, git, Command Line)

Fun:

Hard, smart:

Nobel Prize winner Tim Berners-Lee

If one person had to be named as the creator of the Internet, it might be in 1989. More specifically, he created the World Wide Web while working at . It was a way of transferring information over the TCP/IP network talked about in last chapter.

No more

Microfiche was text printed on tiny films. Searching through many films was a pain

The most important part of a website remains the .

HTML is Batman and CSS is Robin. CSS doesn't ever work alone--it's there to support HTML
It can often be very frustrating to find the right CSS rule to fix your display

found this video
Check it out
SDK
IDE
interpreter
Read about it
its documentation
https://codepen.io/
https://www.w3schools.com/csS/css3_buttons.asp
coolest CSS buttons
https://startbootstrap.com/
Visual Studio Code
Google Drive File Stream
https://www.codecademy.com/
https://codecombat.com/
https://app.codesignal.com/
Tim Berners-Lee
CERN
Microfiche
hyperlink
Crush all the Codingbat Problems
Go over the AP Classroom problems
Fill in any gaps in your skills
https://www.varsitytutors.com/ap_computer_science_a-practice-tests
http://www.danshuster.com/apcs/java_tests.htm
https://www.youtube.com/playlist?list=PL-ZKvhIgD8x0Dgl2_rnNAv1lhJoRsIfLg
https://www.youtube.com/playlist?list=PL_JS5ztwk2L9EhSQysP2tiQ_k5g_fAaji

5: Objects & References

We will look more closely at the object-oriented programming and the implications of instantiated objects.

Learning Targets

  • I can describe what it means to be an object-oriented programmer.

  • I can describe the difference between values and references.

  • I can build unit tests to check every method in my class definition.

Class Vocab

Object-Oriented Programming

Why don't we list all of our code in one long file? How do we start to organize big projects? We start with objects. Already we've been using a class with a main method as its starting point. All of our methods have been static. What if we wanted to make a game with a lot of monsters? We can define our own Monster class and create as many instances of that object as we need in the game. We can't use static methods anymore as a result.

Let's try out a simple game in class using while-true loop and a Monster.

Encapsulation

Keep your data private, accessible only to methods that allow for more careful controls.

Primitives and Refs

import java.util.ArrayList;

public class Practice {

	public static void main(String[] args) {
		
		// create a primitive
		int myPrimitive = 5;
		// pass it by value to a method that adds one to the item.

		addOne(myPrimitive);
		// print the unchanged value of the primitive
		System.out.println("Primitive: " + myPrimitive);
		
		// instantiate a list and store the reference to it in myRef
		ArrayList<Integer> myRef = new ArrayList<>();
		// add the value 5 to a new Integer 
		myRef.add(5);
		// pass it by reference to a method that adds one to the first element in the list
		addOne(myRef);
		// print what's now in the first spot of the object that was passed by reference
		System.out.println("Reference: " + myRef.get(0));
		
	} // closes main
	
	public static void addOne(ArrayList x) {
		// get the current value of the first item in the list, convert to int
		int current = (int)x.get(0);
		// set the first item's value to one more than its current
		x.set(0, ++current);
	}
	
	public static void addOne(int x) {
		++x;
	}

} // closes the class
	

Intro to ArrayLists

ArrayLists are introduced in this section because they're objects themselves. They illustrate some of the differences we see when working with objects. Instead of arrays when we can access an element just by printing someCollection[x], we now need to use someOtherCollection.get(x). Let's get into these differences.

Different Kind of Loop

Because ArrayLists are only accessible through methods, you can use the same type of access[index] you can with an array. Here's what a simple traversal looks like with a good ol' array:

int[] myArray = {5, 10, 15, 20};
for(int x = 0; x < myArray.length; x++){
    System.out.println(myArray[x]);
}

Notice how I used length as a property not as an accessor method() and I accessed an element from the collection using [brackets]. Now let's take a look at an ArrayList:

List myList = new ArrayList<Integer>(); 
myList.add(5);  // I could loop and add all these
myList.add(10); 
myList.add(15);  
myList.add(20);  
for(int x = 0; x < myList.size(); x++){
    System.out.println(myList.get(x));
}

There's a couple important things happening above you should look closely at:

  • Notice how I declared a List and then turned it into an ArrayList? It wouldn't have worked if I tried to do new List because a List is abstract. It's like mammal. You can tell the computer that you'd like to make a new mammal named x and it should run the new Dog() constructor. That's a polymorphic declaration. Use a general ancestor as a type and then be more specific during the constructor.

  • If you look inside the ArrayList class programmed inside our Java library, you'll notice it has an array at its core. It's a wrapper for an array. So there is a .length property that's relevant to its internal, private programming. Every time you .add(something) to an ArrayList it destroys its old array and copies all the content to a new, longer array. So .length is serious business. Since that's occupied, we use the .size() accessor method to retrieve the length of an ArrayList.

SecureList: An Example

What's the point of creating our own objects? How does an ArrayList differ from an array in practical implementation? Let's go through an example project to help iIllustrate these concepts.

What is a SecureList?

SecureLists are made up. They're a silly object that provides an extra layer of "security" by storing your list of 12 names in two different objects, an array and an ArrayList. Does that actually provide additional security? No, not really. But let's pretend it does so you have an opportunity to work with an array and an ArrayList simultaneously.

Let's set up your project with the following files:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

import java.util.Scanner;

public class App {
    
    // from a static method, we'll create instances of our made-up object
    public static void main(String[] args) throws Exception {
      
        System.out.println("Let's build a list of names to test.");
        Scanner s = new Scanner(System.in);
        
        // our example container
        String[] testList = new String[12];
        
        // build an example list to work with
        System.out.print("Would you like to enter names? (y/n): ");
        if(s.nextLine().equals("y")){
            // populate the array with names from user
            for(int x = 0; x < 12; x++){
                System.out.print("\nInsert name at index " + x + ": ");
                testList[x] = s.nextLine();
                System.out.println();
            }  
        } else {
            // populate the array with just numbers
            for(int x = 0; x < 12; x++){
                testList[x] = "Student #" + x;
            }  
        }        
       
        System.out.println("\n----- SecureList Unit Tests ------\n");
        
        // test the constructor
        SecureList test1 = new SecureList(testList);
        
        // test title mutator and accessor
        System.out.println("\nTITLE TEST: \n");
        test1.title("Demo"); // mutator 
        System.out.println(test1.title());  // accessor

        // implicitly call the .toString() method
        System.out.println("\nPRINT TEST: \n");
        System.out.println(test1);
        
        // draw a random name from the list
        System.out.println("\nGET RANDOM: \n");
        System.out.println(test1.getRandom());
        
        // check that each element in both collections match
        System.out.println("\nIS SECURE: \n");
        System.out.println(test1.isSecure()); // should print "true"
        
        // get the first name in the list
        System.out.println("\nGET STUDENT 0: \n");
        System.out.println(test1.getName(0));
        
        // get the first name in the list using the seat number not the index
        System.out.println("\nGET SEAT 1: \n");
        System.out.println(test1.getStudentBySeat(1));
        
        // randomize the order of the names
        System.out.println("\nSHUFFLE: \n");
        test1.shuffle();
        System.out.println(test1);
        
    }
}
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

import java.util.ArrayList;

/**
 * Doubles the protection of your data by storing your 12 names in both an array
 * and an ArrayList
 */
public class SecureList {
    
    // ENCAPSULATED INSTANCE VARIABLES
    // a var for the title String
    
    // uninitialized String Array
     
    // uninstantiated ArrayList typecast to String
    
    
    // -----------
    // CONSTRUCTORS
    // -----------
        
    /**
     * This is the basic constructor that initializes all the instance variables
     */
    public SecureList(){
        // create a blank title
        title = "";
        // create a blank array of Strings
        nameArray = new String[12];
        // instantiate an ArrayList and then loop and add 12 blank Strings
        nameList = new ArrayList<String>();        
        for(int i = 0; i < 12; i++) nameList.add("");
    }
    
    /**
     * Extracts names from an ArrayList to store in both class containers
     * @param nameList : starting names
     */
    public SecureList(ArrayList<String> nameList){
        // call the first constructor to setup the blank stuff
        this();
        
        // copy the data from the given list
        
    }
    
    /**
     * Extracts names from an array to store in both class containers
     * @param nameArray : starting names
     */
    public SecureList(String[] nameArray){
        // call the first constructor to setup the blank stuff
        this();
        
        // copy the data from the given array
    }
    
    // -----------
    // ACCESSORS
    // -----------
    
    /**
     * Accessor method for the title instance variable
     * @return this.title
     */
    public String title(){
    
    }
    
    /**
     * After checking that the names between the two strings
     * @param n : the zero-indexed location of the name
     * @return
     */
    public String getName(int n){
        // use the isSecure method to check n
        if(!isSecure(n)){
            System.out.println("NOT SECURE");
            return null;
        }
        
        // return the name in the index location of n
        
    }
    
    /**
     * Wrapper for the getName method that is NOT zero-indexed
     * @param s: Seat location
     * @return
     */
    public String getStudentBySeat(int s){
        
    }
    
    // -----------
    // MUTATORS
    // -----------
    
    /**
     * Modify this instance's title property
     * @param title : new label for this secure list object
     */
    public void title(String title){
    
    }
    
    /**
     * Change the name of both collections at a given index location
     * @param n : index location to target
     * @param name : new name value to set
     */
    public void changeName(int n, String name){
        
    }
    
    // -----------
    // UTILITIES
    // -----------
    
    /**
     * Checks if the given index location is a blank "" string
     * @param n : index location to check
     * @return : true if the index location had a length of zero
     */
    public boolean isEmpty(int n){
        
    }
    
    /**
     * Returns the comparision between the two Strings in the container at position n
     * @param n : the zero-indexed location in the collection to check
     * @return true if the two Strings .equal
     */
    public boolean isSecure(int n){
        
    }
    
    /**
     * Traverses the length of the collection and checks in location is secure.
     * If any is found insecure, it returns false
     * @return list integrity 
     */
    public boolean isSecure(){
        // loop
            // if insecure at that postion, return false
​
        // if you make it through the loop safely, return true
    }
    
    /**
     * Draws a random index location and returns the name at that location
     * @return : the String value at a random index location
     */
    public String getRandom(){
        // generate a random number from 0 up until but not including the length
        
        // return the call to the getName method
    }
    
    /**
     * Randomizes the location of all the Strings using the Selection Shuffle
     * algorithm 
     */
    public void shuffle(){
        
    }
    
    /**
     * Traverses name collection, printing the seat location followed
     * by the name
     */
    @Override
    public String toString(){
        
    }
    
}

Data Science

I wanted to put our own spin on the Data lab from CollegeBoard for this project. Rather than just following the standard lab, we're going to analyze real-world video game sales data that will give you hands-on experience with classes, interfaces, and data processing in Java.

This project will give you practical experience with:

  • Creating and using custom classes

  • Working with interfaces

  • Processing CSV data files

  • Implementing search and analysis algorithms

  • Visualizing data patterns

Activity 1: Getting Started

Our project requires two main Java classes:

  • GameDataRow - Represents a single game record from our dataset

  • GameDataManager - Handles loading and analyzing collections of game data

Let's start by looking at how to set up the GameDataRow class:

Understanding the Class Header and Interfaces

The class header public class GameDataRow implements Comparable<GameDataRow> has several important components:

  1. public - This access modifier makes the class accessible from outside its package.

  2. class GameDataRow - Defines a new class named GameDataRow.

  3. implements Comparable<GameDataRow> - Indicates that this class implements the Comparable interface.

The Comparable Interface

The Comparable interface is part of the Java Collections Framework and enables objects of a class to be compared to each other. When a class implements Comparable, it must provide an implementation of the compareTo() method:

The compareTo() method must return:

  • A negative value if this object should be ordered before the other object

  • Zero if both objects are equal

  • A positive value if this object should be ordered after the other object

In our implementation, we're sorting games by global sales in descending order (highest sales first).

Other Common Interfaces in Java

While we're only using Comparable in this project, here are other common interfaces you might encounter:

  • Serializable - Marks a class as capable of being serialized (converted to a byte stream).

  • Runnable - Used for classes whose instances will be executed by a thread.

  • ActionListener - Used for handling action events, commonly in GUI applications.

  • Iterable - Allows an object to be the target of the "for-each loop" statement.

Properties and Encapsulation

Now, let's determine what properties our GameDataRow class needs. Our CSV file contains 17 columns of data about each game, and we want to represent each data point as instance variables in our class.

Looking at the structure of our CSV file, we need to create properties that match each column:

Encapsulation Review

Remember that encapsulation is one of the four fundamental OOP concepts, along with inheritance, polymorphism, and abstraction. Encapsulation means bundling data and methods that operate on that data within a single unit (the class) and restricting direct access to some of the object's components.

Notice all our instance variables are marked as private. This is a key principle of encapsulation:

  1. Private instance variables: By making our instance variables private, we prevent outside classes from directly accessing or modifying them.

  2. Public accessor methods: We provide controlled access through getter methods (and sometimes setter methods).

  3. Data validation: Through these methods, we can validate any changes to ensure they meet our requirements.

Good encapsulation ensures that the internal representation of an object can't be seen from outside the object's definition, which creates a "black box" effect.

Constructors

We need constructors to initialize our GameDataRow objects. A well-designed class should have multiple constructors to provide flexibility in object creation:

Notice I've included three constructors:

  1. A primary constructor with all fields

  2. A simplified constructor with only essential fields

  3. A copy constructor to create a deep copy of an existing object

Accessor Methods (Getters)

Now we need accessor methods (getters) for all our instance variables. This is a perfect opportunity to use AI responsibly. Rather than typing out all these repetitive methods, you can ask Claude or an IDE's chatbot to generate them for you.

For example, you could say:

Please generate all the accessor methods for the GameDataRow class based on the instance variables.

This isn't plagiarism or cutting corners - it's using a tool to handle the tedious, repetitive aspects of coding so you can focus on the more challenging and creative aspects like designing algorithms and implementing the business logic.

Here's a snippet showing what a few of these accessor methods would look like:

Test-Driven Development

Let's talk about Test-Driven Development (TDD) - a software development approach where you write tests before writing the actual implementation code. This practice has been widely adopted by professional developers because it leads to more reliable, maintainable code.

In TDD, the process follows three simple steps, often called "Red-Green-Refactor":

  1. Write a test that fails (Red)

  2. Write the minimal code to make the test pass (Green)

  3. Improve the code without changing its behavior (Refactor)

For our project, I've prepared a complete main method that serves as a test suite. It will systematically test all the required functionality of your GameDataRow class and tell you exactly what's missing or not working correctly.

Adding GameDataManager and Testing

Now that your GameDataRow class is complete, let's work with collections of games:

Activity 2: Building Methods

Now that we have our class structure and properties defined, it's time to add meaningful functionality to our GameDataRow class. To complete this class, you'll need to implement several methods that analyze game data in different ways.

I'm providing you with a few utility methods that handle some of the trickier aspects of parsing data from the CSV file, such as handling non-numeric user scores. Let's first look at these provided methods:

I'm giving you these methods because:

  1. The hasUserReviews() and getUserScoreNumeric() methods handle data conversion and error checking that might be challenging

  2. The toString() method is lengthy but straightforward, and implementing it wouldn't teach you much

Now, let's focus on the methods you need to implement:

Method 1: getAverageScore()

Return Type: float

This method calculates the average between critic and user scores. However, there's a challenge: critic scores are on a scale of 0-100, while user scores are on a scale of 0-10.

Requirements:

  • Return a float representing the normalized average score on a scale of 0-10

  • Normalize the critic score to a 0-10 scale by dividing by 10

  • Handle cases where one or both scores are missing/invalid

  • Return the appropriate average or individual score based on what's available

  • Return 0.0f if no scores are available

Key Considerations:

  • What constitutes an "available" score? (Hint: check for positive values)

  • How do you handle the case where only one score type is available?

Hints:

You can paste this code into your method as a starting guide:

Method 2: getSalesPercentages()

Return Type: float[]

This method calculates what percentage of the global sales comes from each region (North America, Europe, Japan, and Other).

Requirements:

  • Return an array of float values representing percentages for each region

  • The array should have 4 elements, one for each region

  • Use the defined constants (NA_REGION, EU_REGION, etc.) for array indices

  • Handle the case where globalSales is zero to avoid division by zero

Key Considerations:

  • The formula for calculating percentage is: (regional sales / global sales) * 100

  • If globalSales is zero, return an array of zeros to avoid division by zero

Method 3: hasSalesData()

Return Type: boolean

This method determines whether the game has any sales data available.

Requirements:

  • Return true if any sales data (regional or global) is available

  • Return false if all sales fields are zero

Key Considerations:

  • Check all sales fields (naSales, euSales, jpSales, otherSales, globalSales)

  • Use logical OR operators to efficiently check multiple conditions

Method 4: hasCriticReviews()

Return Type: boolean

This method determines whether the game has critic review data available.

Requirements:

  • Return true if the game has both a critic score and a count of critics

  • Return false if either piece of information is missing or zero

Key Considerations:

  • Both criticScore and criticCount should be positive values

Method 5: getDominantRegion()

Return Type: String

This method determines which region has the highest sales for this game.

Requirements:

  • Compare sales across all regions and find the highest

  • Return a string representing that region ("North America", "Europe", "Japan", or "Other")

  • Handle ties by choosing the first region encountered with the maximum value

Key Considerations:

  • You'll need to track the maximum sales value and the corresponding region

  • You can use a switch statement to convert from region index to region name (see example below)

Method 6: getRegionalSales()

Return Type: float

This method returns the sales figures for a specific region.

Requirements:

  • Accept an int parameter representing the region (use the class constants)

  • Return the sales figure (as a float) for the specified region

  • Handle all four possible regions: NA_REGION, EU_REGION, JP_REGION, OTHER_REGION

Key Considerations:

  • Use a switch statement to select the appropriate sales figure based on the region parameter

Switch Statement Example

A switch statement allows you to select one of many code blocks to be executed. Here's how you might implement the getRegionalSales method using a switch statement:

The switch statement evaluates the regionIndex parameter and executes the code block that matches the case. The default case handles any values that don't match any specified cases.

Method 7: Implementation of Comparable

Return Type: int

You need to implement the compareTo method from the Comparable interface.

Requirements:

  • Override the compareTo method to compare games based on global sales

  • Higher sales should sort before lower sales (descending order)

  • Return negative value if this game has higher sales than the other game

  • Return positive value if this game has lower sales than the other game

  • Return zero if both games have equal sales

Key Considerations:

  • Remember that returning a negative value means "this" comes before "other" in the sorted order

Activity 3: Results

Let's add one final method to our GameDataRow class before moving on to working with collections of game data:

Understanding Static Variables and Methods

This method introduces an important concept in Java: static members. Unlike instance variables and methods that belong to specific objects, static members belong to the class itself.

Here's what you need to know:

  • Static variables (like our gamesAnalyzed counter) are shared across all instances of a class. There's only one copy in memory, regardless of how many objects you create.

  • Static methods operate at the class level rather than the instance level. They can be called using the class name without creating an object: GameDataRow.getGamesAnalyzed().

  • Cannot use this in static context: Since static methods don't operate on a specific instance, you cannot use the this keyword inside them. There's no "current object" to reference! If you try to use this in a static method, you'll get a compiler error.

  • Access limitations: Static methods can only directly access other static members (variables or methods). They cannot directly access instance variables or methods without referencing a specific object.

In our case, we're using the static variable gamesAnalyzed to track how many game objects have been created throughout our program's execution. Each constructor increments this counter, and our static method lets us retrieve the current count.

Creating Your Own Analysis

Now it's time to put your skills to work! Modify the GameDataManager.java file to add your own custom analysis of the video game data.

Add at least one new method to the GameDataManager class that performs an interesting analysis. Here are some ideas:

  1. Year Analysis: Which year had the highest average game quality? Most releases?

  2. Developer Success Rate: For developers with multiple games, which ones have the highest average scores?

  3. Cross-Platform Analysis: Which games appeared on the most platforms? Do multi-platform games sell better?

  4. Sales vs. Ratings Correlation: Do higher-rated games generally sell better? Is there a difference between critic and user ratings?

  5. Genre Evolution: How have the popularity of different genres changed over time?

Once you've added your analysis method(s), modify the main method to call your new method and display the results.

Example Custom Analysis Method

Here's what your custom analysis might look like (don't just copy this - create your own!):

In the main method, you would add a call to your new analysis:

Requirements for Your Custom Analysis

Your analysis should:

  • Process data from multiple games

  • Use loops and conditionals appropriately

  • Output meaningful results

  • Include comments explaining your approach

  • Handle edge cases (like missing data)

Activity 4: Recursion

In this final activity, you'll explore recursion - a powerful programming technique where a method calls itself to solve a problem by breaking it down into smaller instances of the same problem.

Understanding Recursion

Recursion is a fundamental concept in computer science that provides elegant solutions to certain types of problems. A recursive method has two essential components:

  1. Base case(s): The simplest scenario(s) that can be solved directly without further recursion

  2. Recursive case(s): Where the method calls itself with a simpler version of the problem

Let's examine a simple example - calculating the factorial of a number:

When calculating factorial(5):

  1. The method first checks if n equals 0 or 1 (our base case) - it doesn't, so we move to the recursive case

  2. It returns 5 * factorial(4)

  3. Now it calculates factorial(4), which is 4 * factorial(3)

  4. This continues until we reach factorial(1), which returns 1 (base case)

  5. Then the recursion "unwinds": 1 * 2 * 3 * 4 * 5 = 120

Why Use Recursion?

Recursion offers several advantages:

  1. Elegance: Recursive solutions can be concise and elegant for problems that would be complex to solve iteratively

  2. Divide and conquer: Recursion naturally implements divide-and-conquer strategies, breaking down large data sets into smaller pieces

  3. Tree traversal: For hierarchical data structures like trees, recursion provides a natural approach

  4. Problem decomposition: Complex problems become simpler when broken into smaller, similar sub-problems

Implementing Recursion in Game Data Analysis

Looking at our GameDataManager class, several methods could benefit from a recursive approach. For example, finding games within a specific criteria could be implemented using a binary search algorithm rather than the current linear search.

Here's an example of how we could improve the findGamesByTitle method using a recursive binary search (assuming the games list is sorted by title):

The recursive binary search has a time complexity of O(log n), which is much more efficient than the O(n) time complexity of linear search, especially with large datasets.

Another example would be implementing a recursive merge sort:

Your Task

  1. Choose one method from your GameDataRow or GameDataManager class that could benefit from a recursive approach

  2. Reimplement it using recursion

  3. Test your implementation and compare it to the original approach

  4. Document your findings: Was the recursive approach more elegant? More efficient? What challenges did you face?

Alternatively, you can implement a new recursive method that performs a complex analysis that would be difficult to do iteratively. Here are some ideas:

  • Find the most profitable franchise (games with similar names) recursively

  • Implement a recursive algorithm to categorize games into hierarchical genres (e.g., "RPG > Action RPG")

  • Create a recursive method to find "hidden gems" - games with high ratings but low sales

Example: Recursive Method for Maximum Critic Score

Here's an example of how you might implement a recursive method to find the game with the highest critic score within a list of games:

This method uses a divide-and-conquer approach, recursively finding the maximum in each half of the list and then comparing the results. While this specific example might not be more efficient than a simple loop, it demonstrates the recursive pattern that can be applied to more complex problems.

Remember, not all problems are best solved with recursion. Some considerations:

  • Recursion can lead to stack overflow errors with very large inputs

  • Recursive solutions sometimes have higher memory usage

  • Some problems have simpler iterative solutions

3: Hello Flask

Expectations

Learning Targets

  • I can create and view a blank Flask app.

Before we get into the structure and mechanics of our code, let’s build the most basic of Flask apps. It’ll help set some context as we then start to learn particular skills. It’s important that you start from scratch as it builds confidence knowing you can start from the ground-up.

Hello Flask

Let's look at the most simple possible Flask app.

Alternative

In case Repl.it isn't cooperating with your browser, here's a simple view of a basic "Hello Flask" app.

Challenge

Variables from a route

If I go to /hello/george, can you make the screen say, "Hello, George?" How do we pull a variable from the URL on that GET request?

Link to another page

Build another route and switch between two pages.

Basic templating

Use render_template

What's Missing?

If you can understand some of the elements that are missing from this simple example, you’ll have a greater appreciation for the core of our Flask app and the many components that we’re about to study.

No Templates and Few Routes

Our initial application, hello flask, had one singular route @app.route('/') which is very basic. Just a homepage, that’s it. On the other side, “Flaskinni” includes numerous routes so you see blog and account pages just to name a few. Each route in Flaskinni calls templates with method calls like render_template('index.html'). These are just as their name suggests, templates or outlines of the final HTML page a user sees. Templates are a big deal (⅓ of our whole MVT structure).

No Models or Database

In the Hello Flask application, there is no database or model schema being used. There are no objects like user, admin, blog post in the app. Also in the Hello Flask app, we had no database, but in Flaskinni there is a database, and a schema that shows how the database will be set up. Also in Flaskinni there is code that creates database tables and is able to send the data to the database in the format laid out by the schema.

No Interactivity

Our initial Hello Flask application had no interactivity whatsoever as illustrated by the one simple message that is sent to the user. Our app only responds to GET requests, never a POST request. In other words, the user is only getting static information and is never sending information back to the server or requesting more specific information. For example in the Flaskinni application a user can post a blog post or can request or a certain blog post.

Few Libraries

Libraries are expansion packs, they're files containing compiled code that allow the app to reference them later in other files. Libraries allow the app the run faster and have more capabilities. Instead of calling methods over and over while writing the app, the user can call the library file. The linking of libraries allows a file to gain the capabilities of the library module without having to define those methods again.

You got this.
References are links to the original. Passing by value makes a copy

For this project, we'll be using a comprehensive dataset containing information about video games, including sales figures, critic ratings, user scores, and more. I've sourced this dataset from Kaggle: .

Copy the contents of GameDataManager.java file from this link:

Download the video_games.csv file and place it in your project directory. The location should match the path in the GameDataManager.loadFromCSV() method call.

Where are you going to do your coding? If you try to run your app, what other software is required? How are you going to save or publish your work? Configuring your , , and is essentially your workspace.

Want to know the difference between ‘GET’ and ‘POST’? You see them mentioned as a on line 16 in the picture below? Well, you should know the name Tim Berners Lee. GET and POST are two of the HTTP requests that travel over our network and provide us the Internet. Simply put, GET is a request for a page and POST is when the user is submitting a form. Knowing the types of HTTP requests gets really important if you ever decide to use to use this web app to power mobile apps, too.

Want some extra practice?
/**
 * The GameDataRow class represents a single video game from the dataset
 * and provides methods for analyzing game data including sales, ratings, and more.
 */
public class GameDataRow implements Comparable<GameDataRow> {
    // Instance variables will go here
    // Methods will go here
}
@Override
public int compareTo(GameDataRow other) {
    // if you want to implement Comparable, you'll need this sort of thing
    if (this.number > other.number) return -1;
    if (this.number < other.number) return 1;
    return 0;
}
public class MyClass implements Serializable { ... }
public class MyTask implements Runnable {
    public void run() {
        // Code to be executed in a thread
    }
}
public class ButtonHandler implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        // Handle button click
    }
}
public class MyCollection<T> implements Iterable<T> {
    public Iterator<T> iterator() {
        // Return an iterator
    }
}
// Instance variables
private int index;
private String name;
private String platform;
private float yearOfRelease;
private String genre;
private String publisher;
private float naSales;
private float euSales;
private float jpSales;
private float otherSales;
private float globalSales;
private float criticScore;
private float criticCount;
private String userScore; // Note: String type, not float
private float userCount;
private String developer;
private String rating;

// Static variable to track number of games analyzed
private static int gamesAnalyzed = 0;

// Constants for regional sales references
public static final int NA_REGION = 0;
public static final int EU_REGION = 1;
public static final int JP_REGION = 2;
public static final int OTHER_REGION = 3;
/**
 * Primary constructor for creating a new GameDataRow object with all fields
 */
public GameDataRow(int index, String name, String platform, float yearOfRelease, 
                   String genre, String publisher, float naSales, float euSales, 
                   float jpSales, float otherSales, float globalSales, 
                   float criticScore, float criticCount, String userScore, 
                   float userCount, String developer, String rating) {
    this.index = index;
    this.name = name;
    this.platform = platform;
    this.yearOfRelease = yearOfRelease;
    this.genre = genre;
    this.publisher = publisher;
    this.naSales = naSales;
    this.euSales = euSales;
    this.jpSales = jpSales;
    this.otherSales = otherSales;
    this.globalSales = globalSales;
    this.criticScore = criticScore;
    this.criticCount = criticCount;
    this.userScore = userScore;
    this.userCount = userCount;
    this.developer = developer;
    this.rating = rating;
    gamesAnalyzed++;
}

/**
 * Simplified constructor with essential fields only
 */
public GameDataRow(String name, String platform, float yearOfRelease, 
                   String genre, String publisher, float globalSales) {
    this.index = -1; // Default value for index
    this.name = name;
    this.platform = platform;
    this.yearOfRelease = yearOfRelease;
    this.genre = genre;
    this.publisher = publisher;
    this.naSales = 0.0f;
    this.euSales = 0.0f;
    this.jpSales = 0.0f;
    this.otherSales = 0.0f;
    this.globalSales = globalSales;
    this.criticScore = 0.0f;
    this.criticCount = 0.0f;
    this.userScore = "0.0";
    this.userCount = 0.0f;
    this.developer = "Unknown";
    this.rating = "Not Rated";
    gamesAnalyzed++;
}

/**
 * Copy constructor that creates a deep copy of another GameDataRow object
 */
public GameDataRow(GameDataRow other) {
    this.index = other.index;
    this.name = other.name;
    this.platform = other.platform;
    this.yearOfRelease = other.yearOfRelease;
    this.genre = other.genre;
    this.publisher = other.publisher;
    this.naSales = other.naSales;
    this.euSales = other.euSales;
    this.jpSales = other.jpSales;
    this.otherSales = other.otherSales;
    this.globalSales = other.globalSales;
    this.criticScore = other.criticScore;
    this.criticCount = other.criticCount;
    this.userScore = other.userScore;
    this.userCount = other.userCount;
    this.developer = other.developer;
    this.rating = other.rating;
    gamesAnalyzed++;
}
// Accessor methods (getters)
public int getIndex() { return index; }
public String getName() { return name; }
public String getPlatform() { return platform; }
public float getYearOfRelease() { return yearOfRelease; }
public String getGenre() { return genre; }
public String getPublisher() { return publisher; }
// ... and so on for all instance variables
/**
 * Main method for testing the GameDataRow class
 */
public static void main(String[] args) {
    System.out.println("===== GAME DATA ROW TEST SUITE =====\n");
    int testsPassed = 0;
    int totalTests = 9;
    
    try {
        // Test 1: Basic constructor and accessors
        GameDataRow game1 = new GameDataRow(
            1, "Wii Sports", "Wii", 2006.0f, "Sports", "Nintendo", 
            41.49f, 29.02f, 3.77f, 8.46f, 82.74f, 
            76.0f, 51.0f, "8.0", 322.0f, "Nintendo", "E"
        );
        
        if (game1.getName().equals("Wii Sports") && 
            game1.getPlatform().equals("Wii") &&
            game1.getGlobalSales() == 82.74f) {
            System.out.println("✓ Test 1 Passed: Basic constructor and accessors working");
            testsPassed++;
        } else {
            System.out.println("✗ Test 1 Failed: Basic constructor or accessors not working correctly");
        }
        
        // Test 2: Simplified constructor
        GameDataRow game2 = new GameDataRow("Super Mario Bros.", "NES", 1985.0f, 
                                           "Platform", "Nintendo", 40.24f);
        
        if (game2.getName().equals("Super Mario Bros.") && 
            game2.getGlobalSales() == 40.24f) {
            System.out.println("✓ Test 2 Passed: Simplified constructor working");
            testsPassed++;
        } else {
            System.out.println("✗ Test 2 Failed: Simplified constructor not working correctly");
        }
        
        // Test 3: Copy constructor
        GameDataRow game3 = new GameDataRow(game1);
        
        if (game3.getName().equals(game1.getName()) && 
            game3.getGlobalSales() == game1.getGlobalSales() &&
            game3 != game1) {  // Different objects
            System.out.println("✓ Test 3 Passed: Copy constructor working");
            testsPassed++;
        } else {
            System.out.println("✗ Test 3 Failed: Copy constructor not working correctly");
        }
        
        // Test 4: Static counter
        int expectedCount = 3;  // game1, game2, game3
        if (GameDataRow.getGamesAnalyzed() == expectedCount) {
            System.out.println("✓ Test 4 Passed: Static counter working");
            testsPassed++;
        } else {
            System.out.println("✗ Test 4 Failed: Static counter expected " + 
                              expectedCount + " but got " + 
                              GameDataRow.getGamesAnalyzed());
        }
        
        // Test 5: Get regional sales
        if (Math.abs(game1.getRegionalSales(GameDataRow.NA_REGION) - 41.49f) < 0.01f) {
            System.out.println("✓ Test 5 Passed: Regional sales accessor working");
            testsPassed++;
        } else {
            System.out.println("✗ Test 5 Failed: Regional sales accessor not working correctly");
        }
        
        // Test 6: Dominant region
        if (game1.getDominantRegion().equals("North America")) {
            System.out.println("✓ Test 6 Passed: Dominant region calculation working");
            testsPassed++;
        } else {
            System.out.println("✗ Test 6 Failed: Dominant region expected 'North America' but got '" + 
                              game1.getDominantRegion() + "'");
        }
        
        // Test 7: Sales percentages
        float[] percentages = game1.getSalesPercentages();
        if (percentages.length == 4 && 
            Math.abs(percentages[0] - 50.14f) < 0.1f) {  // ~50.14% for NA
            System.out.println("✓ Test 7 Passed: Sales percentages calculation working");
            testsPassed++;
        } else {
            System.out.println("✗ Test 7 Failed: Sales percentages not calculated correctly");
        }
        
        // Test 8: User score numeric conversion
        if (Math.abs(game1.getUserScoreNumeric() - 8.0f) < 0.01f) {
            System.out.println("✓ Test 8 Passed: User score numeric conversion working");
            testsPassed++;
        } else {
            System.out.println("✗ Test 8 Failed: User score numeric conversion not working correctly");
        }
        
        // Test 9: compareTo implementation (formerly Test 10)
        if (game1.compareTo(game2) < 0 &&  // game1 has higher sales
            game2.compareTo(game1) > 0) {
            System.out.println("✓ Test 9 Passed: Comparable implementation working");
            testsPassed++;
        } else {
            System.out.println("✗ Test 9 Failed: Comparable implementation not working correctly");
        }
        
    } catch (Exception e) {
        System.out.println("\nTest failed with exception: " + e.getMessage());
        e.printStackTrace();
    }
    
    // Summary
    System.out.println("\n===== TEST SUMMARY =====");
    System.out.println("Passed: " + testsPassed + "/" + totalTests + " tests");
    
    if (testsPassed == totalTests) {
        System.out.println("🎉 Congratulations! All tests passed!");
    } else {
        System.out.println("❌ Some tests failed. Review the output above to see which tests failed.");
    }
}
/**
 * Determines if the game has user reviews
 * @return true if user score and count are available
 */
public boolean hasUserReviews() {
    try {
        return Float.parseFloat(userScore) > 0 && userCount > 0;
    } catch (NumberFormatException e) {
        return false;
    }
}

/**
 * Convert user score from string to float, handling special values
 * @return user score as float or 0.0 if not available
 */
public float getUserScoreNumeric() {
    try {
        return Float.parseFloat(userScore);
    } catch (NumberFormatException e) {
        return 0.0f; // Return 0 for "tbd" or other non-numeric values
    }
}

/**
 * Returns a string representation of the game data
 */
@Override
public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append(name).append(" (").append(yearOfRelease).append(")");
    sb.append("\nPlatform: ").append(platform);
    sb.append("\nGenre: ").append(genre);
    sb.append("\nPublisher: ").append(publisher);
    sb.append("\nDeveloper: ").append(developer);
    sb.append("\nRating: ").append(rating);
    sb.append("\nGlobal Sales: ").append(globalSales).append(" million units");
    sb.append("\nDominant Region: ").append(getDominantRegion());
    
    if (hasCriticReviews()) {
        sb.append("\nCritic Score: ").append(criticScore).append("/100 (").append(criticCount).append(" critics)");
    }
    
    if (hasUserReviews()) {
        sb.append("\nUser Score: ").append(userScore).append("/10 (").append(userCount).append(" users)");
    }
    
    return sb.toString();
}
        // Convert critic score to scale of 10 like user score

        // fetch the user score using the built-in converter

        // check if any score is 0
            // if not, return the average of the two / 2.0f
            // else return the one with the number
// Example of how to use a switch statement to return sales for a specific region
// Example switch statement to convert a day number to a day name
int dayNumber = 3;
String dayName;

switch(dayNumber) {
    case 1:
        dayName = "Monday";
        break;
    case 2:
        dayName = "Tuesday";
        break;
    case 3:
        dayName = "Wednesday";
        break;
    case 4:
        dayName = "Thursday";
        break;
    case 5:
        dayName = "Friday";
        break;
    case 6:
        dayName = "Saturday";
        break;
    case 7:
        dayName = "Sunday";
        break;
    default:
        dayName = "Invalid day";
        break;
}
// Static method to get count of games analyzed
public static int getGamesAnalyzed() {
    return gamesAnalyzed;
}
/**
 * Analyze which platforms have the highest-rated games on average
 */
public void analyzePlatformQuality() {
    Map<String, Float> totalScores = new HashMap<String, Float>();
    Map<String, Integer> gameCounts = new HashMap<String, Integer>();
    
    // Collect data
    for (GameDataRow game : games) {
        if (game.hasCriticReviews()) {
            String platform = game.getPlatform();
            totalScores.put(platform, totalScores.getOrDefault(platform, 0.0f) + game.getCriticScore());
            gameCounts.put(platform, gameCounts.getOrDefault(platform, 0) + 1);
        }
    }
    
    // Calculate averages and find the best
    String bestPlatform = "";
    float bestScore = 0.0f;
    
    System.out.println("\n===== PLATFORM QUALITY ANALYSIS =====");
    System.out.println("Platform\tAvg. Critic Score\tGame Count");
    
    for (String platform : totalScores.keySet()) {
        int count = gameCounts.get(platform);
        if (count >= 10) { // Only consider platforms with enough games
            float avgScore = totalScores.get(platform) / count;
            System.out.printf("%s\t\t%.1f\t\t%d\n", platform, avgScore, count);
            
            if (avgScore > bestScore) {
                bestScore = avgScore;
                bestPlatform = platform;
            }
        }
    }
    
    System.out.println("\nBest-rated platform: " + bestPlatform + 
                       " with average score " + bestScore);
}
// Call your custom analysis
manager.analyzePlatformQuality();
/**
 * Calculates the factorial of n (n!)
 * @param n a non-negative integer
 * @return the factorial of n
 */
public static int factorial(int n) {
    // Base case
    if (n == 0 || n == 1) {
        return 1;
    }
    // Recursive case
    else {
        return n * factorial(n - 1);
    }
}
/**
 * Find a game by title using recursive binary search
 * @param title the title to search for
 * @return the game if found, null otherwise
 */
public GameDataRow findGameByTitle(String title) {
    // Sort the games by title first (if not already sorted)
    Collections.sort(games, (g1, g2) -> g1.getName().compareTo(g2.getName()));
    
    // Call the recursive helper method
    return findGameByTitleHelper(title, 0, games.size() - 1);
}

/**
 * Recursive helper method for binary search
 */
private GameDataRow findGameByTitleHelper(String title, int low, int high) {
    // Base case: element not found
    if (low > high) {
        return null;
    }
    
    // Calculate middle index
    int mid = (low + high) / 2;
    
    // Get the game at the middle
    GameDataRow midGame = games.get(mid);
    
    // Compare the middle element
    int comparison = midGame.getName().compareTo(title);
    
    // If found, return it
    if (comparison == 0) {
        return midGame;
    }
    // If the middle element is greater, search the left half
    else if (comparison > 0) {
        return findGameByTitleHelper(title, low, mid - 1);
    }
    // Otherwise, search the right half
    else {
        return findGameByTitleHelper(title, mid + 1, high);
    }
}
/**
 * Sort games by a certain criteria using merge sort
 * @param criteria the sorting criteria (e.g., "sales", "score")
 */
public void sortGamesByMergeSort(String criteria) {
    games = mergeSort(games, criteria, 0, games.size() - 1);
}

/**
 * Recursive merge sort implementation
 */
private ArrayList<GameDataRow> mergeSort(ArrayList<GameDataRow> list, String criteria, int left, int right) {
    // Base case: list of size 1 or empty
    if (left >= right) {
        ArrayList<GameDataRow> result = new ArrayList<>();
        if (left == right) {
            result.add(list.get(left));
        }
        return result;
    }
    
    // Find the middle point
    int mid = (left + right) / 2;
    
    // Recursively sort both halves
    ArrayList<GameDataRow> leftHalf = mergeSort(list, criteria, left, mid);
    ArrayList<GameDataRow> rightHalf = mergeSort(list, criteria, mid + 1, right);
    
    // Merge the sorted halves
    return merge(leftHalf, rightHalf, criteria);
}

/**
 * Merge two sorted lists
 */
private ArrayList<GameDataRow> merge(ArrayList<GameDataRow> left, ArrayList<GameDataRow> right, String criteria) {
    ArrayList<GameDataRow> result = new ArrayList<>();
    int leftIndex = 0, rightIndex = 0;
    
    // Compare elements from both lists and add the smaller one to result
    while (leftIndex < left.size() && rightIndex < right.size()) {
        GameDataRow leftGame = left.get(leftIndex);
        GameDataRow rightGame = right.get(rightIndex);
        
        boolean addLeft = false;
        
        // Compare based on criteria
        if (criteria.equals("sales")) {
            addLeft = leftGame.getGlobalSales() >= rightGame.getGlobalSales();
        } else if (criteria.equals("score")) {
            addLeft = leftGame.getCriticScore() >= rightGame.getCriticScore();
        } else {  // Default to name
            addLeft = leftGame.getName().compareTo(rightGame.getName()) <= 0;
        }
        
        if (addLeft) {
            result.add(leftGame);
            leftIndex++;
        } else {
            result.add(rightGame);
            rightIndex++;
        }
    }
    
    // Add remaining elements
    while (leftIndex < left.size()) {
        result.add(left.get(leftIndex++));
    }
    
    while (rightIndex < right.size()) {
        result.add(right.get(rightIndex++));
    }
    
    return result;
}
/**
 * Find the game with the highest critic score using recursion
 */
public GameDataRow findGameWithHighestCriticScore() {
    if (games.isEmpty()) {
        return null;
    }
    return findGameWithHighestCriticScoreHelper(0, games.size() - 1);
}

/**
 * Recursive helper to find the game with highest critic score
 */
private GameDataRow findGameWithHighestCriticScoreHelper(int start, int end) {
    // Base case: only one game
    if (start == end) {
        return games.get(start);
    }
    
    // Base case: two games
    if (start + 1 == end) {
        if (games.get(start).getCriticScore() >= games.get(end).getCriticScore()) {
            return games.get(start);
        } else {
            return games.get(end);
        }
    }
    
    // Find middle index
    int mid = (start + end) / 2;
    
    // Recursively find max in both halves
    GameDataRow leftMax = findGameWithHighestCriticScoreHelper(start, mid);
    GameDataRow rightMax = findGameWithHighestCriticScoreHelper(mid + 1, end);
    
    // Return the game with higher critic score
    if (leftMax.getCriticScore() >= rightMax.getCriticScore()) {
        return leftMax;
    } else {
        return rightMax;
    }
}
hello.py

import os  # connects the OS library so we can lookup our own IP address
from flask import Flask   # this connects our framework of tools we'll need

app = Flask(__name__)  # here we create our app in memory. It's maybe the most important line of code

@app.route('/') # if anyone tries to go to the homepage, their request will be routed to the method below
def index():
    return 'Hello from Flask'

if __name__ == '__main__':
    host = os.getenv('IP', '0.0.0.0')
    port = int(os.getenv('PORT', 5000))
    app.debug = True 
    app.run (host=host, port=port)
LogoCodePen
We'll build a practice page together in class using CodePen
LogoFlexbox Froggy
LogoCSS Diner
Video Game Sales and Ratings
https://gist.github.com/dadiletta/2310e45953e3bcb8db3cf151c7c75d06
https://www.kaggle.com/datasets/thedevastator/video-game-sales-and-ratings?resource=download
IDE
dependencies
VCS
kwarg
Flask-RESTful

4: Install Flaskinni

Learning Target

  • I can run Flaskinni after having cloned its code, configured its dependencies in a virtual environment, set up a database, and added an environmental variables file.

Install Party

Your OS

Whether you're using Windows, macOS, or Linux, you have a responsibility to your teammates that you keep your machine updated and organized. Run system updates, keep files off your desktop, have a system of organizing your project files. Knock this out early so it doesn't jam you up while installing complex programming tools.

Dev Tools

Go slowly. Go patiently. Things may not work. You will have to Google stuff, study, maybe ask for help, and solve your problems. Keep hacking at the problem. That's how we all learn best.

Python

Postgres

This is the open-source database tool we're going to use. You'll set up Postgres to host your own private database. It won't be available outside of your computer. It's just so while you work on an app, it can access a practice source of information.

Remember postgres password. Since my computer's database is only used for building and testing apps, I set the password also to postgres

Git / GitHub

NPM

Choco & Brew

Node Package Manager often encourages the installation of amazing CLI installers like choco or brew (Mac and Windows respectively). So if you like quickly installing awesome things and can accept the responsibility to do so safely, get one!

Scss

Editor

VS Code

I recommend these extensions

Setup Code

Clone the repo

Use VS Code's git tool to pull down the repo from GitHub.com: https://github.com/dadiletta/flaskinni

Stand up the db

"Stand up" a database just sounds so much cooler than "set up," but it's the same idea. You can see in settings.py that Flaskinni by default is going to reach out to a PSQL database named db-flaskinni on the server 0.0.0.0. The username and password used to access the database are also loaded there. Changes to this information shouldn't be done in settings.py but rather a .env fille. But before we do any of that, fire up pgAdmin and create a database.

Env variables

Our .env file doesn't and shouldn't ever get synced to GitHub. It's our secure place to keep the unique variables for each environment where our app will run.

###################
##  FLASK 
###################
FLASK_ENV=development
FLASK_APP=main
DEBUG=True 
SECRET_KEY='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'

###################
##  FLASKINNI  
###################
# DO NOT STORE A PASSWORD IN AN .ENV WITHIN PRODUCTION. SERIOUSLY UNSAFE
STARTING_ADMIN_PASS = 'flaskinni' 
ADMIN_EMAIL='flaskinni@gmail.com'
MAX_CONTENT_LENGTH = 2048 * 2048
UPLOAD_EXTENSIONS = ['.jpg', '.png', '.gif']

###################
##  SQLAlchemy 
###################
# Windows users change this to 127.0.0.1
DB_HOST=0.0.0.0 
DB_USERNAME='postgres' 
DB_PASSWORD='postgres' 
DB_PORT='5432'
DATABASE_NAME='db-flaskinni'
SQLALCHEMY_TRACK_MODIFICATIONS=False

###################
##  FLASK-SECURITY 
###################
SECURITY_REGISTERABLE=True
SECURITY_CONFIRMABLE=True
SECURITY_RECOVERABLE=True  
SECURITY_POST_LOGIN_VIEW='/'
SECURITY_EMAIL_SENDER='flaskinni@gmail.com'
SECURITY_PASSWORD_HASH ='pbkdf2_sha512'
SECURITY_PASSWORD_SALT = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'

###################
##  FLASK-MAIL
###################
MAIL_SERVER='sandbox.smtp.mailtrap.io'
MAIL_PORT=2525
MAIL_USE_SSL=False
MAIL_USE_TLS=True
MAIL_USERNAME='xxxxxxxxx'
MAIL_PASSWORD='xxxxxxxxxxx'
MAIL_DEFAULT_SENDER='flaskinni@gmail.com'

###################
##  JWT 
###################
PROPAGATE_EXCEPTIONS = True
JWT_BLOCKLIST_TOKEN_CHECKS = ['access', 'refresh']

Virtual env

First you use the correct version of Python to launch its venv module to create a folder for our dependencies (also named venv):

  • Windows: python -m venv venv

  • Mac: python3 -m venv venv (as of this writing, Mac still comes with now-defunct Python2, so you need to distinguish between them)

Let's say you're using Windows and you need to specify a non-default version of Python. You may need a line like:/c/Users/smithj/AppData/Local/Programs/Python/Python3XX/python -m venv venv

Then we activate the virtual environment so all our required "expansion packs" or dependencies will be installed in our little bubble:

  • Mac: source venv/bin/activate

  • Windows: (might need) Set-ExecutionPolicy Unrestricted -Scope Process .\venv\Scripts\activate

  • Windows (using bash instead of default Powershell): source venv/Scripts/activate

If you've got a happy little (venv) before your terminal prompt, you're ready to run: pip install -r requirements.txt

Did one of the dependencies listed in requirements.txt fail to install correctly? It's a common problem that must be solved. uWSGI doesn't need to be installed in the development environment so you can #comment that line out. If psycopg2 is failing to install, you can comment that out and manually install the binary alternative, pip install psycopg2-binary. Running pip install wheel may also resolve many of the installation issues.

You're likely going to end up with the wrong version of Flask-Security. So next run: pip uninstall flask-security

pip uninstall flask-security-too

pip install flask-security-too

Flask run

Migrations

Alternate setups

Replit

Docker

I need to study up on Docker. These are notes that I'll use to redo this section later. Trying new stuff is important, even if you're not moving it into your stack. Docker represents a booming growth in containers, and that's something serious web dev folks need to deploy at scale.

  1. Edit the Dockerfile with environmental variables

  2. docker-compose up --build

What if it's not working?

You're going to get stuck... a lot. This is where you can distinguish yourself as a programmer. Every problem big and small you hack your way through makes you more legit. So enjoy the grind. It's important to read around the problem and not just through it. Sloppy copying from StackOverflow once you copy and paste the error into Google can get you in trouble. Get background research done to understand some of the bigger concepts. Be willing to reach out for help, but respect that other people are grinding away too. Always show evidence of your research when asking for help as it will build trust with your support network.

7: Theme & Blueprint

Expectations

During this phase of your project, you can implement a new cosmetic layer. This will help setup the visual tone of your project while buying us some more time while we learn fundamentals. We will also add a new folder inside app/ that will store your routes

Learning Targets

  • I can implement a new HTML theme into a web app's base template.

  • I can create my own blueprint and prepare to expand my database schema.

Implementing a new HTML theme

We’ve got to build our base.html. That one file is the frame to our whole app. It’s a key HTML file in the T of our MVT. We’ll need to carefully setup the <head>’s attached files, the <body> and any wrapper/container structure your theme might be using, the <nav> bar, the {% block container %} where all other pages will be inserted, and your footer.

Pro Tip: Sometimes it's nice to have more than one base.html, if say, you have areas of your site that look dramatically different than others. I sometimes have marketing_base.html for my front page and a base.html with all the controls a user has when logged in.

Skinning your login page

Your theme, whether you got it for free or paid for it, will have a pattern to how it organizes the HTML each page (some themes use a series of containers, others <section>s, for example). Implementing a theme is about transferring static assets (like images and files) and separating the parts of your HTML code that are common on every page (and putting that in the base.html) and what is unique to the individual page (and putting that in individual template files).

Configuring your notifications

Figure out where all of these messages are listed in their container. Replace the stock objects, (probably will be li elements) and that will be generated instead by this line: {% include "security/_messages.html" %}

Note: When an HTML file is unable to stand up on its own because it's just a partial element, we put an underscore and the start of its filename.

{% with messages = get_flashed_messages(with_categories=true) %}
  {% for category, message in messages %}
    {% if category == "success" %}
    <li class="media">
			<div class="mr-3">
				<a href="#" class="btn bg-success-400 rounded-round btn-icon"><i class="icon-mention"></i></a>
			</div>
			<div class="media-body">
				{{ message }}
				<div class="font-size-sm text-muted mt-1">4 minutes ago</div>
			</div>
		</li>
    {% elif category == "danger" %}
    <li class="media">
			<div class="mr-3">
				<a href="#" class="btn bg-success-400 rounded-round btn-icon"><i class="icon-mention"></i></a>
			</div>
			<div class="media-body">
				{{ message }}
				<div class="font-size-sm text-muted mt-1">4 minutes ago</div>
			</div>
		</li>
    {% elif category == "info" %}
    <li class="media">
			<div class="mr-3">
				<a href="#" class="btn bg-success-400 rounded-round btn-icon"><i class="icon-mention"></i></a>
			</div>
			<div class="media-body">
				{{ message }}
				<div class="font-size-sm text-muted mt-1">4 minutes ago</div>
			</div>
		</li>
    {% elif category == "warning" %}
    <li class="media">
			<div class="mr-3">
				<a href="#" class="btn bg-success-400 rounded-round btn-icon"><i class="icon-mention"></i></a>
			</div>
			<div class="media-body">
				{{ message }}
				<div class="font-size-sm text-muted mt-1">4 minutes ago</div>
			</div>
		</li>
    {% else %}
    <li class="media">
			<div class="mr-3">
				<a href="#" class="btn bg-success-400 rounded-round btn-icon"><i class="icon-mention"></i></a>
			</div>
			<div class="media-body">
				{{ message }}
				<div class="font-size-sm text-muted mt-1">4 minutes ago</div>
			</div>
		</li>
    {% endif %}
  {% endfor %}
{% endwith %}

An old demo

Here's a demonstration showing the implementation of Flaskinni's old theme.

Create your blueprint

The different parts of your app should be kept in separate sections or blueprints. It'll make it easier to take one cool blog feature from one site and add it to another project later on. It also keeps your code more organized and easier to work on.

Files and Folders

The stuff we have to add to create a new blueprint can be divided up into the MVT (which I'll address in reverse). But first, do you know the name of your blueprint? It should be an easy shorthand because you'll be typing it a lot like so: {{ url_for('why_is_my_blueprint_name_so_long.dashboard') }}

This example uses a blueprint named "project" which is a pretty lame name. Hopefully you can do better.

Template

Inside the templates/ folder, create a new folder with your blueprint's name. I almost always use a _cards.html full of macros ready to build cards for all sorts of objects in my app. Might as well add that now, too. For all the new pages you add to your app, you should use use a blank_page.html that you can copy and paste then rename.

Views

Create a new folder within the app/ folder. Like always, spaces and capitals are a bad idea in folder names. Inside that folder create an __init__.py file. In the file, you'll need to customize this code for a folder name unoriginally titled project/:

"""
project blueprint constructor - flaskinni/app/project/__init__.py
"""
from flask import Blueprint

project = Blueprint('project', __name__)

from . import views, forms # you can split these into multiple files if they get big

Model

We keep a separate folder for our models. I typically have quite a few files. We'll talk more about building your schema next chapter. For now, know that any new classes you make need to be imported in the __init__.py file. That keeps our imports more organized.

Connecting to Flaskinni

When our app factory in app/__init__.py puts together an instance of our software, it registers our blueprints and imports our models. The app factory is the knot that holds everything together. So the final step is to register our blueprint there. You're now ready to start taking Flaskinni's application logic in a whole new direction.

Making changes to the database

Destroy and rebuild (the wrong way)

The right way to handle this situation is discussed in the next section. Let’s look at the lazy, dangerous way of keeping your database up-to-date through gross destruction. DANGER: This will destroy all saved user data. You have a sacred mission to keep this safe and private. This practice is only tolerable at this very early stage of development when we’re learning how to form effective and efficient database schemas. So if you can say to yourself, “who cares? There’s no data here and never has been,” then this might be the right way to update your database.

Check private.py for the name of the database being used in our app: BLOG_DATABASE_NAME. In this example, it’s called, “db”.

psql

\l

drop database db;

\l

create database db;

\q

Migrate and upgrade (the right way)

Once your database has been configured and your tables all have columns, making changes is tough. Sure, rows (aka “records”) can be added and deleted without any major problem. But changing the schema so that an object, or table, has new properties (columns in your tables) is much more difficult. Changing the columns in your database tables is a delicate process. Fortunately there are tools like Flask-Migrate to help migrate the data from one version of the table to the next.

Why does this work differently?

If you do it to one, you've got to do it to them all

Typically, we don’t work on just one database at a time. Most projects have a staging version and a production version and both have their own databases. If you make a change to one, you'll have to migrate the other. That’s why we have Flask-Migrate! Don’t start this process until your teacher has told you your database schema is largely stabilized, (this should happen at the end of the next section of this guide).

Getting started:

flask db init -- this command you'll only do the first time

flask db migrate-- this command detects any changes and builds a migration strategy to change your database

flask db upgrade-- this command executes the migration

Publish Static HTML

Move from a development environment to production

Congratulations! You've poured your creativity and skills into crafting a stunning design project on Replit. While Replit offers a fantastic development environment, the built-in preview webpage has limitations. It can't handle large volumes of users and might have occasional downtime, potentially affecting your project's visibility.

To overcome these limitations and showcase your work to the world, we'll take the next step: deployment. Don't worry; the process is a snap.

Flask has been helping our projects by adding our navbar and footer and such to every page. But now we want to export a copy of the site that doesn't require this fancy tool. That's essentially what we'll be doing by flattening your website. This means converting your project into a static HTML format, eliminating the need for constant server interaction. This static version will be much faster, more reliable, and accessible to a broader audience.

To achieve this flattening magic, I'll use a tool called Frozen-Flask. It's a powerful script specializing in creating static Flask application versions. Once your project is flattened, we'll proceed to the deployment stage. This is where your project finds its permanent home on the World Wide Web: a hosting platform called Netlify.

Think of Netlify as your website's personalized apartment building. It provides the infrastructure and resources needed for your project to be live and accessible 24/7.

Publishing

    • Create an account on the site and verify your email address

    • Once logged in, you'll see an area indicated by a dotted line where you can drop a folder

      • If your folder isn't uploading, you may images or other files that are too large. Downsize your images or move unneeded files outside of the bootstrap_project folder

    • Edit your site details so you can change the URL from its randomly-issued name

    • Submit the URL so it can be graded. Remember, if you make further changes, you need to re-publish your site using the following instructions:

Updating your page

You've been seeing your page update on your local machine. That's not on the Internet and the link in your browser won't work on anyone else's machine as it refers to a file on your computer. But we can deploy the website to free host using Netlify.

Requirements

  • All stock content replaced

  • A color palette implemented uniformly throughout the page and corresponds with the subject of the site

  • Custom header and body fonts that corresponds

  • CSS file formatted into sections with color palette written in a comment at the top

  • CSS rules overwriting theme styles like btn and bg

  • A new section added to the navbar and the body with smooth scroll working to that location

  • A new Bootstrap component taken from the documentation

  • A new CSS class and ID implemented in the CSS and HTML

  • Images (not in conflict with copyright law) successfully added to img folder and added to site

Wordle with Turtles

Daily Lessons

Wordle with Turtles Assignment

In order to complete the Wordle program, there are a few things you need to add:

  • Make a new method in GamePlay.py which can be called during process_input() with different colors in the different letter situations. Keep your code D.R.Y. (4 points)

  • Complete the check_game_end() method in Gameplay.py and implement checks throughout your game. Make sure the game actually ends -- remember we have a boolean which controls the end of the game in main.py. (4 points)

  • Make sure your settings variables are all implemented within your program (for example: when you change background value to a different color, it actually makes the change in your program). (2 points)

  • Add a minimum of twenty 5 letter words to your word list. (1 point)

  • Clean up your code. Get rid of methods or imports you didn't use. (1 point)

4: Turtle Design App

Class Videos

2/1

2/2

2/7 assignment PT 2

2/7

2/9 -- Extending the SuperTurtle APP Assignment

To finish off the superturtle app, we are going to add the following to our program:

  • Move the printing of the menu options to the helper function, but run it in main.py (2 points)

  • Add four_square to the menu options (you should have 1. add turtle, 2. star, 3. four square at this point) and make them execute when called. (2 points)

  • Add at least 3 new methods to the SuperTurtle class (whatever you want, but they should be obviously different than the things we wrote together.) Add the methods to the main menu and make sure they execute when called. (9 points)

  • Make sure you have a creative display! (2 points)

6: Advanced Editing

Learning Targets

  • I can configure a project folder in a cloud-based file system.

  • I can customize the elements of an HTML template.

  • I can publish a completed webpage and share the link with my friends.

  • I can take feedback on my website and publish an improved draft.

Colors

Inspect and Overwrite

Let's identify a rule that's being used by our theme and overwrite it.

New Bootstrap Component

Revisions

We all have to edit our work. We need to collect feedback, review, make a list, and add improvements to our project. The more you repeat this process, the better your end product (as well as first draft on your next project).

Responsive refinement

@media only screen and (max-width: 600px) {
  body {
    background-color: lightblue;
  }
}

Fine Tuning

Extra Addons

Load Screen

We're going to use jQuery

Add a <div id="cover"></div> on the first line of your <body>. Then at the very bottom, add the following script:

  <script>
    $(window).on('load', function(){
      $('#cover').fadeOut(1000);
    });
  </script>

And we'll add the following code to our custom.css.

#cover {
    /* save a file called loading.gif to your img folder */
    background: url("../img/loading.gif") no-repeat scroll center center #FFF;
    position: absolute;
    height: 100%;
    width: 100%;
    z-index: 9999;
}

Replacing Images

JavaScript

5: Collaboration

Use project management software to be accountable for professional-caliber design work.

Learning Targets

  • I can build a professional-caliber file system.

  • I can collaborate with my team through a KANBAN board.

Google Drive

While often used for online storage, Google Drive's offline functionality unlocks its potential for design projects. You and your team can work on Adobe AI and Photoshop files without an internet connection by enabling offline access. Shared folders within Drive serve as central hubs for exchanging design files and planning materials like Google Docs. This seamless collaboration ensures everyone stays on the same page, regardless of location or internet availability. This technique is crucial for delivering professional-caliber design work in a collaborative environment.

  • ProjectName

    • Loose in the folder can be branding documents, collections of text in Google Doc and other guides.

    • STOCK

      • Collect images from allthefreestock.com and other sources. These are raw images that will need to be resized and possibly color-treated.

    • HTML

      • Any coding elements get stored in this folder

    • IMG

      • Edited images ready for the web.

    • LOGO

      • Adobe files and your logo package

    • RESEARCH

      • Collect relevant articles, screenshots of other websites for comparison, etc.

KANBAN

Initially developed by Toyota to optimize manufacturing, KANBAN boards have become a popular project management tool across various industries, including design. Their simplicity lies in their visual, three-columned structure: Backlog, In Progress, and Done. This straightforward visualization aids communication and transparency, allowing every team member to grasp the project's status at a glance. KANBAN's power lies in its ability to manage project flow. Tasks move from Backlog to In Progress, signifying active work. Once completed, they shift to Done, signifying progress and freeing up space for new tasks. This system prevents overloading team members and keeps complex projects manageable, even for large-scale design endeavors. Whether collaborating remotely or in person, KANBAN boards ensure transparency, focus, and continuous project flow, propelling your design project toward successful completion.

Every Trello card is a vital piece in our project puzzle. Here's what makes a great one:

Title: Keep it simple and descriptive. Focus on the problem, not the solution ("Broken Link on Homepage" versus "Update Header Navigation").

Description: Explain the issue itself, avoiding descriptions of actions taken. Let the details flow freely so others can understand the scope of the problem.

Visuals: Paint a picture! Paste screenshots directly onto the card to clearly illustrate the issue and where it occurs.

Teamwork: Ensure the right team is aware. Tag the appropriate team members who can tackle this specific problem.

Backlog to In Progress: When the card is ready for action, drag it to the "In Progress" column. Now's the time to assign ownership! Choose the individual(s) directly responsible for working on the issue, not the entire team.

Progress Tracking: Before marking the card "Done," log your activity in the comments section. Share screenshots, code snippets, or any relevant updates to document your progress.

Time Transparency: Be kind to your future self (and colleagues)! Track your work in 15-minute increments. This detailed time log will prove invaluable when creating project invoices.

Remember, clear and concise Trello cards are the key to smooth communication, effective collaboration, and, ultimately, project success. Let's build clear cards and conquer those sprints!

Example Cards

You'll have to make your own cards, but here's some starting ideas:

We'll be using Trello to track your progress and to coordinate a team project. Each task or card must be a specific task that can be achieved preferably within a class period or at least within a week. The measurement or proof of that task's completion should be described in the activity log entry of that Trello card.

3: Data Types & Flow

We will learn to solve simple problems with Java programming. We will create all sorts of variables, test their limitations and exercise basic control flow.

Learning Targets

  • I can declare variables of common Java data types and assign values.

  • I can control the flow of my app with loops, conditionals and method calls.

  • I can write efficient conditionals and return comparisons in my methods.

  • I can describe the difference between logic, run time and compile time errors.

Declaring Variables

Naming Conventions

CompoundCapitalize name of classes

camelCase variables and methods

ALLCAPS variables marked as final, meaning they can't change

snake_case is typically used only in Python and I miss it every time I work in Java or C#

Operators

Arithmetic

Operator

Description

Example (a=10, b=20)

+ (Addition)

Adds values on either side of the operator.

a + b will give 30

- (Subtraction)

Subtracts right-hand operand from left-hand operand.

a - b will give -10

* (Multiplication)

Multiplies values on either side of the operator.

a * b will give 200

/ (Division)

Divides left-hand operand by right-hand operand.

b / a will give 2

% (Modulus)

Divides left-hand operand by right-hand operand and returns the remainder.

b % a will give 0

++ (Increment)

Increases the value of operand by 1.

b++ gives 21

-- (Decrement)

Decreases the value of operand by 1.

b-- gives 19

Integer Math

What's 9 / 4? In Java, it's just2, but if you wrote it like 9.0 / 2, then the answer would be 2.5. If you don't introduce a decimal to the operation, if you only give Java literal ints , it'll match that format and ignore decimals.

Comparison

We evaluate / test data and produce a true or false value.

Operator

Description

Example (a=10, b=15)

Result

==

Equality operator

a==b

false

!=

Not Equal to operator

a!=b

true

>

Greater than

a>b

false

<

Less than

a<b

true

>=

Greater than or equal to

a>=b

false

<=

Less than or equal to

a<=b

true

Short-Circuit Evaluation

This comes up all the time in problems. It's a useful trick to avoid crashing your apps, too.

Conditions

A fundamental element of flow control is whether or not you want to execute a block of code. We use a conditional or if statement to test something. That test will result in a true or false value. If it's true, we'll execute the block of code. If it's false, we'll skip to the end of the block of code.

Loops

Loops are how we repeat commands or loop through items in a collection.

for loops

standard for loop

Most for loops look something like this:

for(int x = 0; x < 20; x++) {
    // code goes in here
}

The for statement has a declaration, condition and increment. But you can skip the declaration if you'd like. Let's say you want the counter to have a wider scope (so it can be accessed outside of the loop) like this:

int x = 0;  // declared outside the loop so it can remain afterwards
for(; x < 20; x++){
    // code goes here for the loop
}
System.out.println(x);  // will print 20

foreach loop

Let's say I have an array or collection of numbers like this: int[] numberArray = [5, 10, 15, 20, 25];

Each number in that group has an address or index (that starts at 0). If I wanted to print the number 10 for example, I could write System.out.println(numberArray[1]);

So if I wanted to loop through (called iterating or traversing) all the items in this array, I could use a normal for loop like this:

for (int x = 0; x < numberArray.length; x++){
    System.out.println(numberArray[x]);
}

But there's an easier form of the for loop that's meant to easily traverse through a collection. We'll go over some of the pros and cons of this method later.

for (int x : numberArray){
    // x isn't looping through the addresses this time
    // rather, it's pretending to be each number in the collection
    System.out.println(x); 
}

while loops

Infinite loop

while(true){
    // will never stop looping unless I use the break command
}

do-while loop

do {
    // code will run at least one
} while(x > 10);

Arrays

You can declare and initialize an int like int x = 5; Similarly, you can create an array that contains three ints like this: int[] x = {5, 10, 15};

Arrays are immutable. They don't change in size. Java uses a fancier object called an ArrayList that is more flexible. So if one of your friends is trying to convince you to increase the size of an array, just say no.

Array Tricks

// Let's demonstrate some array skills!

// Here's a blank array that's got spots for five ints
int[] arr = new int[5]; 

// You can also create an array with initial values
int[] x = {5, 10, 15}; 

How long is that array?

x.length; // note: this isn't a method like it is in the String class.

What's the first element in the array?

x[0]; // this will print "5" in my example

What's the last element in the array?

x[x.length-1]; // this will print "15" in my example

What other skills do you need to know?

  • Loop through every element in the array

  • Check if an element is found in an array

  • Make an array of other types of objects

Method Calls

This is a part of control flow. The thread, the computer's train of thought, is being sent over to work through a set of commands called a method or function (either name works in this class).

Gamemaker Studio 2 and Github Setup

Web App Dev

Produce a full-stack web application in Python's Flask framework. While this is difficult and complex, it'll be a rewarding challenge.

Why web development?

Web Development is my favorite area of Computer Science to study. Programming at the hub of all information gives you a bird’s eye view of how business operations fit together. If an organization has mobile apps, websites, and some sort of critical information for their business, then web developers are the people holding systems together. There's so much happening in this field, too. In fact, we've got to be careful that all this cool tech doesn't overwhelm you.

Pro-level challenge

Acceptable Level of Abstraction

Little kids like to keep asking, “Why?”

A thread of inquiry can always get more detailed. It never stops. You can keep digging deeper. Sooner or later we just accept the idea of something and stop asking questions. For example, I know hardly any of the electrical engineering involved to build a stick of RAM but I would still claim I know what RAM is. I’ve just accepted that there’s a thing called RAM and it works like so and I’m okay not knowing any more details than that for right now.

We are going to narrow our focus to building a Python Flask app using templates and a pre-built starting point. We can build really cool things but it means that we’re going to brush over big concepts that are totally worth studying. Sometimes it’s hard to feel like you understand something if you can’t take the time to closely examine all of the pieces and principles involved. Write down questions, don’t stifle your curiosity, but be patient as we setup lots of abstract ideas that we won’t be able to satisfactorily investigate for a while. TLDR: Be patient and keep a running list of concepts and questions to research later.

Resources

  • Guided Training: Do your homework! Actually grind out the projects in tutorials. Learn the rules of new languages.

  • Publishing: How do we get our Flask app online?

Extra Resources for the Try-Hards:

  • Books at give superpowers

8: Sorting

We will write our most complex algorithms as we study efficient ways to sort collections of data. Some of these algorithms will require recursion, our most abstract and challenging topic to date.

Learning Targets

  • I can implement selection, insertion and merge sort algorithms.

  • I can compare sorting algorithms' efficiency.

Algorithms

We've talked about algorithms before, most especially around the shuffling patterns we've used in the Elevens lab.

Efficiency

The bigger the group of data, the more important it is to be efficient. Searching on the web or in a database needs to be awfully fast. We measure the efficiency of a complex search or sort algorithm in Big O notation.

Searching

Let's knock out a quick algorithm first, searching. The O(n) way is just a straight traversal. But we could chop that down to a O(log n) with a binary search:

The visualization of these patterns / algorithms / methods / whatever, is surprisingly helpful. You can get a feel for how we chunk the computer's task to organize a long list of numbers.

Selection Sort

Let's start with a nested loop, a boring old O(n^2) traversal and sort.

Now between the inner and otter loops, we do a 3-part-swap

Insertion Sort

Insertion sort has the same worst-case scenario efficiency as selection sort, but it has a much better best-case scenario efficiency.

Step 1: Nested loop with an inner loop traversing in reverse.

Still Step 1: The inner loop doesn't need to start at index[0]

Step 2: The inner loop goes backwards so long as the number that the outer loop has is bigger

Step 3: You'll have to move numbers over as you go to make room

Assignment

Create a class that uses Sortable and IntegerMonster. Hopefully, that and the code below is enough for you to figure out what to do next. If not, let's make some extra time to practice/read about inheritance in Java.

You'll have to use extends before implements. Potentially helpful analogy: I imagine "extends" as the class's last name and "implements" as job titles.

Surprise: Your client suddenly changes the SoW and insists that the sort methods' outer loops print the current state of the array neatly on one line. Each array during the sort should be labeled.

Recursion

What happens if I call a function that calls itself? You can use this as a trick to chunk information in a loop-like flow.

A base case is the critical piece of a recursive function that will terminate the recursive calls, and start the domino effect in the opposite direction.

If we have a base case in place (rhymes!) we can use recursion to solve some tricky problems in an elegant fashion.

Merge Sort

Let's start with some numbers to sort:

Check if nums has hit its base case. Is it already split up? If not, split it up.

Then we send each side to mergeSort. Notice we send the left side first. And the next copy of mergeSort will break that side up first too--all the way down to the base case.

But down at that last level, when they can't be broken down any further, we'll be left with a few useful ingredients, the (yellow) nums, the left side, l, and the right side, r. Now we'll shove l and r back together, in order, and overwrite the contents of nums. We'll do this in a separate function: merge(nums, l, r, mid, n - mid);

First notice how they include the post-operation increment, k++ (instead of ++k). This way, every time k is used, it increases the index tracker on the parent array. It's a clever touch. Meanwhile, i is serving similarly as the index tracker for the left side and j is serving the right side.

The first while loop proceeds until one of the counters hits their max. Then only one of the two remaining while loops will execute, collecting the last number.

Assignment

Create a class that extends NameManager and implements all required methods.

4: Strings

We start to delve into algorithms and basic AI with our first CollegeBoard-issued lab. We will learn about String manipulation so we can have a conversation with our computer.

Learning Targets

  • I can use common String methods to modify a string.

  • I can evaluate the contents of a String.

  • I can use a Scanner to take inputs.

  • I can isolate an object in the user's input and use it in Magpie's response.

Magpie Lab

CollegeBoard used to have three official projects, Magpie, Elevens, and PicLab. A few years ago, they dropped those four and started four new ones: Celebrity, Consumer Review, DataLab, and Steganography. But I still think Magpie is the best lab for starters.

What's a magpie?

A bid that can mimic speech.

Check out the chatbot in Activity 1:

Strings

Strings are a special data type in Java. They're not primitives but they behave a little differently than most instantiated objects. In many ways, they're an array of primitive char objects. The biggest difference is that Strings also have many helpful methods to change their formatting, to search and examine the Strings, and lots of other helpful tools.

StringExplorer

Create a new class in our project called StringExplorer and drop this code in:

Activity 2 Starter Code

Now we're going to add a few new classes to the project.

Magpie.java

Now write a commit message to bookmark these changes and push the new version to GitHub. Then following along with the exercises in Activity 2.

Activity 3: Better method

Magpie's current structure and use of .indexOf("something") >= 0 is full of logic errors. It's caps sensitive, it can't tell if you've entered no response at all, and it sees the word "no" inside of "know". Let's do better.

Now we've got to update our getResponse method to use this instead of indexOf.

Let's use this chart to walk through what's happening:

Activity 4: Slice and dice

Let's use parts of the user's message in our response. Read the details in the student guide. Before proceeding.

Replace the else in our getResponse method with the following code:

Now below this getResponse method, let's add in a few methods that are being called by the code above.

Okay, now you're ready to follow along the student guide with the class and ask some questions along the way.

Chatterbots

Your team will build a chatbot that will enter into a conversation with other chatbots built in class.

Step 1: Duplicate and rename example

Next, we need to rename the file and the class.

Do not name your chatbot the same as anyone else's in class.

Step 2: Instantiate bot

Now that you've created your robot, you can add it to the main method.

Step 3: Meet requirements

  • File

    • 1 point: Your file has an original name that matches the name in your class definition

  • name

    • 1 point: Returns a one-word name that roughly matches your class name

  • greet

    • 2 points: Returns a 25 - 100 word opening statement.

    • Bonus +1 point: Randomly selects from at least three opening statements

  • respond

    • 3 points: Checks for three different antagonistic words and does not complete the respond method but instead calls the antagonize or pacify method instead

    • 3 points: Checks for three different pacifying words and does not complete the respond method but instead calls the antagonize or pacify method instead

    • 5 points: Searches for at least five keywords and responds to the given subject matter.

  • antagonize

    • 3 points: Searches for at least three keywords and responds in a negative tone to the given subject matter.

  • pacify

    • 3 points: Searches for at least three keywords and responds in a positive, disarming tone to the given subject matter.

  • BONUS POINTS

    • Have your greet method randomly select from at least three opening statements

    • Successfully use substring on the given prompt/statement

    • Your bot successfully adapts to antagonistic or pacifying messages from other bots

Review

Let's review some basics before we move onto our next, advanced concept. Now's the time to hit codingbat, SoloLearn, Codecademy, or other training websites to practice. You want the basics down pat so you can focus on new concepts as we move forward.

Game 1: Bouncing Ball

The bouncing ball game will provide the basics of using sprites, sounds, objects and rooms.

Game 1: Instructions

Bounce Code

6: Visualize Your App

Expectations

Learning Targets

  • I can develop a brand identify for my product including logos, color pallets, fonts, and tone of voice.

  • I can outline the workflow of my app in a wireframe.

Setup a local folder using something like Google Drive to collaborate with your team. Download a theme. Start a PowerPoint or Google Slides document to take notes, build a scrapbook of visual designs that can help you shape the message you’re trying to send.

Select a Theme

For rapid prototyping, don't be afraid of using Flaskinni's default theme. Proving your app concept with a pleasant, neutral design is smart.

Custom layer

Change base.html

The Brand

Building your app, your team, and your company requires a lot of drive. A brand identity is a flag on a battlefield for your soldiers to rally.

Colors

Go to the websites of some major brand names you know and look at the colors used. If you did deep enough, you'll find a variety of button colors, but most things follow a pretty consistent pattern. It's time to set up such a pattern inside our CSS.

Sass

If you're using SourceLair, you may need to upgrade Sass so it can handle recent Bootstrap templates. So first run npm install -g sass so you can then run: sass app/static/scss/custom.scss:app/static/css/custom.min.css

The code below are example MacOS settings for the Live Sass Compiler extension for VS Code.

Fonts

You'll need a header and a body font at least. Sometimes a logo font is used as the headers, sometimes not. You may want to pick out your logo first and then find complementary fonts afterwards.

Logo

Start sketching ideas on your branding document. It can be very powerful to have a logo designed early in project development as it sets styles, colors and gives you something to reference when discussing your project.

Stock Images

Shutterstock.com -- start building collections of images you might want to use

Add images to your branding document. Scrapbook images that you don’t intend or are unable to buy and use but speak to the type of look and feel you want (or want to avoid). Have a different section for images that you may want to purchase and use later on. Free images you can start to download and organize into your team’s project folder. Paid images you can start to save in bookmarks, links on your slides, or in other ways.

Wireframes

The wire-framing that needs to be added to your branding document is essentially just shapes illustrating what your app can do. You could use Google Slides in a real hurry. Ideally though, you should use the wire-framing process not only to determine all the steps your users will need to take, but also how you'll organize the interface. You're making UI decisions as well as UX.

I try to start by first looking through the pages that come with my HTML theme and see what sort of layout, widgets and objects are readily accessible. Keep them in mind when designing your wire-frames. After this early phase, we will be building full HTML mockups to illustrate these wire-frames.

HTML mockups

Building HTML mockups is much, much slower than Adobe XD. You ought to sketch out your apps before you code HTML elements. But designing the HTML elements using the theme assets you'll have in production takes you from planning the outline of the user experience (UX) to the mechanics of the actual interface (UI).

Before you advance, be sure you’re making steady progress through the Flask Udemy course (and getting help when stuck)

Game 2: Maze

The maze game increases user control with directional inputs as well as creating a game progression through multiple rooms.

Maze Instructions.

A day before some hackathons or events like , experts will host a session to help everyone install the tools they'll need. If you serve pizza, you can call pretty much anything a party.

Your computer only understands Python code through a or . Your computer uses bytecode to run the software. Our interpreter changes our beautiful Python code into a jumble of machine instructions. Ensure you use the same version in development as you do in production. That means if your server will run, say, Python 3.10, that's what you use to build the thing.

Mac users should have and run xcode-select --install in their terminals. Windows users need to install . This gives you the commands to clone a repository, manage your changes to code, and sync

Once upon a time, Javascript was just used to make pictures slowly spin on a webpage. Now we've got NodeJS letting this language that used to be purely stuck inside a web browser to now run independently on your computer. It's so popular, the tool to quickly install awesome new Node packages is a must-have.

(Windows) (Mac)

Old-school CSS is a pain to program at a large scale. Sass is much more powerful. Your computer has to have it to run the service built into Flaskinni. If you've got Choco or Brew installed, adding Sass is a breeze.

(they make it much easier to see your files)

You can edit your code on the cloud with cool sites like . A cloud-based IDE is likely going to be based on Linux. That means you'll need to know a bit about . Linux plays well with coders and a cloud-based IDE makes it easy to share your development progress with people and get feedback faster. That's big.

You can also set up right on your computer. You should know how to do this just so you can practice putting all the pieces together. I prefer to program in the cloud and locally and use to keep the two environments in sync.

After running flask run in VS Code, you should be able to visit to see your website.

This is important! Pity the poor programmers that forget to set up their migration tools. Once Flaskinni is up and running the first time, run flask db init to allow Flask-Migrate to help with any future changes to your models. We'll talk about .

Help! I don't know how to configure Replit's database service with SQLAlchemy. Their technical support doesn't know how to do it. They point me to ... and those folks can't crack it, either.

Make sure is installed, running, and logged in.

Clone git clone http://github.com/dadiletta/flaskinni

Our next task is to apply your theme’s design to the built-in login page. Applying a cosmetic, HTML layer to your application is sometimes referred to as “skinning.” The login’s template is provided by our installed in Flaskinni. If you were to delete one of the template files, the app would default to the built-in Flask-Security template. By having the files in our templates folder, we override the built-in look of the pages.

HTML templating is fun

If you haven't learned about flash notices yet for homework, you can , or talk about them in class. Assuming you get the idea and see how Flaskinni uses them, let's now rewire the system so it looks good in your HTML template. Maybe we'll use a dismissible Bootstrap alert but maybe want to tie into some fancier features that come with some themes.

Many HTML themes have notification div boxes like this

In the next section, we’re about to build . You must understand that anytime you tinker with a models.py file, (from the /inni folder or elsewhere) then you’ve altered your schema and now your database is likely now out of sync. For example, let’s say you wanted to combine User.first_name with User.last_name so there was just one field, User.name. The SQL tables that stored that information can’t adjust to your modified Python code so easily. All of the existing records (i.e. the rows in your tables) will need to now be migrated to a the new set of columns you’ve constructed. That can be really tricky!

These commands are different and likely to change in the future. Think about it: we're not using our Flask app. Instead, we're using some tool that detects changes in our database and automates the migration of our data in our old table to our new table. Delicate stuff! Before we'd use Flask-Script as an intermediate. Now we use to access terminal commands that will migrate our database.

Must read:

And then select your site
Go the page that will allow us to update the root folder

​

​​

​​

​​

​​

​ ​

​

Let's get back to the Bootstrap and shop for a new component to add to our site.

This comes from a great blog post about "breakpoints"

If you're not frequently having to look things up (and finding W3Schools) you're not trying out enough new things.

Our Bootstrap template uses , which is a really handy JavaScript library. JavaScript is a programming language that runs right inside your browser. Most of what you do with jQuery can be done in plain-old vanilla JavaScript. We use jQuery to make life a little easier.

Pretty simple idea, right?

Primitives are objects that live entirely in stack memory (they're lowercase like int and not like String) . We'll go over the difference between stack and heap memory later. For now, just think of stack memory as the lightweight stuff that's really fast-access. Take a look at the .

The do-while is rarely used but it's handy if you want to make sure the steps run the first time before the loop condition is tested.

This is a silly joke, not an actual way to resolve problems with your loops.
The main function is calling max(), passing it a few numbers and saving the result
The variable declared in the header is scoped to that function

This section of 's Computer Science Department's GitBook is also the official documentation of the . If you would like to skip the background information about web applications, you can proceed straight to .

Want to jump in with both feet and go hard on the research? See if you can get your head around the growing change from to . What are those and why is there a change happening? Don't sweat it if YouTube videos and articles go right over your head. It's good to start dabbling and exposing yourself to top-level discussion.

(Python)

This is a great follow-up to the video below.

There are all sorts of variations on mergeSort and the merge function. The one from is pretty clever and fun to talk over. Check it out:

Check out the .

Let's drop these two methods into your Magpie class ():

If you don't start visualizing things before you're knee-deep in code, your product will lack a cohesive visual style and an intuitive workflow. Building an app starts with colors, logos and most importantly, .

Rather than design our own HTML layout and polish the finer details and effects, we’re going to use a theme. We’ll look at and . You must make sure your theme is based on , preferably the most recent version. You want to make sure that the theme has a variety of elements and layouts that will allow you to mockup pages quickly.

Never make changes to theme.css, style.css or whatever your file is called that governs the primary rules of your theme. We will override the rules using different files. That way we can more easily upgrade the theme in the future. The custom.css file (that hopefully you're using to produce) in our <head> after the theme’s CSS. That way, our rules will overwrite the theme’s. We’ll have the final say.

Implementing a new theme is tricky business. You'll have to rebuild your static assets and modify all the templates. The base.html file will need the most amount of work as it will need to reflect We talk about that more .

These palettes can help you color your logo

expand the 5 colors you get from coolors

Eva will help you fill in any gaps on the standard Bootstrap colors (primary, success, info, warning, danger)

When in doubt, use Flat design

Hopefully you have a _variables.scss file where you can drop all your color palette. Many themes include these assets. Flaskinni's default theme comes from so you can take advantage of the to quickly implement your colors.

Note: Maze reuses the resources from the first game. If you need to download the assets again, they can be found .

RailsBridge
compiler
interpreter
Xcode
Git for Windows
npm
https://chocolatey.org/
https://brew.sh/
WebAssembly
Cyberpunk theme
Custom icons
Better Jinja
DotENV
Python Auto Env
SourceLair
Linux CLI
GitHub
http://127.0.0.1:5000
why that's super important later
the forums
Docker
Flaskinni
Flask-Security plugin
read about them
database schema
Click
https://flask-migrate.readthedocs.io/en/latest/
https://app.netlify.com/drop
https://startbootstrap.com/
https://code.visualstudio.com
Google Fonts
AllTheFreeStock
https://coolors.co
https://colorhunt.co/
Color wheel
CSS cheatsheet
https://color.hailpixel.com
documentation
@media is one I have to repeatedly look up.
jQuery
types of Java primitives
Read more.
public static void selectionSort ( int[] num ){   
    // outer loop stops one early!   
    for ( int i = 0; i < num.length - 1; i++ ){      	
        //initialize the smallest_index    
	int smallest_index = i;        		
	//inner loop locates the smallest after starting one past the outer loop
	for(int j = i + 1; j < num.length; j++) {
	    // if I find a smaller number...
	    if( num[ j ] < num[ smallest_index ] )
	        smallest_index = j;    
	}     	
	// 3 part swap between loops   
	int temp = num[ smallest_index ];         	
	num[ smallest_index ] = num[ i ];     		
	num[ i ] = temp;    
    } // close the otter loop          
} // close the method
public static void insertionSort(int[] nums){
    // outer loop starts one in b/c my inner loop goes bkwrds
    for(int j = 1; j < nums.length; j++){
        // start a weird 3-part-swap by backing up j
        int temp = nums[j];
        // inner loop goes backwards and it's a while loop
        // let's start the counter
        int i = j - 1; 
        // our counter can't go out of bounds AND 
        // the inner loop is looking at a number bigger than temp  
        while( i > -1 &&  nums[i] > temp ) {
           // skoootch numbers over  
           nums[i + 1] = nums[i];
           // move the inner loop counter down
           i--;
        }
        // complete the 3-way-swap, undoing the last i--
        nums[i+1] = temp;
    }
}
interface Sortable {
    void selectionSort(boolean lowToHigh);    
    void insertionSort(boolean lowToHigh);    
}
abstract class IntegerMonster {

  public int[] nums;
  
  public IntegerMonster(int length){
    nums = new int[length];
  }
  
  public void buildRandomArray(){
    for(int i = 0; i < nums.length; i++){
      nums[i] = (int)(Math.random() * 5000);
    }
  }
  
  public abstract void printArray();
  
}
public void recursive(){
    System.out.println("It was a dark and stormy night.");
    recursive();
}
public static void merge(
  int[] a, int[] l, int[] r, int left, int right) {
  
    int i = 0, j = 0, k = 0;
    while (i < left && j < right) {
        if (l[i] <= r[j]) {
            a[k++] = l[i++];
        }
        else {
            a[k++] = r[j++];
        }
    }
    while (i < left) {
        a[k++] = l[i++];
    }
    while (j < right) {
        a[k++] = r[j++];
    }
}
abstract class NameManager {
    /** Core data structure to hold your name list */
    protected ArrayList<String> names;

    /** Adds names to the list until a blank is submitted */
    abstract void buildList();
    
    /** Uses selection shuffle algorithm */
    abstract void shuffle();
    
    /** Sorts the list of names using insertion sort */
    abstract void insertionSort();
    
    /** Sorts the list of names using selection sort */
    abstract void selectionSort();
    
    /** Sorts the list of names using merge sort */
    abstract void mergeSort();
    
    /** Returns a random name from the names list */
    abstract String pickRandom();
}
import java.util.Scanner;

public class StringExplorer
{
	public static void main(String[] args)
	{
      // Count down with a "T minus 5"
      
      // Declare and instantiate a Scanner
    
      // infinite loop 
      
          // take an input
    
          // repeat input + message
    
          // implement "equals" to stop with the word "stop"
          
      
      /*
      ---------------------------
          SAMPLE STUFF
      ---------------------------
      */
  		String sample = "The quick brown fox jumped over the lazy dog.";
  
      // Print the sample and add a blank line after
      System.out.println("OUR SAMPLE:");
  		
      //  Demonstrate the length method.
  		int l = 9999;
  		System.out.println ("sample.length() = " + l);
  
  		//  Demonstrate the indexOf method.
  		int position = 9999;
  		System.out.println ("sample.indexOf(\"quick\") = " + position);
		
      //  Demonstrate the toLowerCase method.
		  String lowerCase = sample.toLowerCase();
		  System.out.println ("sample.toLowerCase() = " + lowerCase);
		  System.out.println ("After toLowerCase(), sample = " + sample);
				
		  //  toUpperCase


      // lastIndexOf


      // substring
      
      
      // equals

	}
}
import java.util.Scanner;


/**
 * A simple class to run the Magpie class.
 * @author Laurie White
 * @version April 2012
 */
public class MagpieRunner
{
	/**
	 * Create a Magpie, give it user input, and print its replies.
	 */
	public static void main(String[] args)
	{
		Magpie maggie = new Magpie();
		
		System.out.println (maggie.getGreeting());
		Scanner in = new Scanner (System.in);
		String statement = in.nextLine();
		
		while (!statement.equals("Bye"))
		{
			System.out.println (maggie.getResponse(statement));
			statement = in.nextLine();
		}
	}
	
}
/**
 * A program to carry on conversations with a human user.
 * This is the initial version that:  
 * <ul><li>

 *       Uses indexOf to find strings
 * </li><li>
 * 		    Handles responding to simple words and phrases 
 * </li></ul>
 * This version uses a nested if to handle default responses.
 * @author Laurie White
 * @version April 2012
 */
public class Magpie
{
	/**
	 * Get a default greeting 	
	 * @return a greeting
	 */
	public String getGreeting()
	{
		return "Hello, let's talk.";
	}
	
	/**
	 * Gives a response to a user statement
	 * 
	 * @param statement
	 *            the user statement
	 * @return a response based on the rules given
	 */
	public String getResponse(String statement)
	{
		String response = "";
		if (statement.indexOf("no") >= 0)
		{
			response = "Why so negative?";
		}
		else if (statement.indexOf("mother") >= 0
				|| statement.indexOf("father") >= 0
				|| statement.indexOf("sister") >= 0
				|| statement.indexOf("brother") >= 0)
		{
			response = "Tell me more about your family.";
		}
		else
		{
			response = getRandomResponse();
		}
		return response;
	}
	
	/**
	 * Pick a default response to use if nothing else fits.
	 * @return a non-committal string
	 */
	private String getRandomResponse()
	{
		final int NUMBER_OF_RESPONSES = 4;
		double r = Math.random();
		int whichResponse = (int)(r * NUMBER_OF_RESPONSES);
		String response = "";
		
		if (whichResponse == 0)
		{
			response = "Interesting, tell me more.";
		}
		else if (whichResponse == 1)
		{
			response = "Hmmm.";
		}
		else if (whichResponse == 2)
		{
			response = "Do you really think so?";
		}
		else if (whichResponse == 3)
		{
			response = "You don't say.";
		}
		
		return response;
	}
}
/**
 * Search for one word in phrase. The search is not case
 * sensitive. This method will check that the given goal
 * is not a substring of a longer string (so, for
 * example, "I know" does not contain "no").
 *
 * @param statement the string to search
 * @param goal the string to search for
 * @param startPos the character of the string to begin the search at
 * @return the index of the first occurrence of goal in
 *         statement or -1 if it's not found
 */
private int findKeyword(String statement, String goal,
		int startPos)
{
	String phrase = statement.trim().toLowerCase();
	goal = goal.toLowerCase();

	// The only change to incorporate the startPos is in
	// the line below
	int psn = phrase.indexOf(goal, startPos);

	// Refinement--make sure the goal isn't part of a
	// word
	while (psn >= 0)
	{
		// Find the string of length 1 before and after
		// the word
		String before = " ", after = " ";
		if (psn > 0)
		{
			before = phrase.substring(psn - 1, psn);
		}
		if (psn + goal.length() < phrase.length())
		{
			after = phrase.substring(
					psn + goal.length(),
					psn + goal.length() + 1);
		}

		// If before and after aren't letters, we've
		// found the word
		if (((before.compareTo("a") < 0) || (before
				.compareTo("z") > 0)) // before is not a
										// letter
				&& ((after.compareTo("a") < 0) || (after
						.compareTo("z") > 0)))
		{
			return psn;
		}

		// The last position didn't work, so let's find
		// the next, if there is one.
		psn = phrase.indexOf(goal, psn + 1);

	}

	return -1;
}

/**
 * Search for one word in phrase. The search is not case
 * sensitive. This method will check that the given goal
 * is not a substring of a longer string (so, for
 * example, "I know" does not contain "no"). The search
 * begins at the beginning of the string.
 * 
 * @param statement
 *            the string to search
 * @param goal
 *            the string to search for
 * @return the index of the first occurrence of goal in
 *         statement or -1 if it's not found
 */
private int findKeyword(String statement, String goal)
{
	return findKeyword(statement, goal, 0);
}
		// Responses which require transformations
		else if (findKeyword(statement, "I want to", 0) >= 0)
		{
			response = transformIWantToStatement(statement);
		}

		else
		{
			// Look for a two word (you <something> me)
			// pattern
			int psn = findKeyword(statement, "you", 0);

			if (psn >= 0
					&& findKeyword(statement, "me", psn) >= 0)
			{
				response = transformYouMeStatement(statement);
			}
			else
			{
				response = getRandomResponse();
			}
		}
	/**
	 * Take a statement with "I want to <something>." and transform it into 
	 * "What would it mean to <something>?"
	 * @param statement the user statement, assumed to contain "I want to"
	 * @return the transformed statement
	 */
	private String transformIWantToStatement(String statement)
	{
		//  Remove the final period, if there is one
		statement = statement.trim();
		String lastChar = statement.substring(statement
				.length() - 1);
		if (lastChar.equals("."))
		{
			statement = statement.substring(0, statement
					.length() - 1);
		}
		int psn = findKeyword (statement, "I want to", 0);
		String restOfStatement = statement.substring(psn + 9).trim();
		return "What would it mean to " + restOfStatement + "?";
	}

	
	
	/**
	 * Take a statement with "you <something> me" and transform it into 
	 * "What makes you think that I <something> you?"
	 * @param statement the user statement, assumed to contain "you" followed by "me"
	 * @return the transformed statement
	 */
	private String transformYouMeStatement(String statement)
	{
		//  Remove the final period, if there is one
		statement = statement.trim();
		String lastChar = statement.substring(statement
				.length() - 1);
		if (lastChar.equals("."))
		{
			statement = statement.substring(0, statement
					.length() - 1);
		}
		
		int psnOfYou = findKeyword (statement, "you", 0);
		int psnOfMe = findKeyword (statement, "me", psnOfYou + 3);
		
		String restOfStatement = statement.substring(psnOfYou + 3, psnOfMe).trim();
		return "What makes you think that I " + restOfStatement + " you?";
	}
	
	
public class Drills{
	
	public static void main(String[] args){
	
		// Declare 5 different data types with initial values
		
		// A standard for loop printing a message three times
		
		// A for-each loop traversing a String[array]
		
		// An infinite loop
		
			// a short-circut conditional with four tests
		
				// Break a loop if a conditional passes
		
		// Loop through each char in a String
				
		// Print only the first three letters in “word”
		
		// Print all the odd numbers from 1 - 100
		
		// Create a Scanner and take an input
		
		// Create a Scanner, take a number, and count down from that number to 0
		
	}
	
	// Create a method that returns a comparison (include a JavaDoc comment)
	
}
///Bounce against walls

move_bounce_all(true);
move_outside_all(direction, 100);
    // add to your settings.json file in VSCode if you choose to liveSassCompile
    "liveSassCompile.settings.includeItems": [
        "/app/static/scss/custom.scss"
    ],
    "liveSassCompile.settings.generateMap": false,
    "liveSassCompile.settings.formats":[
        {
            "format": "compressed",
            "extensionName": ".min.css",
            "savePath": "/app/static/css/"
        }
    ]
169KB
Magpie Lab Student Guide_updated_Sept_2014.pdf
pdf
Student Guide from College Board
LogoDownload PythonPython.org
What version should you install? Whichever is the most stable on an Ubuntu server.
LogoPostgreSQL: Downloads
LogoGitHub DesktopGitHub Desktop
LogoGetting started | npm Docs
LogoSass: Install Sass
https://code.visualstudio.comcode.visualstudio.com
You may have different things to fix than shown in this video, but I hope it shows the process to follow
Logoloading.io - Your SVG + GIF + PNG Ajax Loading Icons and Animation Generatorloadingio
Don't have a loading GIF? Use this and give them credit in your code!
Guide to setting up the software needed for class
LogoEasily Make Video Games with GameMaker Studio 2YoYo Games
LogoGitHub DesktopGitHub Desktop
The great Richard Feynman addresses acceptable levels of abstraction, though he doesn't call it such
Gilmour Academy
Flaskinni open-source project
4: Install Flaskinni
REST API
GraphQL
Pretty Printed
The Flask Mega-Tutorial by (the great) Miguel Grinberg
Codecademy
SoloLearn
Digital Ocean
Heroku
Official Flask Documentation
JavaScript on Udemy
Code Combat
CodeSignal
Flask by Miguel Grinberg
Fluent Python
article
Baeldung
official documentation
they're overloaded
Game 1: sprites and sound resources
wireframes
paid themes
free themes
Bootstrap
Sass
http://coolors.co
https://color.adobe.com/create/color-wheel/
https://colors.eva.design/
http://designmodo.github.io/Flat-UI/
startbootstrap
Sass structure
http://fonts.google.com
http://graphicriver.net
http://allthefreestock.com/
HERE
next chapter

Class Overview

Expectations

We will be learning programming concepts using GameMaker Studio 2's drag and drop interface as well as some simple GML code. All the concepts will be taught through the creation of games. Through PowerPoint instructions, you will be able to work at your own pace and return to concepts which might be confusing.

Mr. Vanek will be available to help if you have bugs that crop up in your programming and to clarify points in the tutorials.

In each unit, you will be responsible for completing an assignment which builds on the concepts you have learned. Feel free to flex your creative design muscles, especially in the assignment portion of the game. Adding extra features or finding new ways to accomplish them will help your game and your learning.

For the final project of the semester, you will be developing your own game. If you have good ideas for the form the game may take during the course of the semester, be sure to write them down.

This example doesn't use Sass. Not great.

6: Inheritance & Algorithms

We introduce our first complex algorithms and start to pull back the scaffolding a bit. Students will get their first real experience designing aggregate objects with encapsulated properties.

Learning Targets

  • I can secure my class variables with encapsulation.

  • I can create a constructor to initialize an object.

  • I can override a parent method.

  • I can build unit tests for all methods in an aggregate object.

Inheritance

Keep it DRY and OOP-y

DRY stands for Don't Repeat Yourself. So far, that's meant that if you need to repeat a bit of code, you make a loop instead of sloppily copying and pasting the same commands a few times. Now we're seeing that OOP, or Object-Oriented Programming, has was to build classes off of one another. That means we can avoid repeating (aka DRY code) by using inheritance.

Abstract Classes

Polymorphism Practice

Polymorphism is my favorite CS term because it sounds so much fancier than it really is (sort of a theme here). In class we'll build an abstract class called Shape with some encaspulated instance variables like length and width, abstract methods like .area(). Then we'll inherit from those methods when we create types of shapes like Circle, Rectangle, Triangle and so on. Let's look closer at why this is an example of inheritance and polymorphism.

Why this is smart, object-oriented programming

Creating a parent class called Shape that all your shapes will inherit means that the common properties and functions can live in one place. If new features or changes needed to happen across all the elements in your app, you would have a logical place to check.

But why do we declare abstract methods?

Let's take a look at a shortened Shape class:

class Shape {
    
    // a single example encaspulated instance variable
    private float length;
    
    // accessor method
    public float length(){
        // using this. is not required but helpful when writing
        return this.length; 
    
    // mutator method
    public void length(float length){
        // now using this. is required to tell the local and instance var apart
        this.length = length;

    // example abstract method. Each shape will need to make or "implement" 
    pubilc abstract float area();
        
}

All the encapsulation shown between lines 3 - 14 should be familiar by now. Seek additional practice including your teacher's office hours if not. The cool new thing here is line 17. Because the parent is declaring this method, all its children (i.e class Circle extends Shape { )will have to build their own area method. The Circle class will return 3.14 * (length * length); for its area() implementation.

So how exactly is this business "polymorphic?"

Because all of my app's shapes will have a common parent, I can create a collection of Shape like: ArrayList<Shape> myShapes = new ArrayList<>();

That allows me to to loop through the whole collection and report out their areas:

for (Shape x : myShapes) {
    System.out.println("This shape's area is: " + x.area() + " cm2");
}

Multiple Inheritance?

What if I wanted to build a huge space game with thousands of types of ships. I'd make rules for cargo ships and warships. There may be times when I want multiple inheritances to be applied. Well there are some limits here in Java. You can have multiple vertical levels, like Ship --> Warship --> Battleship but a single ship can't inherit from two places simultaneously. Instead, there are Interfaces.

Elevens

Please download the guide to this old project from CollegeBoard.

538KB
AP_CompSciA_Elevens_Lab_Student_Guide.pdf
pdf
Elevens Lab Student Guide

Elevens 1

Let's create a simple Card object and test its encapsulated properties.

/**

 * This is a class that tests the Card class.
 */
public class CardTester {

	/**
	 * The main method in this class checks the Card operations for consistency.
	 *	@param args is not used.
	 */
	public static void main(String[] args) {
		/* *** TO BE IMPLEMENTED IN ACTIVITY 1 *** */
	}
}
/**

 * Card.java
 *
 * <code>Card</code> represents a playing card.
 */
public class Card {

	/**
	 * String value that holds the suit of the card
	 */
	private String suit;

	/**
	 * String value that holds the rank of the card
	 */
	private String rank;

	/**
	 * int value that holds the point value.
	 */
	private int pointValue;


   /**
	 * Creates a new <code>Card</code> instance.
	 *
	 * @param cardRank  a <code>String</code> value
	 *                  containing the rank of the card
	 * @param cardSuit  a <code>String</code> value
	 *                  containing the suit of the card
	 * @param cardPointValue an <code>int</code> value
	 *                  containing the point value of the card
	 */
	public Card(String cardRank, String cardSuit, int cardPointValue) {
		/* *** TO BE IMPLEMENTED IN ACTIVITY 1 *** */
	}


	/**
	 * Accesses this <code>Card's</code> suit.
	 * @return this <code>Card's</code> suit.
	 */
	public String suit() {
		/* *** TO BE IMPLEMENTED IN ACTIVITY 1 *** */
   }

	/**
	 * Accesses this <code>Card's</code> rank.
	 * @return this <code>Card's</code> rank.
	 */
	public String rank() {
		/* *** TO BE IMPLEMENTED IN ACTIVITY 1 *** */
	}

   /**
	 * Accesses this <code>Card's</code> point value.
	 * @return this <code>Card's</code> point value.
	 */
	public int pointValue() {
		/* *** TO BE IMPLEMENTED IN ACTIVITY 1 *** */
	}

	/** Compare this card with the argument.
	 * @param otherCard the other card to compare to this
	 * @return true if the rank, suit, and point value of this card
	 *              are equal to those of the argument;
	 *         false otherwise.
	 */
	public boolean matches(Card otherCard) {
		/* *** TO BE IMPLEMENTED IN ACTIVITY 1 *** */
	}

	/**
	 * Converts the rank, suit, and point value into a string in the format
	 *     "[Rank] of [Suit] (point value = [PointValue])".
	 * This provides a useful way of printing the contents
	 * of a <code>Deck</code> in an easily readable format or performing
	 * other similar functions.
	 *
	 * @return a <code>String</code> containing the rank, suit,
	 *         and point value of the card.
	 */
	@Override
	public String toString() {
		/* *** TO BE IMPLEMENTED IN ACTIVITY 1 *** */
	}
}
import java.util.List;
import java.util.ArrayList;

/**
 * The ThirteensBoard class represents the board in a game of Thirteens.
 */
public class ThirteensBoard extends Board {

	/**
	 * The size (number of cards) on the board.
	 */
	private static final int BOARD_SIZE = 10;

	/**
	 * The ranks of the cards for this game to be sent to the deck.
	 */
	private static final String[] RANKS =
		{"ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "jack", "queen", "king"};

	/**
	 * The suits of the cards for this game to be sent to the deck.
	 */
	private static final String[] SUITS =
		{"spades", "hearts", "diamonds", "clubs"};

	/**
	 * The values of the cards for this game to be sent to the deck.
	 */
	private static final int[] POINT_VALUES =
		{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0};

	/**
	 * Flag used to control debugging print statements.
	 */
	private static final boolean I_AM_DEBUGGING = false;


	/**
	 * Creates a new <code>ThirteensBoard</code> instance.
	 */
	 public ThirteensBoard() {
	 	super(BOARD_SIZE, RANKS, SUITS, POINT_VALUES);
	 }

	/**
	 * Determines if the selected cards form a valid group for removal.
	 * In Thirteens, the legal groups are (1) a pair of non-face cards
	 * whose values add to 13, and (2) a king.
	 * @param selectedCards the list of the indices of the selected cards.
	 * @return true if the selected cards form a valid group for removal;
	 *         false otherwise.
	 */
	@Override
	public boolean isLegal(List<Integer> selectedCards) {
		if (selectedCards.size() == 1) {
			return findKing(selectedCards).size() > 0;
		} else if (selectedCards.size() == 2) {
			return findPairSum13(selectedCards).size() > 0;
		} else {
			return false;
		}
	}

	/**
	 * Determine if there are any legal plays left on the board.
	 * In Thirteens, there is a legal play if the board contains
	 * (1) a pair of non-face cards whose values add to 13, or (2) a king.
	 * @return true if there is a legal play left on the board;
	 *         false otherwise.
	 */
	@Override
	public boolean anotherPlayIsPossible() {
		List<Integer> cIndexes = cardIndexes();
		return findPairSum13(cIndexes).size() > 0
			 || findKing(cIndexes).size() > 0;
	}

	/**
	 * Look for an 13-pair in the selected cards.
	 * @param selectedCards selects a subset of this board.  It is list
	 *                      of indexes into this board that are searched
	 *                      to find an 13-pair.
	 * @return a list of the indexes of an 13-pair, if an 13-pair was found;
	 *         an empty list, if an 13-pair was not found.
	 */
	private List<Integer> findPairSum13(List<Integer> selectedCards) {
		List<Integer> foundIndexes = new ArrayList<Integer>();
		for (int sk1 = 0; sk1 < selectedCards.size(); sk1++) {
			int k1 = selectedCards.get(sk1).intValue();
			for (int sk2 = sk1 + 1; sk2 < selectedCards.size(); sk2++) {
				int k2 = selectedCards.get(sk2).intValue();
				if (cardAt(k1).pointValue() + cardAt(k2).pointValue() == 13) {
					foundIndexes.add(new Integer(k1));
					foundIndexes.add(new Integer(k2));
					return foundIndexes;
				}
			}
		}
		return foundIndexes;
	}

	/**
	 * Look for a king in the selected cards.
	 * @param selectedCards selects a subset of this board.  It is list
	 *                      of indexes into this board that are searched
	 *                      to find a king.
	 * @return a list of the index of a king, if a king was found;
	 *         an empty list, if a king was not found.
	 */
	private List<Integer> findKing(List<Integer> selectedCards) {
		List<Integer> foundIndexes = new ArrayList<Integer>();
		for (Integer kObj : selectedCards) {
			int k = kObj.intValue();
			if (cardAt(k).rank().equals("king")) {
				foundIndexes.add(new Integer(k));
				return foundIndexes;
			}
		}
		return foundIndexes;
	}

	/**
	 * Looks for a legal play on the board.  If one is found, it plays it.
	 * @return true if a legal play was found (and made); false othewise.
	 */
	public boolean playIfPossible() {
		return playPairSum13IfPossible() || playKingIfPossible();
	}

	/**
	 * Looks for a pair of non-face cards whose values sum to 13.
	 * If found, replace them with the next two cards in the deck.
	 * The simulation of this game uses this method.
	 * @return true if an 13-pair play was found (and made); false othewise.
	 */
	private boolean playPairSum13IfPossible() {
		List<Integer> foundIndexes = cardIndexes();
		List<Integer> cardsToReplace = findPairSum13(foundIndexes);
		if (cardsToReplace.size() > 0) {
			replaceSelectedCards(cardsToReplace);
			if (I_AM_DEBUGGING) {
				System.out.println("13-Pair removed.\n");
			}
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Looks for a King.
	 * If found, replace it with the next card in the deck.
	 * The simulation of this game uses this method.
	 * @return true if a king play was found (and made); false othewise.
	 */
	private boolean playKingIfPossible() {
		List<Integer> foundIndexes = cardIndexes();
		List<Integer> cardsToReplace = findKing(foundIndexes);
		if (cardsToReplace.size() > 0) {
			replaceSelectedCards(cardsToReplace);
			if (I_AM_DEBUGGING) {
				System.out.println("King removed.\n");
			}
			return true;
		} else {
			return false;
		}
	}
}
import java.util.List;
import java.util.ArrayList;

/**
 * The ElevensBoard class represents the board in a game of Elevens.
 */
public class ElevensBoard extends Board {

	/**
	 * The size (number of cards) on the board.
	 */
	private static final int BOARD_SIZE = 9;

	/**
	 * The ranks of the cards for this game to be sent to the deck.
	 */
	private static final String[] RANKS =
		{"ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "jack", "queen", "king"};

	/**
	 * The suits of the cards for this game to be sent to the deck.
	 */
	private static final String[] SUITS =
		{"spades", "hearts", "diamonds", "clubs"};

	/**
	 * The values of the cards for this game to be sent to the deck.
	 */
	private static final int[] POINT_VALUES =
		{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0};

	/**
	 * Flag used to control debugging print statements.
	 */
	private static final boolean I_AM_DEBUGGING = true;


	/**
	 * Creates a new <code>ElevensBoard</code> instance.
	 */
	 public ElevensBoard() {
	 	super(BOARD_SIZE, RANKS, SUITS, POINT_VALUES);
	 }

	/**
	 * Determines if the selected cards form a valid group for removal.
	 * In Elevens, the legal groups are (1) a pair of non-face cards
	 * whose values add to 11, and (2) a group of three cards consisting of
	 * a jack, a queen, and a king in some order.
	 * @param selectedCards the list of the indices of the selected cards.
	 * @return true if the selected cards form a valid group for removal;
	 *         false otherwise.
	 */
	@Override
	public boolean isLegal(List<Integer> selectedCards) {
		if (selectedCards.size() == 2) {
			return findPairSum11(selectedCards).size() > 0;
		} else if (selectedCards.size() == 3) {
			return findJQK(selectedCards).size() > 0;
		} else {
			return false;
		}
	}

	/**
	 * Determine if there are any legal plays left on the board.
	 * In Elevens, there is a legal play if the board contains
	 * (1) a pair of non-face cards whose values add to 11, or (2) a group
	 * of three cards consisting of a jack, a queen, and a king in some order.
	 * @return true if there is a legal play left on the board;
	 *         false otherwise.
	 */
	@Override
	public boolean anotherPlayIsPossible() {
		List<Integer> cIndexes = cardIndexes();
		return findPairSum11(cIndexes).size() > 0
			 || findJQK(cIndexes).size() > 0;
	}

	/**
	 * Look for an 11-pair in the selected cards.
	 * @param selectedCards selects a subset of this board.  It is list
	 *                      of indexes into this board that are searched
	 *                      to find an 11-pair.
	 * @return a list of the indexes of an 11-pair, if an 11-pair was found;
	 *         an empty list, if an 11-pair was not found.
	 */
	private List<Integer> findPairSum11(List<Integer> selectedCards) {
		List<Integer> foundIndexes = new ArrayList<Integer>();
		for (int sk1 = 0; sk1 < selectedCards.size(); sk1++) {
			int k1 = selectedCards.get(sk1).intValue();
			for (int sk2 = sk1 + 1; sk2 < selectedCards.size(); sk2++) {
				int k2 = selectedCards.get(sk2).intValue();
				if (cardAt(k1).pointValue() + cardAt(k2).pointValue() == 11) {
					foundIndexes.add(new Integer(k1));
					foundIndexes.add(new Integer(k2));
					return foundIndexes;
				}
			}
		}
		return foundIndexes;
	}

	/**
	 * Look for a JQK in the selected cards.
	 * @param selectedCards selects a subset of this board.  It is list
	 *                      of indexes into this board that are searched
	 *                      to find a JQK group.
	 * @return a list of the indexes of a JQK, if a JQK was found;
	 *         an empty list, if a JQK was not found.
	 */
	private List<Integer> findJQK(List<Integer> selectedCards) {
		List<Integer> foundIndexes = new ArrayList<Integer>();
		int jackIndex = -1;
		int queenIndex = -1;
		int kingIndex = -1;
		for (Integer kObj : selectedCards) {
			int k = kObj.intValue();
			if (cardAt(k).rank().equals("jack")) {
				jackIndex = k;
			} else if (cardAt(k).rank().equals("queen")) {
				queenIndex = k;
			} else if (cardAt(k).rank().equals("king")) {
				kingIndex = k;
			}
		}
		if (jackIndex != -1 && queenIndex != -1 && kingIndex != -1) {
			foundIndexes.add(new Integer(jackIndex));
			foundIndexes.add(new Integer(queenIndex));
			foundIndexes.add(new Integer(kingIndex));
		}
		return foundIndexes;
	}

	/**
	 * Looks for a legal play on the board.  If one is found, it plays it.
	 * @return true if a legal play was found (and made); false othewise.
	 */
	public boolean playIfPossible() {
		return playPairSum11IfPossible() || playJQKIfPossible();
	}

	/**
	 * Looks for a pair of non-face cards whose values sum to 11.
	 * If found, replace them with the next two cards in the deck.
	 * The simulation of this game uses this method.
	 * @return true if an 11-pair play was found (and made); false othewise.
	 */
	private boolean playPairSum11IfPossible() {
		List<Integer> foundIndexes = cardIndexes();
		List<Integer> cardsToReplace = findPairSum11(foundIndexes);
		if (cardsToReplace.size() > 0) {
			replaceSelectedCards(cardsToReplace);
			if (I_AM_DEBUGGING) {
				System.out.println("11-Pair removed.\n");
			}
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Looks for a group of three face cards JQK.
	 * If found, replace them with the next three cards in the deck.
	 * The simulation of this game uses this method.
	 * @return true if a JQK play was found (and made); false othewise.
	 */
	private boolean playJQKIfPossible() {
		List<Integer> foundIndexes = cardIndexes();
		List<Integer> cardsToReplace = findJQK(foundIndexes);
		if (cardsToReplace.size() > 0) {
			replaceSelectedCards(cardsToReplace);
						if (I_AM_DEBUGGING) {
				System.out.println("JQK-Triplet removed.\n");
			}
			return true;
		} else {
			return false;
		}
	}
}
import java.awt.Point;
import java.awt.Graphics;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Color;
import java.awt.Toolkit;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
import java.net.URL;
import java.util.List;
import java.util.ArrayList;

/**
 * This class provides a GUI for solitaire games related to Elevens.
 */
public class CardGameGUI extends JFrame implements ActionListener {

	/** Height of the game frame. */
	private static final int DEFAULT_HEIGHT = 302;
	/** Width of the game frame. */
	private static final int DEFAULT_WIDTH = 800;
	/** Width of a card. */
	private static final int CARD_WIDTH = 73;
	/** Height of a card. */
	private static final int CARD_HEIGHT = 97;
	/** Row (y coord) of the upper left corner of the first card. */
	private static final int LAYOUT_TOP = 30;
	/** Column (x coord) of the upper left corner of the first card. */
	private static final int LAYOUT_LEFT = 30;
	/** Distance between the upper left x coords of
	 *  two horizonally adjacent cards. */
	private static final int LAYOUT_WIDTH_INC = 100;
	/** Distance between the upper left y coords of
	 *  two vertically adjacent cards. */
	private static final int LAYOUT_HEIGHT_INC = 125;
	/** y coord of the "Replace" button. */
	private static final int BUTTON_TOP = 30;
	/** x coord of the "Replace" button. */
	private static final int BUTTON_LEFT = 570;
	/** Distance between the tops of the "Replace" and "Restart" buttons. */
	private static final int BUTTON_HEIGHT_INC = 50;
	/** y coord of the "n undealt cards remain" label. */
	private static final int LABEL_TOP = 160;
	/** x coord of the "n undealt cards remain" label. */
	private static final int LABEL_LEFT = 540;
	/** Distance between the tops of the "n undealt cards" and
	 *  the "You lose/win" labels. */
	private static final int LABEL_HEIGHT_INC = 35;

	/** The board (Board subclass). */
	private Board board;

	/** The main panel containing the game components. */
	private JPanel panel;
	/** The Replace button. */
	private JButton replaceButton;
	/** The Restart button. */
	private JButton restartButton;
	/** The "number of undealt cards remain" message. */
	private JLabel statusMsg;
	/** The "you've won n out of m games" message. */
	private JLabel totalsMsg;
	/** The card displays. */
	private JLabel[] displayCards;
	/** The win message. */
	private JLabel winMsg;
	/** The loss message. */
	private JLabel lossMsg;
	/** The coordinates of the card displays. */
	private Point[] cardCoords;

	/** kth element is true iff the user has selected card #k. */
	private boolean[] selections;
	/** The number of games won. */
	private int totalWins;
	/** The number of games played. */
	private int totalGames;


	/**
	 * Initialize the GUI.
	 * @param gameBoard is a <code>Board</code> subclass.
	 */
	public CardGameGUI(Board gameBoard) {
		board = gameBoard;
		totalWins = 0;
		totalGames = 0;

		// Initialize cardCoords using 5 cards per row
		cardCoords = new Point[board.size()];
		int x = LAYOUT_LEFT;
		int y = LAYOUT_TOP;
		for (int i = 0; i < cardCoords.length; i++) {
			cardCoords[i] = new Point(x, y);
			if (i % 5 == 4) {
				x = LAYOUT_LEFT;
				y += LAYOUT_HEIGHT_INC;
			} else {
				x += LAYOUT_WIDTH_INC;
			}
		}

		selections = new boolean[board.size()];
		initDisplay();
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		repaint();
	}

	/**
	 * Run the game.
	 */
	public void displayGame() {
		java.awt.EventQueue.invokeLater(new Runnable() {
			public void run() {
				setVisible(true);
			}
		});
	}

	/**
	 * Draw the display (cards and messages).
	 */
	public void repaint() {
		for (int k = 0; k < board.size(); k++) {
			String cardImageFileName =
				imageFileName(board.cardAt(k), selections[k]);
			URL imageURL = getClass().getResource(cardImageFileName);
			if (imageURL != null) {
				ImageIcon icon = new ImageIcon(imageURL);
				displayCards[k].setIcon(icon);
				displayCards[k].setVisible(true);
			} else {
				throw new RuntimeException(
					"Card image not found: \"" + cardImageFileName + "\"");
			}
		}
		statusMsg.setText(board.deckSize()
			+ " undealt cards remain.");
		statusMsg.setVisible(true);
		totalsMsg.setText("You've won " + totalWins
			 + " out of " + totalGames + " games.");
		totalsMsg.setVisible(true);
		pack();
		panel.repaint();
	}

	/**
	 * Initialize the display.
	 */
	private void initDisplay()	{
		panel = new JPanel() {
			public void paintComponent(Graphics g) {
				super.paintComponent(g);
			}
		};

		// If board object's class name follows the standard format
		// of ...Board or ...board, use the prefix for the JFrame title
		String className = board.getClass().getSimpleName();
		int classNameLen = className.length();
		int boardLen = "Board".length();
		String boardStr = className.substring(classNameLen - boardLen);
		if (boardStr.equals("Board") || boardStr.equals("board")) {
			int titleLength = classNameLen - boardLen;
			setTitle(className.substring(0, titleLength));
		}

		// Calculate number of rows of cards (5 cards per row)
		// and adjust JFrame height if necessary
		int numCardRows = (board.size() + 4) / 5;
		int height = DEFAULT_HEIGHT;
		if (numCardRows > 2) {
			height += (numCardRows - 2) * LAYOUT_HEIGHT_INC;
		}

		this.setSize(new Dimension(DEFAULT_WIDTH, height));
		panel.setLayout(null);
		panel.setPreferredSize(
			new Dimension(DEFAULT_WIDTH - 20, height - 20));
		displayCards = new JLabel[board.size()];
		for (int k = 0; k < board.size(); k++) {
			displayCards[k] = new JLabel();
			panel.add(displayCards[k]);
			displayCards[k].setBounds(cardCoords[k].x, cardCoords[k].y,
										CARD_WIDTH, CARD_HEIGHT);
			displayCards[k].addMouseListener(new MyMouseListener());
			selections[k] = false;
		}
		replaceButton = new JButton();
		replaceButton.setText("Replace");
		panel.add(replaceButton);
		replaceButton.setBounds(BUTTON_LEFT, BUTTON_TOP, 100, 30);
		replaceButton.addActionListener(this);

		restartButton = new JButton();
		restartButton.setText("Restart");
		panel.add(restartButton);
		restartButton.setBounds(BUTTON_LEFT, BUTTON_TOP + BUTTON_HEIGHT_INC,
										100, 30);
		restartButton.addActionListener(this);

		statusMsg = new JLabel(
			board.deckSize() + " undealt cards remain.");
		panel.add(statusMsg);
		statusMsg.setBounds(LABEL_LEFT, LABEL_TOP, 250, 30);

		winMsg = new JLabel();
		winMsg.setBounds(LABEL_LEFT, LABEL_TOP + LABEL_HEIGHT_INC, 200, 30);
		winMsg.setFont(new Font("SansSerif", Font.BOLD, 25));
		winMsg.setForeground(Color.GREEN);
		winMsg.setText("You win!");
		panel.add(winMsg);
		winMsg.setVisible(false);

		lossMsg = new JLabel();
		lossMsg.setBounds(LABEL_LEFT, LABEL_TOP + LABEL_HEIGHT_INC, 200, 30);
		lossMsg.setFont(new Font("SanSerif", Font.BOLD, 25));
		lossMsg.setForeground(Color.RED);
		lossMsg.setText("Sorry, you lose.");
		panel.add(lossMsg);
		lossMsg.setVisible(false);

		totalsMsg = new JLabel("You've won " + totalWins
			+ " out of " + totalGames + " games.");
		totalsMsg.setBounds(LABEL_LEFT, LABEL_TOP + 2 * LABEL_HEIGHT_INC,
								  250, 30);
		panel.add(totalsMsg);

		if (!board.anotherPlayIsPossible()) {
			signalLoss();
		}

		pack();
		getContentPane().add(panel);
		getRootPane().setDefaultButton(replaceButton);
		panel.setVisible(true);
	}

	/**
	 * Deal with the user clicking on something other than a button or a card.
	 */
	private void signalError() {
		Toolkit t = panel.getToolkit();
		t.beep();
	}

	/**
	 * Returns the image that corresponds to the input card.
	 * Image names have the format "[Rank][Suit].GIF" or "[Rank][Suit]S.GIF",
	 * for example "aceclubs.GIF" or "8heartsS.GIF". The "S" indicates that
	 * the card is selected.
	 *
	 * @param c Card to get the image for
	 * @param isSelected flag that indicates if the card is selected
	 * @return String representation of the image
	 */
	private String imageFileName(Card c, boolean isSelected) {
		String str = "cards/";
		if (c == null) {
			return "cards/back1.GIF";
		}
		str += c.rank() + c.suit();
		if (isSelected) {
			str += "S";
		}
		str += ".GIF";
		return str;
	}

	/**
	 * Respond to a button click (on either the "Replace" button
	 * or the "Restart" button).
	 * @param e the button click action event
	 */
	public void actionPerformed(ActionEvent e) {
		if (e.getSource().equals(replaceButton)) {
			// Gather all the selected cards.
			List<Integer> selection = new ArrayList<Integer>();
			for (int k = 0; k < board.size(); k++) {
				if (selections[k]) {
					selection.add(new Integer(k));
				}
			}
			// Make sure that the selected cards represent a legal replacement.
			if (!board.isLegal(selection)) {
				signalError();
				return;
			}
			for (int k = 0; k < board.size(); k++) {
				selections[k] = false;
			}
			// Do the replace.
			board.replaceSelectedCards(selection);
			if (board.isEmpty()) {
				signalWin();
			} else if (!board.anotherPlayIsPossible()) {
				signalLoss();
			}
			repaint();
		} else if (e.getSource().equals(restartButton)) {
			board.newGame();
			getRootPane().setDefaultButton(replaceButton);
			winMsg.setVisible(false);
			lossMsg.setVisible(false);
			if (!board.anotherPlayIsPossible()) {
				signalLoss();
				lossMsg.setVisible(true);
			}
			for (int i = 0; i < selections.length; i++) {
				selections[i] = false;
			}
			repaint();
		} else {
			signalError();
			return;
		}
	}

	/**
	 * Display a win.
	 */
	private void signalWin() {
		getRootPane().setDefaultButton(restartButton);
		winMsg.setVisible(true);
		totalWins++;
		totalGames++;
	}

	/**
	 * Display a loss.
	 */
	private void signalLoss() {
		getRootPane().setDefaultButton(restartButton);
		lossMsg.setVisible(true);
		totalGames++;
	}

	/**
	 * Receives and handles mouse clicks.  Other mouse events are ignored.
	 */
	private class MyMouseListener implements MouseListener {

		/**
		 * Handle a mouse click on a card by toggling its "selected" property.
		 * Each card is represented as a label.
		 * @param e the mouse event.
		 */
		public void mouseClicked(MouseEvent e) {
			for (int k = 0; k < board.size(); k++) {
				if (e.getSource().equals(displayCards[k])
						&& board.cardAt(k) != null) {
					selections[k] = !selections[k];
					repaint();
					return;
				}
			}
			signalError();
		}

		/**
		 * Ignore a mouse exited event.
		 * @param e the mouse event.
		 */
		public void mouseExited(MouseEvent e) {
		}

		/**
		 * Ignore a mouse released event.
		 * @param e the mouse event.
		 */
		public void mouseReleased(MouseEvent e) {
		}

		/**
		 * Ignore a mouse entered event.
		 * @param e the mouse event.
		 */
		public void mouseEntered(MouseEvent e) {
		}

		/**
		 * Ignore a mouse pressed event.
		 * @param e the mouse event.
		 */
		public void mousePressed(MouseEvent e) {
		}
	}
}

Elevens 2

Now we'll build our aggregate object, the Deck.

/**
 * This is a class that tests the Deck class.

 */
public class DeckTester {

	/**
	 * The main method in this class checks the Deck operations for consistency.
	 *	@param args is not used.
	 */
	public static void main(String[] args) {
		/* *** TO BE IMPLEMENTED IN ACTIVITY 2 *** */
	}
}
import java.util.List;
import java.util.ArrayList;

/**
 * The Deck class represents a shuffled deck of cards.
 * It provides several operations including
 *      initialize, shuffle, deal, and check if empty.
 */
public class Deck {

	/**
	 * cards contains all the cards in the deck.
	 */
	private List<Card> cards;

	/**
	 * size is the number of not-yet-dealt cards.
	 * Cards are dealt from the top (highest index) down.
	 * The next card to be dealt is at size - 1.
	 */
	private int size;


	/**
	 * Creates a new <code>Deck</code> instance.<BR>
	 * It pairs each element of ranks with each element of suits,
	 * and produces one of the corresponding card.
	 * @param ranks is an array containing all of the card ranks.
	 * @param suits is an array containing all of the card suits.
	 * @param values is an array containing all of the card point values.
	 */
	public Deck(String[] ranks, String[] suits, int[] values) {
        cards = new ArrayList<Card>();
        for (int j = 0; j < ranks.length; j++) {
            for (String suitString : suits){
                cards.add(new Card(ranks[j], suitString, values[j]));
            }
	}


	/**
	 * Determines if this deck is empty (no undealt cards).
	 * @return true if this deck is empty, false otherwise.
	 */
	public boolean isEmpty() {
		/* *** TO BE IMPLEMENTED IN ACTIVITY 2 *** */
	}

	/**
	 * Accesses the number of undealt cards in this deck.
	 * @return the number of undealt cards in this deck.
	 */
	public int size() {
		/* *** TO BE IMPLEMENTED IN ACTIVITY 2 *** */
	}

	/**
	 * Randomly permute the given collection of cards
	 * and reset the size to represent the entire deck.
	 */
	public void shuffle() {
		/* *** TO BE IMPLEMENTED IN ACTIVITY 4 *** */
	}

	/**
	 * Deals a card from this deck.
	 * @return the card just dealt, or null if all the cards have been
	 *         previously dealt.
	 */
	public Card deal() {
		/* *** TO BE IMPLEMENTED IN ACTIVITY 2 *** */
        // IS EMPTY if so return null
        size--;
        Card c = cards.get(size);
        return c;
	}

	/**
	 * Generates and returns a string representation of this deck.
	 * @return a string representation of this deck.
	 */
	@Override
	public String toString() {
		String rtn = "size = " + size + "\nUndealt cards: \n";

		for (int k = size - 1; k >= 0; k--) {
			rtn = rtn + cards.get(k);
			if (k != 0) {
				rtn = rtn + ", ";
			}
			if ((size - k) % 2 == 0) {
				// Insert carriage returns so entire deck is visible on console.
				rtn = rtn + "\n";
			}
		}

		rtn = rtn + "\nDealt cards: \n";
		for (int k = cards.size() - 1; k >= size; k--) {
			rtn = rtn + cards.get(k);
			if (k != size) {
				rtn = rtn + ", ";
			}
			if ((k - cards.size()) % 2 == 0) {
				// Insert carriage returns so entire deck is visible on console.
				rtn = rtn + "\n";
			}
		}

		rtn = rtn + "\n";
		return rtn;
	}
}

Elevens 3: Shuffling Algorithm

This algorithm uses a lot of structures we'll see when we have to start sorting items rather than shuffling. The problem with a perfect shuffle is that after 4 passes, all the cards are back in the original order.

/**

 * This class provides a convenient way to test shuffling methods.
 */
public class Shuffler {

	/**
	 * The number of consecutive shuffle steps to be performed in each call
	 * to each sorting procedure.
	 */
	private static final int SHUFFLE_COUNT = 1;

	/**
	 * Tests shuffling methods.
	 * @param args is not used.
	 */
	public static void main(String[] args) {
		System.out.println("Results of " + SHUFFLE_COUNT +
								 " consecutive perfect shuffles:");
		int[] values1 = {0, 1, 2, 3};
		for (int j = 1; j <= SHUFFLE_COUNT; j++) {
			perfectShuffle(values1);
			System.out.print("  " + j + ":");
			for (int k = 0; k < values1.length; k++) {
				System.out.print(" " + values1[k]);
			}
			System.out.println();
		}
		System.out.println();

		System.out.println("Results of " + SHUFFLE_COUNT +
								 " consecutive efficient selection shuffles:");
		int[] values2 = {0, 1, 2, 3};
		for (int j = 1; j <= SHUFFLE_COUNT; j++) {
			selectionShuffle(values2);
			System.out.print("  " + j + ":");
			for (int k = 0; k < values2.length; k++) {
				System.out.print(" " + values2[k]);
			}
			System.out.println();
		}
		System.out.println();
	}


	/**
	 * Apply a "perfect shuffle" to the argument.
	 * The perfect shuffle algorithm splits the deck in half, then interleaves
	 * the cards in one half with the cards in the other.
	 * @param values is an array of integers simulating cards to be shuffled.
	 */
	public static void perfectShuffle(int[] values) {
		/* *** TO BE IMPLEMENTED IN ACTIVITY 3 *** */
	}

	/**
	 * Apply an "efficient selection shuffle" to the argument.
	 * The selection shuffle algorithm conceptually maintains two sequences
	 * of cards: the selected cards (initially empty) and the not-yet-selected
	 * cards (initially the entire deck). It repeatedly does the following until
	 * all cards have been selected: randomly remove a card from those not yet
	 * selected and add it to the selected cards.
	 * An efficient version of this algorithm makes use of arrays to avoid
	 * searching for an as-yet-unselected card.
	 * @param values is an array of integers simulating cards to be shuffled.
	 */
	public static void selectionShuffle(int[] values) {
		/* *** TO BE IMPLEMENTED IN ACTIVITY 3 *** */
	}
}

Elevens 4-6

In Activity 4, we'll add the shuffler method to the Deck class. It's the same process but we'll adapt using arrays to ArrayLists. We'll just skip activities 5 and 6 outright as we'll cover that material elsewhere. In case you're curious, the one cool thing we skip over for now is assert statements in Java:

Elevens 7

import java.util.List;
import java.util.ArrayList;

/**
 * This class represents a Board that can be used in a collection
 * of solitaire games similar to Elevens.  The variants differ in
 * card removal and the board size.
 */
public abstract class Board {

	/**
	 * The cards on this board.
	 */
	private Card[] cards;

	/**
	 * The deck of cards being used to play the current game.
	 */
	private Deck deck;

	/**
	 * Flag used to control debugging print statements.
	 */
	private static final boolean I_AM_DEBUGGING = false;

	/**
	 * Creates a new <code>Board</code> instance.
	 * @param size the number of cards in the board
	 * @param ranks the names of the card ranks needed to create the deck
	 * @param suits the names of the card suits needed to create the deck
	 * @param pointValues the integer values of the cards needed to create
	 *                    the deck
	 */
	public Board(int size, String[] ranks, String[] suits, int[] pointValues) {
		cards = new Card[size];
		deck = new Deck(ranks, suits, pointValues);
		if (I_AM_DEBUGGING) {
			System.out.println(deck);
			System.out.println("----------");
		}
		dealMyCards();
	}

	/**
	 * Start a new game by shuffling the deck and
	 * dealing some cards to this board.
	 */
	public void newGame() {
		deck.shuffle();
		dealMyCards();
	}

	/**
	 * Accesses the size of the board.
	 * Note that this is not the number of cards it contains,
	 * which will be smaller near the end of a winning game.
	 * @return the size of the board
	 */
	public int size() {
		return cards.length;
	}

	/**
	 * Determines if the board is empty (has no cards).
	 * @return true if this board is empty; false otherwise.
	 */
	public boolean isEmpty() {
		for (int k = 0; k < cards.length; k++) {
			if (cards[k] != null) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Deal a card to the kth position in this board.
	 * If the deck is empty, the kth card is set to null.
	 * @param k the index of the card to be dealt.
	 */
	public void deal(int k) {
		cards[k] = deck.deal();
	}

	/**
	 * Accesses the deck's size.
	 * @return the number of undealt cards left in the deck.
	 */
	public int deckSize() {
		return deck.size();
	}

	/**
	 * Accesses a card on the board.
	 * @return the card at position k on the board.
	 * @param k is the board position of the card to return.
	 */
	public Card cardAt(int k) {
		return cards[k];
	}

	/**
	 * Replaces selected cards on the board by dealing new cards.
	 * @param selectedCards is a list of the indices of the
	 *        cards to be replaced.
	 */
	public void replaceSelectedCards(List<Integer> selectedCards) {
		for (Integer k : selectedCards) {
			deal(k.intValue());
		}
	}

	/**
	 * Gets the indexes of the actual (non-null) cards on the board.
	 *
	 * @return a List that contains the locations (indexes)
	 *         of the non-null entries on the board.
	 */
	public List<Integer> cardIndexes() {
		List<Integer> selected = new ArrayList<Integer>();
		for (int k = 0; k < cards.length; k++) {
			if (cards[k] != null) {
				selected.add(Integer.valueOf(k));
			}
		}
		return selected;
	}

	/**
	 * Generates and returns a string representation of this board.
	 * @return the string version of this board.
	 */
	public String toString() {
		String s = "";
		for (int k = 0; k < cards.length; k++) {
			s = s + k + ": " + cards[k] + "\n";
		}
		return s;
	}

	/**
	 * Determine whether or not the game has been won,
	 * i.e. neither the board nor the deck has any more cards.
	 * @return true when the current game has been won;
	 *         false otherwise.
	 */
	public boolean gameIsWon() {
		if (deck.isEmpty()) {
			for (Card c : cards) {
				if (c != null) {
					return false;
				}
			}
			return true;
		}
		return false;
	}

	/**
	 * Method to be completed by the concrete class that determines
	 * if the selected cards form a valid group for removal.
	 * @param selectedCards the list of the indices of the selected cards.
	 * @return true if the selected cards form a valid group for removal;
	 *         false otherwise.
	 */
	public abstract boolean isLegal(List<Integer> selectedCards);

	/**
	 * Method to be completed by the concrete class that determines
	 * if there are any legal plays left on the board.
	 * @return true if there is a legal play left on the board;
	 *         false otherwise.
	 */
	public abstract boolean anotherPlayIsPossible();

	/**
	 * Deal cards to this board to start the game.
	 */
	private void dealMyCards() {
		for (int k = 0; k < cards.length; k++) {
			cards[k] = deck.deal();
		}
	}
}
import java.util.List;
import java.util.ArrayList;

/**
 * The ElevensBoard class represents the board in a game of Elevens.
 */
public class ElevensBoard extends Board {

	/**
	 * The size (number of cards) on the board.
	 */
	private static final int BOARD_SIZE = 9;

	/**
	 * The ranks of the cards for this game to be sent to the deck.
	 */
	private static final String[] RANKS =
		{"ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "jack", "queen", "king"};

	/**
	 * The suits of the cards for this game to be sent to the deck.
	 */
	private static final String[] SUITS =
		{"spades", "hearts", "diamonds", "clubs"};

	/**
	 * The values of the cards for this game to be sent to the deck.
	 */
	private static final int[] POINT_VALUES =
		{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0};

	/**
	 * Flag used to control debugging print statements.
	 */
	private static final boolean I_AM_DEBUGGING = true;


	/**
	 * Creates a new <code>ElevensBoard</code> instance.
	 */
	 public ElevensBoard() {
	 	super(BOARD_SIZE, RANKS, SUITS, POINT_VALUES);
	 }

	/**
	 * Determines if the selected cards form a valid group for removal.
	 * In Elevens, the legal groups are (1) a pair of non-face cards
	 * whose values add to 11, and (2) a group of three cards consisting of
	 * a jack, a queen, and a king in some order.
	 * @param selectedCards the list of the indices of the selected cards.
	 * @return true if the selected cards form a valid group for removal;
	 *         false otherwise.
	 */
	@Override
	public boolean isLegal(List<Integer> selectedCards) {
		if (selectedCards.size() == 2) {
			return findPairSum11(selectedCards).size() > 0;
		} else if (selectedCards.size() == 3) {
			return findJQK(selectedCards).size() > 0;
		} else {
			return false;
		}
	}

	/**
	 * Determine if there are any legal plays left on the board.
	 * In Elevens, there is a legal play if the board contains
	 * (1) a pair of non-face cards whose values add to 11, or (2) a group
	 * of three cards consisting of a jack, a queen, and a king in some order.
	 * @return true if there is a legal play left on the board;
	 *         false otherwise.
	 */
	@Override
	public boolean anotherPlayIsPossible() {
		List<Integer> cIndexes = cardIndexes();
		return findPairSum11(cIndexes).size() > 0
			 || findJQK(cIndexes).size() > 0;
	}

	/**
	 * Look for an 11-pair in the selected cards.
	 * @param selectedCards selects a subset of this board.  It is list
	 *                      of indexes into this board that are searched
	 *                      to find an 11-pair.
	 * @return a list of the indexes of an 11-pair, if an 11-pair was found;
	 *         an empty list, if an 11-pair was not found.
	 */
	private List<Integer> findPairSum11(List<Integer> selectedCards) {
		List<Integer> foundIndexes = new ArrayList<Integer>();
		for (int sk1 = 0; sk1 < selectedCards.size(); sk1++) {
			int k1 = selectedCards.get(sk1).intValue();
			for (int sk2 = sk1 + 1; sk2 < selectedCards.size(); sk2++) {
				int k2 = selectedCards.get(sk2).intValue();
				if (cardAt(k1).pointValue() + cardAt(k2).pointValue() == 11) {
					foundIndexes.add(Integer.valueOf(k1));
					foundIndexes.add(Integer.valueOf(k2));
					return foundIndexes;
				}
			}
		}
		return foundIndexes;
	}

	/**
	 * Look for a JQK in the selected cards.
	 * @param selectedCards selects a subset of this board.  It is list
	 *                      of indexes into this board that are searched
	 *                      to find a JQK group.
	 * @return a list of the indexes of a JQK, if a JQK was found;
	 *         an empty list, if a JQK was not found.
	 */
	private List<Integer> findJQK(List<Integer> selectedCards) {
		List<Integer> foundIndexes = new ArrayList<Integer>();
		int jackIndex = -1;
		int queenIndex = -1;
		int kingIndex = -1;
		for (Integer kObj : selectedCards) {
			int k = kObj.intValue();
			if (cardAt(k).rank().equals("jack")) {
				jackIndex = k;
			} else if (cardAt(k).rank().equals("queen")) {
				queenIndex = k;
			} else if (cardAt(k).rank().equals("king")) {
				kingIndex = k;
			}
		}
		if (jackIndex != -1 && queenIndex != -1 && kingIndex != -1) {
			foundIndexes.add(Integer.valueOf(jackIndex));
			foundIndexes.add(Integer.valueOf(queenIndex));
			foundIndexes.add(Integer.valueOf(kingIndex));
		}
		return foundIndexes;
	}

	/**
	 * Looks for a legal play on the board.  If one is found, it plays it.
	 * @return true if a legal play was found (and made); false othewise.
	 */
	public boolean playIfPossible() {
		return playPairSum11IfPossible() || playJQKIfPossible();
	}

	/**
	 * Looks for a pair of non-face cards whose values sum to 11.
	 * If found, replace them with the next two cards in the deck.
	 * The simulation of this game uses this method.
	 * @return true if an 11-pair play was found (and made); false othewise.
	 */
	private boolean playPairSum11IfPossible() {
		List<Integer> foundIndexes = cardIndexes();
		List<Integer> cardsToReplace = findPairSum11(foundIndexes);
		if (cardsToReplace.size() > 0) {
			replaceSelectedCards(cardsToReplace);
			if (I_AM_DEBUGGING) {
				System.out.println("11-Pair removed.\n");
			}
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Looks for a group of three face cards JQK.
	 * If found, replace them with the next three cards in the deck.
	 * The simulation of this game uses this method.
	 * @return true if a JQK play was found (and made); false othewise.
	 */
	private boolean playJQKIfPossible() {
		List<Integer> foundIndexes = cardIndexes();
		List<Integer> cardsToReplace = findJQK(foundIndexes);
		if (cardsToReplace.size() > 0) {
			replaceSelectedCards(cardsToReplace);
						if (I_AM_DEBUGGING) {
				System.out.println("JQK-Triplet removed.\n");
			}
			return true;
		} else {
			return false;
		}
	}
}

Elevens 9

/**
 * This is a class that plays the GUI version of the Elevens game.
 * See accompanying documents for a description of how Elevens is played.
 */
public class ElevensGUIRunner {

	/**
	 * Plays the GUI version of Elevens.
	 * @param args is not used.
	 */
	public static void main(String[] args) {
		Board board = new ElevensBoard();
		CardGameGUI gui = new CardGameGUI(board);
		gui.displayGame();
	}
}
import java.awt.Point;
import java.awt.Graphics;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Color;
import java.awt.Toolkit;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
import java.net.URL;
import java.util.List;
import java.util.ArrayList;

/**
 * This class provides a GUI for solitaire games related to Elevens.
 */
public class CardGameGUI extends JFrame implements ActionListener {

	/** Height of the game frame. */
	private static final int DEFAULT_HEIGHT = 302;
	/** Width of the game frame. */
	private static final int DEFAULT_WIDTH = 800;
	/** Width of a card. */
	private static final int CARD_WIDTH = 73;
	/** Height of a card. */
	private static final int CARD_HEIGHT = 97;
	/** Row (y coord) of the upper left corner of the first card. */
	private static final int LAYOUT_TOP = 30;
	/** Column (x coord) of the upper left corner of the first card. */
	private static final int LAYOUT_LEFT = 30;
	/** Distance between the upper left x coords of
	 *  two horizonally adjacent cards. */
	private static final int LAYOUT_WIDTH_INC = 100;
	/** Distance between the upper left y coords of
	 *  two vertically adjacent cards. */
	private static final int LAYOUT_HEIGHT_INC = 125;
	/** y coord of the "Replace" button. */
	private static final int BUTTON_TOP = 30;
	/** x coord of the "Replace" button. */
	private static final int BUTTON_LEFT = 570;
	/** Distance between the tops of the "Replace" and "Restart" buttons. */
	private static final int BUTTON_HEIGHT_INC = 50;
	/** y coord of the "n undealt cards remain" label. */
	private static final int LABEL_TOP = 160;
	/** x coord of the "n undealt cards remain" label. */
	private static final int LABEL_LEFT = 540;
	/** Distance between the tops of the "n undealt cards" and
	 *  the "You lose/win" labels. */
	private static final int LABEL_HEIGHT_INC = 35;

	/** The board (Board subclass). */
	private Board board;

	/** The main panel containing the game components. */
	private JPanel panel;
	/** The Replace button. */
	private JButton replaceButton;
	/** The Restart button. */
	private JButton restartButton;
	/** The "number of undealt cards remain" message. */
	private JLabel statusMsg;
	/** The "you've won n out of m games" message. */
	private JLabel totalsMsg;
	/** The card displays. */
	private JLabel[] displayCards;
	/** The win message. */
	private JLabel winMsg;
	/** The loss message. */
	private JLabel lossMsg;
	/** The coordinates of the card displays. */
	private Point[] cardCoords;

	/** kth element is true iff the user has selected card #k. */
	private boolean[] selections;
	/** The number of games won. */
	private int totalWins;
	/** The number of games played. */
	private int totalGames;


	/**
	 * Initialize the GUI.
	 * @param gameBoard is a <code>Board</code> subclass.
	 */
	public CardGameGUI(Board gameBoard) {
		board = gameBoard;
		totalWins = 0;
		totalGames = 0;

		// Initialize cardCoords using 5 cards per row
		cardCoords = new Point[board.size()];
		int x = LAYOUT_LEFT;
		int y = LAYOUT_TOP;
		for (int i = 0; i < cardCoords.length; i++) {
			cardCoords[i] = new Point(x, y);
			if (i % 5 == 4) {
				x = LAYOUT_LEFT;
				y += LAYOUT_HEIGHT_INC;
			} else {
				x += LAYOUT_WIDTH_INC;
			}
		}

		selections = new boolean[board.size()];
		initDisplay();
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		repaint();
	}

	/**
	 * Run the game.
	 */
	public void displayGame() {
		java.awt.EventQueue.invokeLater(new Runnable() {
			public void run() {
				setVisible(true);
			}
		});
	}

	/**
	 * Draw the display (cards and messages).
	 */
	public void repaint() {
		for (int k = 0; k < board.size(); k++) {
			String cardImageFileName =
				imageFileName(board.cardAt(k), selections[k]);
			URL imageURL = getClass().getResource(cardImageFileName);
			if (imageURL != null) {
				ImageIcon icon = new ImageIcon(imageURL);
				displayCards[k].setIcon(icon);
				displayCards[k].setVisible(true);
			} else {
				throw new RuntimeException(
					"Card image not found: \"" + cardImageFileName + "\"");
			}
		}
		statusMsg.setText(board.deckSize()
			+ " undealt cards remain.");
		statusMsg.setVisible(true);
		totalsMsg.setText("You've won " + totalWins
			 + " out of " + totalGames + " games.");
		totalsMsg.setVisible(true);
		pack();
		panel.repaint();
	}

	/**
	 * Initialize the display.
	 */
	private void initDisplay()	{
		panel = new JPanel() {
			public void paintComponent(Graphics g) {
				super.paintComponent(g);
			}
		};

		// If board object's class name follows the standard format
		// of ...Board or ...board, use the prefix for the JFrame title
		String className = board.getClass().getSimpleName();
		int classNameLen = className.length();
		int boardLen = "Board".length();
		String boardStr = className.substring(classNameLen - boardLen);
		if (boardStr.equals("Board") || boardStr.equals("board")) {
			int titleLength = classNameLen - boardLen;
			setTitle(className.substring(0, titleLength));
		}

		// Calculate number of rows of cards (5 cards per row)
		// and adjust JFrame height if necessary
		int numCardRows = (board.size() + 4) / 5;
		int height = DEFAULT_HEIGHT;
		if (numCardRows > 2) {
			height += (numCardRows - 2) * LAYOUT_HEIGHT_INC;
		}

		this.setSize(new Dimension(DEFAULT_WIDTH, height));
		panel.setLayout(null);
		panel.setPreferredSize(
			new Dimension(DEFAULT_WIDTH - 20, height - 20));
		displayCards = new JLabel[board.size()];
		for (int k = 0; k < board.size(); k++) {
			displayCards[k] = new JLabel();
			panel.add(displayCards[k]);
			displayCards[k].setBounds(cardCoords[k].x, cardCoords[k].y,
										CARD_WIDTH, CARD_HEIGHT);
			displayCards[k].addMouseListener(new MyMouseListener());
			selections[k] = false;
		}
		replaceButton = new JButton();
		replaceButton.setText("Replace");
		panel.add(replaceButton);
		replaceButton.setBounds(BUTTON_LEFT, BUTTON_TOP, 100, 30);
		replaceButton.addActionListener(this);

		restartButton = new JButton();
		restartButton.setText("Restart");
		panel.add(restartButton);
		restartButton.setBounds(BUTTON_LEFT, BUTTON_TOP + BUTTON_HEIGHT_INC,
										100, 30);
		restartButton.addActionListener(this);

		statusMsg = new JLabel(
			board.deckSize() + " undealt cards remain.");
		panel.add(statusMsg);
		statusMsg.setBounds(LABEL_LEFT, LABEL_TOP, 250, 30);

		winMsg = new JLabel();
		winMsg.setBounds(LABEL_LEFT, LABEL_TOP + LABEL_HEIGHT_INC, 200, 30);
		winMsg.setFont(new Font("SansSerif", Font.BOLD, 25));
		winMsg.setForeground(Color.GREEN);
		winMsg.setText("You win!");
		panel.add(winMsg);
		winMsg.setVisible(false);

		lossMsg = new JLabel();
		lossMsg.setBounds(LABEL_LEFT, LABEL_TOP + LABEL_HEIGHT_INC, 200, 30);
		lossMsg.setFont(new Font("SanSerif", Font.BOLD, 25));
		lossMsg.setForeground(Color.RED);
		lossMsg.setText("Sorry, you lose.");
		panel.add(lossMsg);
		lossMsg.setVisible(false);

		totalsMsg = new JLabel("You've won " + totalWins
			+ " out of " + totalGames + " games.");
		totalsMsg.setBounds(LABEL_LEFT, LABEL_TOP + 2 * LABEL_HEIGHT_INC,
								  250, 30);
		panel.add(totalsMsg);

		if (!board.anotherPlayIsPossible()) {
			signalLoss();
		}

		pack();
		getContentPane().add(panel);
		getRootPane().setDefaultButton(replaceButton);
		panel.setVisible(true);
	}

	/**
	 * Deal with the user clicking on something other than a button or a card.
	 */
	private void signalError() {
		Toolkit t = panel.getToolkit();
		t.beep();
	}

	/**
	 * Returns the image that corresponds to the input card.
	 * Image names have the format "[Rank][Suit].GIF" or "[Rank][Suit]S.GIF",
	 * for example "aceclubs.GIF" or "8heartsS.GIF". The "S" indicates that
	 * the card is selected.
	 *
	 * @param c Card to get the image for
	 * @param isSelected flag that indicates if the card is selected
	 * @return String representation of the image
	 */
	private String imageFileName(Card c, boolean isSelected) {
		String str = "cards/";
		if (c == null) {
			return "cards/back1.GIF";
		}
		str += c.rank() + c.suit();
		if (isSelected) {
			str += "S";
		}
		str += ".GIF";
		return str;
	}

	/**
	 * Respond to a button click (on either the "Replace" button
	 * or the "Restart" button).
	 * @param e the button click action event
	 */
	public void actionPerformed(ActionEvent e) {
		if (e.getSource().equals(replaceButton)) {
			// Gather all the selected cards.
			List<Integer> selection = new ArrayList<Integer>();
			for (int k = 0; k < board.size(); k++) {
				if (selections[k]) {
					selection.add(new Integer(k));
				}
			}
			// Make sure that the selected cards represent a legal replacement.
			if (!board.isLegal(selection)) {
				signalError();
				return;
			}
			for (int k = 0; k < board.size(); k++) {
				selections[k] = false;
			}
			// Do the replace.
			board.replaceSelectedCards(selection);
			if (board.isEmpty()) {
				signalWin();
			} else if (!board.anotherPlayIsPossible()) {
				signalLoss();
			}
			repaint();
		} else if (e.getSource().equals(restartButton)) {
			board.newGame();
			getRootPane().setDefaultButton(replaceButton);
			winMsg.setVisible(false);
			lossMsg.setVisible(false);
			if (!board.anotherPlayIsPossible()) {
				signalLoss();
				lossMsg.setVisible(true);
			}
			for (int i = 0; i < selections.length; i++) {
				selections[i] = false;
			}
			repaint();
		} else {
			signalError();
			return;
		}
	}

	/**
	 * Display a win.
	 */
	private void signalWin() {
		getRootPane().setDefaultButton(restartButton);
		winMsg.setVisible(true);
		totalWins++;
		totalGames++;
	}

	/**
	 * Display a loss.
	 */
	private void signalLoss() {
		getRootPane().setDefaultButton(restartButton);
		lossMsg.setVisible(true);
		totalGames++;
	}

	/**
	 * Receives and handles mouse clicks.  Other mouse events are ignored.
	 */
	private class MyMouseListener implements MouseListener {

		/**
		 * Handle a mouse click on a card by toggling its "selected" property.
		 * Each card is represented as a label.
		 * @param e the mouse event.
		 */
		public void mouseClicked(MouseEvent e) {
			for (int k = 0; k < board.size(); k++) {
				if (e.getSource().equals(displayCards[k])
						&& board.cardAt(k) != null) {
					selections[k] = !selections[k];
					repaint();
					return;
				}
			}
			signalError();
		}

		/**
		 * Ignore a mouse exited event.
		 * @param e the mouse event.
		 */
		public void mouseExited(MouseEvent e) {
		}

		/**
		 * Ignore a mouse released event.
		 * @param e the mouse event.
		 */
		public void mouseReleased(MouseEvent e) {
		}

		/**
		 * Ignore a mouse entered event.
		 * @param e the mouse event.
		 */
		public void mouseEntered(MouseEvent e) {
		}

		/**
		 * Ignore a mouse pressed event.
		 * @param e the mouse event.
		 */
		public void mousePressed(MouseEvent e) {
		}
	}
}

Concepts to Review

  • Loops

    • Searching / counting while traversing an array and an ArrayList

      • Traverse to find max and mins: public static int findLargest(int[] nums){

      • Interact with an ArrayList

        public static void makeLowerCase(ArrayList<String> commands){

      • Keep count

        public static int countNames(ArrayList<String> names, String target){

      • Shuffle methods:

        public static void selectShuffle(int[] nums){ public static void perfectShuffle(Card[] cards){

    • Nested loops

      • Find common elements between two collections:

        public static ArrayList<String> findCommonNames(String[] roster1, String[] roster2){

  • Classes

    • Encapsulation with accessor and mutator methods

    • Implementing an abstract class (with encapsulation)

      • OOP: When should you move properties and methods to an abstract layer?

        • Name three properties or methods that would be suitable for a Human class and three that would go on an abstract Mammal class.

      • How do you declare an abstract class and an abstract method?

        • Declare an abstract class called Athlete, give it private properties of name, number, position, and is_active.

        • Make a constructor.

        • Make accessor methods for each property.

      • How do you declare a class to inherit the properties from an abstract class?

        • Create classes called SoccerAthlete and BasketballAthlete that both inherit from Athlete.

        • Give each class a toString method that returns the String, "My name is {name} and I'm a {position} in soccer. I'm #{number}." Only if they're active. If they're inactive, the returning String should read, "I used to be play basketball as a {position}."

      • How can you take advantage of polymorphism?

        • Create a runner class with a main method that creates an array of Athletes. Loop through them and have each one introduce themselves.

Challenge

Submit a completed NumSet class:

import java.util.ArrayList;


public class NumSet {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        /*
        ROUND 1 tests
        */
        
        // Create a random int array of a given length, low and high end of range
        int[] randArray = randArray(15, 0, 100);
        
        // Create a random Integer ArrayList of given length, low and high range
        ArrayList<Integer> randArrL = randArrL(8, 5, 50);
        
        // How many similar elements are in a given array and ArrayList
        System.out.print("There are this many similar elements: ");
        System.out.println(compareNums(randArray, randArrL));
        
        // printPretty takes an int array and prints it out nicely
        printPretty(randArray);
        // printPretty takes an Integer ArrayList and prints it out nicely
        printPretty(randArrL);
        
        /*
        ROUND 2 tests
        */
        
        // shuffle randomizes an int array (then calls printPretty)
        shuffle(randArray);
        
        // shuffle randomizes an Integer ArrayList (then calls printPretty)
        shuffle(randArrL);
        
        // divide all numbers by two
        divByTwo(randArray);
        divByTwo(randArrL);
        
        //sumArray
        sumArray(randArray);
        sumArray(randArrL);
        
    }
    /*
    ROUND 1 code
    */
    
    // TODO: randArray
    
    
    // TODO: randArrL
    
    
    // TODO: compareNums
    
    
    // TODO: prettyPretty (overloaded)
    
    /*
    ROUND 2 code
    */
    
    // TODO: shuffle array
    
    
    // TODO: shuffle ArrayList
    
    
    // TODO: divByTwo (overloaded)
    
    
    // TODO: sumArray (overloaded)
}

Studying for the Test

Your Elevens test will be a semi-randomized selection of multiple choice questions all taken from the same sources used for our Do Nows. There will be one free response question similar to the homework. Both of these parts of the test reflect the two portions of the AP test. Therefore, the best way to study would be to review AP practice problems from our relevant topics:

  • Redo homework assignments and previous drills

7: Data Structures

We will build our own photo editing tools as we study more complex nested loops to traverse and mutate 2D arrays.

Learning Targets

  • I can remove a column from a 2D array in Java.

  • I can write 2D array methods for the PicLab.

PicLab

Activity 1 & 2: Color Code

Eight Bits for 0 - 255

  1. Convert 128 to binary

  2. Covert 225 to binary

  3. Convert 11010111 from base 2 to base 10

This is a byte.

3 Bytes to RGB

Max red, green and blue (255, 255, 255) is white. No red, green and blue (0, 0, 0) is black. Sometimes we add a fourth byte to control alpha layer (transparency). rgba(255, 255, 255, 255) is opaque black.

Compress to Hex

Two digits in base 16, hexadecimal, can describe 0 - 255. Eight digits can contain rgba. #FF0000FF is opaque black.

Activity 3: Exploring a Picture

  1. What is the row index for the top left corner of the picture?

  2. What is the column index for the top left corner of the picture?

  3. The width of the picture is 640. What is the right most column index?

  4. The height of the picture is 480. What is the bottom most row index?

Activity 4: Picture Arrays

Activity 5: Get working

PictureTester.java
        //A5
        testKeepOnlyBlue();
        testKeepOnlyRed();
        testNegate();
        testGrayscale();
        testFixUnderwater();
        //A6
        testMirrorVertical();
        testMirrorVerticalRightToLeft();
        testMirrorHorizontal();
        testMirrorHorizontalBotToTop();
        testMirrorDiagonal();
        //A7
        testMirrorArms();
        testMirrorGull();
        //A8
        testCollage();
        //A9
        testEdgeDetection2();

Review

NumGrid Practice

NumGroup.java
public interface NumGroup {
    
    /**
     * Provides a total sum of its contained numbers
     * @return accumulated total
     */
    int sum();

    /**
     * Organizes its contained numbers to be sorted from least to great
     * using the selection sort algorithm
     */
    void sort();

    /**
     * Rearranges its contained numbers using the selection shuffle algorithm
     */
    void shuffle();

    /**
     * Displays the contained numbers in a returned string
     * @return formatted String display
     */
    String toString();
    
}

Exercises

  1. Imagine a circumstance where you might use an interface and an abstract class. Create and implement the interface and abstract class. Instantiate objects that extend these. Create a polymorphic container or method.

  2. Calculate the sum of an indicated column from an extremely rare occurrence of a 2D ArrayList: public static int sumColumn(int col, List<List<Integer>> grid){

  3. Remove a row from a 2D array: public static String[][] removeRow(int row, String[][] names){

  4. Calculate the sum of an entire 2D array: public static double sum(double[][] grid){

  5. Count the number of occurrences of a given number in a 2D array public static int count(int[][] grid, int target){

  6. Add a new column to a 2D array of Pixels with the average color at the end of the image public static Pixel[][] addAverageColumn(Pixel[][] picture){ // each Pixel has .getColor() which gives a single int // return an array that's one column wider, containing the average of every color in that row // you can set the color of a pixel by using .setColor() and passing the method the average of that row's .getColor() }

  7. Convert an RGB value like 220, 175, 205 to a hex value

  8. We have an array of Friends, Friends[] friends, and we want to make sure that each of our friends has the items they requested from the store. Friend.getItems() returns an array of Item objects (Item implements the Comparable interface so you can use .equals() to compare two items). If the Item is not on the shopping list, we'll add it to an ArrayList<Item> called requests. The Item class also has a publicly accessible boolean that marks if the Item has been claimed: Item.claimed.

    public ArrayList<Item> checkShoppingList(Friends[] friends, ArrayList<Item> list){

1: Core Concepts

Expectations

Slow down. Get your head around these ideas before we lean into the code. Being able to come back and reference these terms as they come up will help you put the whole puzzle together.

Learning Target

  • I can describe a full-stack application and the tools required to build one using relevant vocabulary.

What is a Stack?

A stack is all the systems used to run an app. Usually, several computers are involved but that's not a must. Let's look at the various layers in a stack...

Let's understand the layers by discussing the programming languages used in each.

Client

... but how do we get this HTML / CSS / JS on our client computer?

Web Server

Web Application

Okay, we've got a web server receiving signals from our client's computer. Now comes the part where our server runs the app we've built and gives us cool information.

Database

More Python Vocab

Imagine two people watching a movie at the same time. Because those two people have different life experiences, they will interpret the movie in a different way. When your app is running, it loads variables and libraries that gives it a particular “experience.” Our application context refers to the references at play.

A module is a loose term. Python uses the term to describe a single file, sometimes just one part of a larger library of tools that you can import and use within your app. If you put a single line of code in a file, you’ve built a module.

Virtual environment does not include “your app” this is separate. And you may have meant modules, not models. The model refers to the objects and database tables we’ll use in our app. Meanwhile, the libraries or modules that our app depends on in order to run will be installed in our virtual environment.

An efficient programmer keeps their dependencies in a virtualenv, but it’s not required to do so. You can install them globally if you’d like, but other apps running on that machine might complicate things. There are other ways to manage dependencies too.

Throughout the course of the semester how often will we be referring back to older versions of our app?

In-line comments are written with a # and add extra notes around our app. ‘’’DocString’’’ comments provide more detailed explanations right underneath class and function headers.

Game 7: Final Project

59KB
Computer Game Design Final Project.pdf
pdf

Please turn in the planning sheet answers by filling them out in a google doc and sharing it with me or by handing a printed sheet to me at the start of class.

Places to find sprite and tile assets

Assignment

All games need to:

  • Have a strong theme or genre. (2 points)

  • Run smoothly and as intended. (8 points)

  • Have at least three animated multi-frame sprites. (3 points)

  • Use 5 rooms (or utilize a procedurally generated room.) (5 points)

  • Get progressively more difficult. (2 points)

  • Be winnable and losable by the player. (2 points)

  • Use variables to control aspects of dynamic game play (i.e.; parts of your game should change in some way throughout the game. Power-ups, Getting new inventory/ materials, or level gain are examples of this.) (3 points)

Game 3: Ping Pong

With Ping Pong students learn to deal with multiple player inputs as well as create a simple scoring system.

Ping Pong Instructions

///Bounce against walls

move_bounce_all(true);
move_outside_all(direction, 100);

HINTS for assignment!

Game 6 Highlights

Due to time, we will cover the following:

  • Platformer Movement (Video 1)

  • Importing Sprite Sheets (Video 1)

  • Enemy Movement & Paths (Video 2)

  • Tile Sets (class and video 3)

  • Big Room with a follow view (class and video 3)

Platformer Movement Script

// Run This Function in END STEP event
/*
 INSTRUCTIONS: 
 This function requires passing in arguments playerSpeed (not hspeed or speed) 
 and a gravity value.
 
 You should also make an optional argument maxFall with a value of 15
 
 In addition, you need to have two variables in the create event
 of your object:
 
     jumpSpeed = 0
     canJump = true
	 
optional:  Jumping variable (needed in create if you are going to have
		   a jumping animation (controlled in step).

*/



/*********************/
/*Horizontal Movement*/
/*********************/

var move = -keyboard_check(vk_left) + keyboard_check(vk_right);
var collision = instance_place(x+playerSpeed, y+vspeed, all);

// You are moving right
if (move == 1){
	
	if (collision < 0 or !object_get_solid(collision.object_index)){
		x += playerSpeed;
	}
	
	// Move to wall, if there is a SOLID wall to your right
	else{  
		move_contact_solid(0, playerSpeed);
	}
}

// You are moving left
else if (move == -1){
	collision = instance_place(x-playerSpeed, y+vspeed, all)
	if ( collision < 0 or !object_get_solid(collision.object_index)){
		x -= playerSpeed;
	}
	
	// Move to wall, if there is a solid wall to your left
	else{
		move_contact_solid(180, playerSpeed);		
	}
}



/*******************/
/*Vertical Movement*/
/*******************/

jumping = false;
collision = instance_place(x, y - jumpSpeed, all);
// Check to see if you are in the air or are about to jump.
if (place_empty(x, y + 1) or jumpSpeed > 0 or (collision > 0 and !object_get_solid(collision.object_index))){
	jumping = true;
}

// if you are jumping...
if (jumping){
	
	
	// Move up or down if there is no collision this frame.
	if (collision < 0 or !object_get_solid(collision.object_index)){
		y -= jumpSpeed;
	}
	
	// Check for a SOLID object below you
	else if (jumpSpeed < 0  and  object_get_solid(collision.object_index)){
		move_contact_solid(270, jumpSpeed)
		jumpSpeed = 0
	}
	
	// Check for a SOLID object above you
	else if (jumpSpeed > 0  and  object_get_solid(collision.object_index)){
		move_contact_solid(90, jumpSpeed)
		jumpSpeed = -0.1
	}
	jumpSpeed -= grav;
	if (jumpSpeed < -maxFall){
		jumpSpeed = -maxFall;
	}
}

// If you are on SOLID ground, allow the player to jump again.
if (!place_empty(x, y+1) and instance_place(x, y + 1, all) > 0 and object_get_solid( instance_place(x, y + 1, all).object_index)){
	canJump = true;
}

Animation Control

var dir = -keyboard_check(vk_left) + keyboard_check(vk_right)

//put your sprite names here:
var jump_right = sMario_jumpR
var walk_right = sMario_right
var jump_left = sMario_jumpL
var walk_left = sMario_left

image_speed = 3
if (dir == 1){
	if (jumping){
		sprite_index = jump_right;
	}
	else {
		sprite_index = walk_right;
	}
}
else if (dir == -1){
	if (jumping){
		sprite_index = jump_left;
	}
	else {
		sprite_index = walk_left;
	}
}
else {
	if (!jumping and sprite_index = jump_right){
		sprite_index = walk_right;
	} else if (!jumping and sprite_index = jump_left){
		sprite_index = walk_left;
	} else if (jumping and sprite_index = walk_right) {
		sprite_index = jump_right;
	} else if (jumping and sprite_index = walk_left) {
		sprite_index = jump_left;
	}
	image_speed = 0;
	image_index = 0;
}
	

Enemy Move

var collision = instance_place(x+hspeed, y+vspeed, all);
var collisionBelowRight = instance_place(x+hspeed+sprite_width, y+1, all)
var collisionBelowLeft = instance_place(x+hspeed-sprite_width, y+1, all)

if (hspeed > 0){
	if (place_empty(x+hspeed+sprite_width, y+1) or
	   (collision >-0 and object_get_solid(collision.object_index)) or
	   (!place_empty(x+hspeed+sprite_width, y+1) and collisionBelowRight > 0 and object_get_solid(collisionBelowRight.object_index) == false )){
		hspeed = -hspeed;
	}
}
else if (hspeed < 0){
	if (place_empty(x+hspeed-sprite_width, y+1) or 
	   (collision >-0 and object_get_solid(collision.object_index)) or
	   (!place_empty(x+hspeed-sprite_width, y+1) and collisionBelowLeft > 0 and object_get_solid(collisionBelowLeft.object_index) == false )){
		hspeed = -hspeed;
	}
}

Jump Attack

if (y < other.y and jumpSpeed <= 0){
	instance_destroy(other)
} 
else {
	instance_destroy(self)	
}

Resources

Game 4: Breakout

Breakout Instructions

Bounce Code

///Bounce against walls

move_bounce_all(true);
move_outside_all(direction, 100);

Pause Code - in obj_pause (create event)

  // Create surface, draw everything to it, deactivate all other objects
 
surf = surface_create(room_width, room_height); 
    // creates a surface which is the same height and width as the room.
    // A surface is basically a clear drawing surface on the screen.
  
surface_set_target(surf);   
    // Sets aside room in memory for surface and begins drawing on it

draw_clear_alpha (c_red, .5); 
    // Clears surface of buffer noise and sets color and alpha 
    // (0= fully transparent, 1 = fully opaque, .5=50% transparent)

surface_reset_target();
    // Tells GM to stop drawing on the surface and 
    // allows drawing directly on the screen again (and thus the draw GUI below)
 
instance_deactivate_object (obj_ball);
    // Deactivates the ball without destroying it.

visible = true; 		
    //This object is visible.  
    //Adding the command is not strictly necessary since we already set the object to visible.

Pause Code - In obj_pause (Draw GUI event)

draw_set_font(fnt_pause);
	// GML commands, also called functions,  are set up in categories.
	// Draw_ gives you access to draw functions.
	// Instance_ functions give you access to things dealing with instances of objects.
	// Draw_set_ commands establish parameters for your draw actions.
	// This one changes your draw font to your pause font (set it up, if you haven’t).

draw_set_color(c_black);
	// This one sets the color.
	// typing c_ will give you a list of different color options.

draw_set_halign(fa_center);
	// Sets the horizontal alignment of the font to center.

draw_surface(surf, 0, 0);
	// This function draws the surface over the room.  
	// The surface that it draws is called surf (which is what we called it in the create event).
	// It draws it starting at 0x and 0y in the room.

draw_text(room_width/2, room_height/2, "Game Paused:  Press Space to Continue");
	// This draws text.  It looks for (x,y,string) which means the programmer 
	// decides where the it goes.  room_width / 2 is right in the center of the room.
	// A string is a series of text in “”. The text is in black and centered because of the above 
	// draw_set_ functions.

draw_set_halign(fa_left);
	// Since the text of the scoreboard is aligned to the left, we need to reset the alignment.

Pause Code - In obj_pause (Key Press - Space)

/// Unpause, clear surface, re-activate all objects.

surface_free(surf); 
	// Free up the memory from the surface.
	// Essentially this deletes the surface.
	// By the way, we are starting code now because there are no commands in 
	// drag and drop programming that deal with surfaces.

instance_activate_all(); 
	// Activate all the objects again
	// We could have also used instance_activate_object (obj_ball); 
	// since that is the only thing we deactivated in the create event.

instance_destroy(self);  
	// Destroy the pause object.
	
	// As you look at this code, remember that instance_ functions are used
	// to control instances of objects in the room.  As we get further along, we 
	// will use more code blocks,  so it is important to be aware of the general 
	// language rules because you won’t always know what the exact command 
	// will be for an operation. 
	
	// In the code block autocomplete will help you find the right one.  If you know
	// you are dealing with an instance, you can start typing “instance_” and will be
	// given a list of possible things which could finish that command.  

2: MVT Pattern

Expectations

In the last section, you learned there's a lot of layers to a stack. But even within our stack's application layer, there's a lot of complexity. If you don't keep organized, your code quickly gets overwhelming and difficult for other people to understand if you need help. But we find that we can sort-of split our code into three areas, 1) code that stores stuff like user data, 2) "logic" code, or rather the stuff that loads data executes actions like making a sale, and 3) the HTML visuals we see when we interact with the app. This pattern was originally called MVC. We use a slight twist on that called MVT.

Learning Targets

  • I can describe the rationale for the MVT design pattern.

Background

  • Model: Database schema or rather, what gets stored in memory. But we won't have to learn a database language like SQL just yet. We'll have a tool called an ORM to convert Python into SQL for us. We'll use that to setup our SQL database tables for each object

  • View: Routes internet traffic. Here's where we connect the /url/someone/typed/ to the Python thinking that will respond to request for that certain webpage. The view is our controller. It's our application logic--our central brain.

  • Template: HTML with bits of {{ python }}. It's not just a regular HTML page. Python will render this so we can respond to different conditions. For example, if a user is logged in we can so the "Logout" button but if not, we show the "Login" button. Careful though, avoid putting too much logic here.

The model (M) is a model or representation of your data. It’s not the actual data, but an interface to the data. The model allows you to pull data from your database without knowing the intricacies of the underlying database. The model usually also provides an abstraction layer with your database, so that you can use the same model with multiple databases.

The view (V) is what you see. It’s the presentation layer for your model. On your computer,the view is what you see in the browser for a Web app, or the UI for a desktop app. The view also provides an interface to collect user input. In our MVT pattern, this becomes T. So MVT and MVC both use the term "view" but for different parents of the same triangle. This seems needlessly cruel to those studying this stuff.

The controller (C) controls the flow of information between the model and the view. It uses programmed logic to decide what information is pulled from the database via the model and what information is passed to the view. It also gets information from the user via the view and implements business logic: either by changing the view, or modifying data through the model, or both. In our MVT pattern, this is the V and will be found in our views.py file.

Model

Schema

If I launched flask shell I could talk with Python while flask is running app and I could ask app.models for all the objects we use around our code. Like app.models.User. That would be the schema. It's not an actual user that I'm referring to when I say app.models.User. That's the definition, the skeleton or the schema. The individual records in the User table will used for the instantiated objects in my code.

Schema is more than just the list of properties (like first_name and such) and functions of an object in your app. It also describes how objects are connected in your database.

Relationships

There's more: Instead of just connecting two objects, what if we wanted to qualify that relationship? Not only do you want to say "this user belongs to this club," but you also want to mark down that she's the president of the club. So now we have a Membership object that can have all sorts of properties that describe your role on the club and what you're allowed to do or not do. Association objects are super cool.

Queries

book_list = new List(); sql = "SELECT book FROM library WHERE author = 'Linus'"; data = query(sql); while (row = data.next()) { book = new Book(); book.setAuthor(row.get('author'); book_list.add(book); }

With an ORM library, it would look like this:

book_list = BookTable.query(author="Linus");

The mechanical part is taken care of automatically via the ORM library.

Questions

  • So object-relational mapping is a programming technique for manipulating data?

    • Yes, it’s the tool (ours is called SQLALchemy) that keeps us from having to write many SQL commands of our own.

View

Routes

Decorators

Template

Inheritance

There's no reason to write every page used in your app on separate html files. Templating allows us to extend or start from a base file that has all the nav bar and footer stuff we need. This is a type of inheritance and it's pretty neat.

Static Assets

Static assets are your images and CSS files and other stuff that doesn't get run like code and have to get served up to your users. We'll find ways of making this process go fast.

5: Tour Flaskinni

Learning Targets

  • I can describe the MVT components of Flaskinni.

  • I can describe the thread's steps as my app starts up.

Organization

Remember, you can help add comments and docstrings to Flaskinni and submit pull requests. Even beginners can help contribute to open source projects in surprisingly substantial ways.

App Factory

The reason why the Application Factory is so important has to do with something called Flask's Application Context. Our app's "context" is what takes the assortment of Python files and modules which make up our app and brings them together so that they see and work with one another.

When your app is serving hundreds or thousands of people at a time, your server will run many instances of your app. You may also run your app in different modes, like a text-only shell. An application factory addresses this need by spitting out instances of app

Blueprints and MVT

Flaskinni comes with a main and an api blueprint. That'll affect your use of url_for. So if you wanted to make a link to the homepage, it'd be <a href="{{ url_for('main.index') }}">home</a>

Template

Now that Flaskinni is running in your environment, local or cloud-based, let's take a tour.

File structure

This is the whole parent-child thing. The parent is the skeleton of your page. We named it base.html and it has <link>s to our Google Fonts, CSS files, and sets up nav bars and any other element that’s site-wide. It’s great! Pretty much sets up the whole theme of our site.

To put our pages inside this metaphorical picture frame, we use the command, {% extends "base.html" %} at the top of every other HTML we put in our templates folder.

The base template extends across all pages, so the website can share HTML code.

Base's blocks

We’re going to make a new template that inherits from our base.html so you can experiment with this handy tool. Create a new file in your templates folder called about.html. This page will need hardly any information at all because all the setup is done in the parent. All we need to do is pass some HTML into any block.

{% extends "base.html" %}   


{% block content %}
    {# this is a comment #}
    <div class="row justify-content-md-center">
        <div class="col-md-6">
            <h1>Hi</h1>
        </div>
    </div>

{% endblock %}

Sass and JS

Don't want to learn? There is a lazy way out and that's to edit your CSS directly. No judgments.

  1. Add them to your collection and get the <link> we’ll use to embed a connection to Google Fonts.

  2. Replace the other <link> to fonts.google.com that was in your base.html file

  3. Add your CSS code to custom.css, something like:

body {
    font-family: 'Roboto Mono', monospace;
}

h1, h2, h3, h4, h5, h6 {
    font-family: 'Rammetto One', cursive;
}
  1. Launch your server

    1. (make sure you’ve got venv activated) source venv/bin/activate or on Windows: source venv/Scripts/Activate

    2. (use our flask-script to run the server) flask run

  2. Check out your font changes!

Views

If you want to see the new template file in action, we’ve got to build a route to that page. As of this writing, there are only two locations for routes in Flaskinni, the master __init__.py file and the views.py file inside the blog module folder. Since our homepage route is in the first file, we’ll put our about route there, too.

# Created a new route used for rendering the about page template 
# Custom app routes for the end of the website url
@app.route('/about')
@app.route('/about/')
@app.route('/about.html')
# Define app route
def about():
        """Render the template"""
        return render_template('about.html')

We later passed a variable to the template. We dropped <h1> {{ some_variable }} </h1> in our about.html file. Nothing shows up until we change the render_template call to something like this:

def about():
        """Render the template"""
        return render_template('about.html', some_variable="Hello!")

Congratulations! You just passed your first variable to a template.

url_for

Flash Notifications

We have cool, color-changing notifications in Flaskinni that rely on Bootstrap classes. So if you want to send a good alert message that something worked, you'd say: flash("Your message has been sent!", "success")

But if something failed, you'd write:

flash("Your message was destroyed by mistake. Whoops!", "danger")

What other Flash notifications are there? How are the flash notifications being built? Let's look at where they come up in the base.html file, trace back the macro that builds the flash messages and then see what other options come with Flaskinni.

Sessions

Cookies!

Models

Users are special

Example Queries

Let's talk about how this blog post is queried from our database:

@app.route('/article/<slug>')
def read(slug):
    post = Post.query.filter_by(slug=slug).first_or_404()
    return render_template('main/article.html', post=post)

Example Relationships

Check out line #20.

class User(db.Model, UserMixin):

    # Our User has six fields: ID, email, password, active, confirmed_at and roles. The roles field represents a
    # many-to-many relationship using the roles_users table. Each user may have no role, one role, or multiple roles.
    id = db.Column(db.Integer, primary_key=True)
    first_name = db.Column(db.String(155))
    last_name = db.Column(db.String(155))
    phone = db.Column(db.String(20)) # let's guess it should be no more than 20
    address = db.Column(db.Text)
    about = db.Column(db.Text)
    image = db.Column(db.String(125))
    email = db.Column(db.String(255), unique=True)
    password = db.Column(db.String(255))
    # TOGGLES
    active = db.Column(db.Boolean(), default=True)
    public_profile = db.Column(db.Boolean(), default=True)
    # DATES
    confirmed_at = db.Column(db.DateTime())
    last_seen = db.Column(db.DateTime(), default=None)
    posts = db.relationship('Post', backref='user', lazy='dynamic')

Extensions

Flask-Security

Flask-Mail

Flask-Migrations

Flask-Assets

Flask-RESTful

10: Deployment

Publish your Flask app to a web server. This is a challenging process often with unique challenges for every app. We'll get there.

We’re going to use Digital Ocean to host our app. I also considered Heroku. If we were better with Docker, I’d also consider using Azure or Google Cloud. So don’t be afraid to look around at other options besides the stuff I spell out here. You really can figure this stuff on your own and chart a different path if you're willing to grind it out

Initial Server Setup

    1. Once you get your venv activated, don't forget pip install --upgrade pip wheel

Deploying Your App

  • If admin rights are needed, you may need a command like this: sudo -H /home/myuser/venv/bin/python -m pip install -r requirements.txt

  • My wsgi.py file:

    from myapp import app if __name__ == "__main__":

    app.run(host='0.0.0.0')

  • There are many critical files in this process, but the one that ties them all together is: sudo nano /etc/systemd/system/flaskinni.service

App deployment is tricky. You'll need some help tracking down problems:

I use sudo cat /var/log/syslog frequently to see the errors being reported by the uWSGI service and use sudo less /var/log/nginx/error.log to see the errors just from nginx (they'll otherwise be mixed in with the syslog)

If everything is working up to this point, your project will load a 500 error. Track down the error and it should be reporting that the connection to the database has failed.

Service

sudo nano /etc/nginx/sites-available/myproject

sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled

Database

Postgres starts with a super user with the somewhat unoriginal name of postgres. You can use your admin powers to switch to that user by typing sudo -iu postgres and now you can use psql and you'll have full control to setup a new user. Read up on how to add a new user in psql. The lazy, slightly dangerous way is to createuser -P -s -e user_name Once you've created your user in psql, update your .env file with the user and password.

We've got to test to make sure your database user can log into the database you've created. If your database user also exists in Linux, you can do the same sudo -iu trick we did before and then open up psql. This command will allow you to be more specific: psql user_name -h 127.0.0.1 -d db_name

You may end up using ALTER USER user_name WITH PASSWORD 'new_password'; from the postgres user.

Security

Change the passwords and hash codes used in .env and remember that changes to secret keys or salt could break passwords currently saved in your database. For random strings to use as secret keys for apps, use a line of code like this to make one:

  1. Practice deploying updates. Add, commit, and push from your development environment and pulling over SSH. Make a change to the database and use migrations to update your models without losing data.

    1. Making changes to your application

      1. After building a cool new feature on Cloud9

        1. git add .

        2. git commit -m “fixed the thing”

        3. git push origin master

      2. Then SSH to your server, navigate to your folder and git pull origin master

Error Reporting

9: Advanced Topics

Expectations

Learning Targets

  • I can research and hack together an MVP.

Session

Decorators

Forms

Drop-down

When filling out a form, you may want to have a drop-down of a user's friends or some other set of data unique to that user. How can you provide those dynamic options within a form template?

And what if you want one drop-down to populate the options of another dropdown?

Build Options From a View

Just use a SelectField with no real options and populate them after you build the form.

Placeholders

Examples:

Captcha

SQLAlchemy and Databases

backref VS back_populates

Two back_populates equals one backref. Using backref declares a two-way relationship. It’s more efficient than dropping a back_populates on both ends of the relationship but I prefer it because I’ve been confused too many times staring at a class wondering about its relationships unaware that another class has declared a relationship backref in a different file.

Relationship Loading: Lazy?

Command Line Interface

flask shell

This is a really useful skill we should go over as it helps us test and figure out where things go wrong.

flask shell

if python just said it doesn't know what that is, then you need this line: from extensions import db

from user.models import User

my_users = User.query.all()

look at your user(s): my_users my_users[0].email

my_users[0].first_name

Talking to Postgres

Let's make sure we can login directly to our database. You can skip this step if you're, say, in the midst of a hackathon, the app is working, and you've got to keep moving. In the long-run, it's critical you know how to flex control over your database directly.

If you're using Terminal, bash or PowerShell, you should be able to type psql to open a command-line version of PostgreSQL. You can also use a friendlier interface like pgAdmin, though I recommend making the effort to explore both. You'll need to specify your user when accessing psql. Specifying your user can vary a lot depending on how you approach it. Good thing you know how to Google.

Linux:

sudo service postgresql start psql (try listing the current databases) \l (if you need to quit) \q

If you’re the superuser using sudo -i then you’ll be on the root account (don’t do that). Postgres has a built-in admin you can log into with su - postgres and then psql (you shouldn’t need that but it’s useful).

You can edit accounts' psql access and credentials with stuff like:

ALTER ROLE ubuntu WITH PASSWORD 'ubuntu';

You probably won’t need this very often, but it’s important to know if you want to understand how your app works. Launch psql and be very careful as you tiptoe through our database:

(connect to our database, which in this example is named “db”) \c db

(check out the tables in our database) \dt

(see what we’ve got in our post table) SELECT * FROM post;

If there are no posts, we’re going to create the first one, which will have the ID of zero. If there are posts already, we’re going to create one with the next highest number.

INSERT INTO post (id, user_id, title, subtitle, body, slug, live) VALUES (0, 0, “Some title”, “Some subtitle”, “Some body”, “someslug”, True);

(let’s quit psql) \q

DELETE FROM post WHERE id=0;

(make sure it’s gone) SELECT * FROM post;

Configuring Flask-Mail

This line needs to be in your settings.py:

SECURITY_EMAIL_SENDER = private.ADMIN_EMAIL

JavaScript

Setting Nav Links Active

Confirmation Buttons

Just as we keep a custom.css file, your project should have a custom.js function. Something like this could be very handy. Now you can just add class=”confirmation” attribute to any <a></a> and it’ll have a JS-powered confirmation window.

AJAX: Server Without Reloads

Actions of our app are triggered by routes in our view. If you type in the url of your site, /index, your browser sends a GET request to that route to the homepage route in your app. Your browser loads the page. But what if you want to avoid refreshing the page? What if you want to send a message from a modal window and press submit without losing your spot on the current page?

Passing Variables from Flask to JavaScript

Calling a JavaScript Method on a Button

<a onclick="hidePaidBills()" href="javascript:void(0);" data-toggle="tooltip" data-placement="top" title="hide paid"><i class="fa fa-eye"></i></a>

Sending SMS Messages with Twillio

Updating Dependencies

Update all libraries (copied from StackOverflow)

sudo -H python3 -m pip freeze --local | grep -v '^-e' | cut -d = -f 1 | xargs -n1 sudo python3 -m pip install -U

If you don't want to overdo it with the sudo nonsense: pip freeze --local | grep -v '^-e' | cut -d = -f 1 | xargs -n1 pip install -U

Create a requirements document:

pip freeze > requirements.txt

Test to make sure the app works. If it doesn't, undo changes tracked by git to get you your previous version of the requirements.txt. Reinstall your dependencies based on all the previously recorded versions.

Documentation

Enable the support of the Google-style docstrings which are much easier to read:

Unit Tests

The most responsible way to build software is to start with unit tests. A script will mimic various types of users as they test every function on your site. The unit test will report when something acts differently than expected. I struggle with keeping to this discipline. A more sophisticated implementation of Flask’s unit test system will be the best sign of my own professional growth in this area.

8: Standup Your DB

Expectations

By now you should have created your module or blueprint’s folder in your project’s directory and another in your templates. Now, we'll talk about what we should add into the models/ folder

Learning Targets

  • I can create an ERD/UML to describe the data that will be stored in my app.

  • I can write new relational database objects and successfully stand up my database.

Make Your Copy

Here's a semi-accurate diagram of Flaskinni's starting objects. Make a copy of this document and share it with your team. Compare your UML's and your wireframes, to make sure all the data you need in your app is stored in a logical hierarchy.

Example 1: Starsite

Example 2: Fipplr

Fipplr allows businesses to log work, manage invoices, and accept payment. This set of tools can be used by freelancers and employers. Fipplr works similarly to many other accounting tools but its simplicity and guided structure protects young entrepreneurs.

Example Class

Query Practice

Invoice Count:

  • Invoice.query.count()

  • len(Invoice.query.all())

    • Count how many invoices have been submitted system-wide

Paid/Unpaid:

  • Invoice.query.filter(Invoice.date_paid != None).all()

    • Check to see if an invoice has been officially paid. This will be a simple boolean check to see if it has been paid or not. Eventually, you will be able to filter paid and unpaid but to begin, it will just be paid.

Project List:

  • Project.query.join(Project_User).filter(Project_User.user_id==current_user.id).all()

    • Print the list of all your current working (live) projects. For employers, this list would include the project name and who is assigned to it. For freelancers, it will list all the projects you are assigned to.

Client/Employer List:

  • [Function name]

    • Find the full list of your clients. For employers, each client would be your subcontractors. For freelancers it will list all the clients that have hired you.

Company List:

  • Company.query.join(Company_User).filter(Company_User.user_id==current_user.id).all()

    • All companies a user is connected to.

Invoiced Work Check:

  • Query: [Function name]

    • Find the full list of work officially invoiced (submitted). If work is not invoiced pull up a separate list. In total there will be two lists, one for the officially invoiced (submitted) work and another for the unofficially invoiced (submitted) work.

Star Sight is a collaborative story editor with a growing array of tools to help writers. You can control access to your work, track your characters, and roll dice to help make decisions. Stories also support rich media so your work can stand out.

Relationships

Database architecture, the way we build and connect elements in an app, often goes unappreciated by the average user. It’s a complex software engineering challenge that’s unique to every problem being solved. In this example we have some of the following relationships:

  • Story_Chapter

  • User_Story: A user has its own attributes (First and last name, email, and ID). A story also has its own attributes (A series it belongs to, and its own ID). In order to connect these two things, a helper table is created and used by pairing the ID of the user and the story it’s associated with.Its an additional object that connects to the two. It told to, it also gives the user permission to give other users access to a particular story.

Example Class

Query Practice

  • Story.query.join(Story_User).filter(User.id==current_user.id).all()

    • All stories the current user has

  • Chapter.query.join(Character_Story).filter(Character.id==x.id).all()

    • All chapters that have a certain character

  • Series.query.join(Story).join(Story_User).filter(User.id==1).all()

    • All series that the current user has

  • User.query.join(Story_User)).all()

    • All users that have stories linked in the Story_User join table

  • User.query.except_(User.query.join(Story_User)).all()

    • All users that don’t have stories

Example 3: Overhaul Repair

Overhaul Repair is an app that allows users to sign up to request a mail-in phone repair service. This web app will allow users to create accounts to monitor their device status and also add their devices into the account, allowing users to easily create repair orders from previously added devices. The app will also include an admin only finance management system.

Example Class

Query Practice

  • Query: Task.query.filter(Task.date_completed==None)

    • Explanation: Query searching through all phones that have unsolved open issues

  • Query: Task.query.order_by(Task.price)

    • Explanation: Order all tasks by price

  • Query:

    • Explanation: All phones that have completed repairs

  • Query: Device.query.filter(device. odel_number.contains(‘A1’))

    • Explanation:

  • Query: Message.query.filter(Message.user_id.contains('Robert Hayek'))

    • Explanation: All messages sent by employees

Example 4: TGene

Tgene is a website that connects the Gilmour Academy molecular genetics lab to others around the world. My app allows the students and lab instructor, Doctor Edward Turk, to write and upload blog posts, pictures, and research about the current work being done in the lab. Through this shared information, collaboration can occur between labs through a contact feature to get teachers and researchers in touch. Collaboration also includes the sale of plasmids from the Gilmour Academy lab to other schools. Tgene is a project that allows Gilmour Academy high school molecular genetics class to share their research, work, and plasmids to other students and researchers across the country.

Example Class

Class for my register form that allows me to register as an admin

Query Practice

  • Query: Moneyplasmid = DBSession.query(Plasmid).filter(plasmid.price)

    • Explanation: Returns all plasmids that cost money

  • Query: Freeplasmid= DBSession.query(Plasmid).filter(plasmid.price<1)

    • Explanation: Returns all plasmids that are free/ link to assistance

  • Query: PlasmidOrder=DBSession.query(Plasmid).order_by(Plasmid.price)

    • Explanation: Query all plasmids ordered by price

  • Query: Plasmidall= DBSession.query(plasmid)

    • For plasmid in Plasmid:

    • print plasmid.name

    • Explanation: Query all available plasmids for sale (free and $$)

  • plasmidgene = DBSession.query(Book).filter_by(gene_id=str)

    • Query that shows all the plasmids bought that include a specific gene (sort by genes)

Example 5: Ennounce

An app to organize announcements for school clubs and teams and to efficiently communicate them to students. Our platform is a way for groups to connect with users. Members can subscribe to groups to stay up to date on what is going on with a group. Groups can post announcements and members can comments and react to them.

Example Class

Query Practice

  • Lists all the groups a certain user is in

    • Group.query.join(Membership).filter(Membership.user_id == 2).all()

  • Lists all of the announcement for a particular school base on school id

    • Announcement.query.filter(Announcement.school_id == 2).all()

  • Lists all of the groups at a particular school

    • Group.query.filter(Group.school_id == 2).all()

  • # Gives all the announcements that a certain user has made

    • Announcement.query.filter_by(user_id=2).all()

  • # Gives all of the announcements of a particular group

    • Announcement.query.filter(Announcement.group_id == 2).all()

  • Membership.query.filter(Membership.user_id==current_user.id, Membership.role=='Leader').all()

  • # NOT WORKING---- Gives all of the announcements for a particular user based on their groups

    • Announcement.query.join(Group.query.join(Membership)).filter(Membership.user_id == 2).all()

    • .filter(Membership.user_id == 2).all()

    • Group.query.join(Membership).filter(Announcement.query.filter_by(user_id=2).all()

Get Started

Assuming you’re responsible enough to use some sort of project management tool like Trello, use the UML or ERD you’ve sketched as a reference to build out your todo list. For almost every table you’ve created in your database, you’ll probably need:

  • A form built in your forms.py that defines each field a user will fill out

  • A .html template where that form can be displayed. This form will be used to create a new object as well as editing an existing object

  • A route and function in your views.py for both the new and edit mode of your object form

  • A link that will trigger the creation of a new object or editing an existing object

The point here is to think through the absolute minimal displays required to add and manage your data. Then layer in some basic commands next to that table of data.

Comment Your Code

Superadmin

Once your models.py file is complete and your app is running, the first route I recommend building is /superadmin.

We'll build control tables, here's how we load the data for the first one, users.

How to query?

3: Exploring the Unity UI

We will be looking at the user interface for Unity, how to navigate, where to find different aspects of our programs.

Building a game is a huge task. Unity organizes the many elements in our game, connecting objects with scripted actions. We must learn how a user interfaces with all Unity's powerful capabilities. \

Tutorial

Unity has changed

The software has been updated frequently since the recording of this video. Be patient and attentive to the new layout as well as changes in class procedures

Learning Targets

  • I can find and create primitive shapes in the hierarchy

  • I can find components of my objects

  • I can find my game asset folder

  • I can navigate the game space

Assignments

  • Create and manipulate at least 5 objects.

2: Installation

We will be installing Unity Game Development Engine to develop your games.

Expectations

Students should set up their personal computers to work with Unity and to share their save files between computers.

Learning Targets

  • I can set up a computer to be ready for work outside of class.

Assignments

Download and install:

  • Unity Hub

  • The most recent version of Unity

  • Github Desktop

Game 1: Rolling Ball

Finished Game Overview

Building The Game

1. Building the Scene

2. Pickups: Scripts - Rotation.

3: Player Movement: Part 1

3b: Player Movement: Part 2

4: Camera Control and Extra Levels

5: Switching Between Levels: Part 1

5b: Switching Between Levels: Part 2

6: Text and User Interface Basics: Part 1

6b: Text and User Interface Basics: Part 2

6c: Text and User Interface Basics: Part 3

Assignment

For your assignment, you will need to build on the ball roller game in the following ways:

  1. Create at least three extra levels (for a total of five).

  2. Make your game say "You Win" when you beat the final level.

  3. Different colored power up with different point value from the ones we built.

  4. Stop the timer and disable game controls if the game is over. (Hint: You will need a boolean (bool) type variable to control whether the game has ended and link those to if - statements within your game)

  5. Create an death box or script under your level that will restart your level if the player falls off our hits it. If you are creating a death box, you will need at box collider, but not necessarily a renderer or material You can create invisible collisions.

  6. Make a sharable build of your game using the instructions below.

Making a Sharable Build

Booleans

Learning Targets

  • I can create and use int, float and bool variables.

  • I can correctly change the value of a variable through code.

  • I understand when to use public and private variables.

  • I can access inputs and apply them to player movement.

  • I can implement if statements in C#.

  • I can write and call my own methods in C#

  • I understand and correctly use Start, Update, FixedUpdate and LateUpdate functions.

  • I can link components to variables.

  • I can determine how many of a GameObject exist in a scene.

  • I can organize and program based on my build index.

  • I can change scenes within my game through code.

  • I can create and manipulate several different 3D primatives.

  • I understand and can use several different components.

  • I can add text elements to the game screen.

  • I understand when to add RigidBody components and when not to.

  • I can use RigidBody components to interact with Unity’s physics system.

  • I can create and apply materials to objects.

Turning in your games

Game 5: Tank Battle

Tank Battle Instructions Part

Tank Battle Instructions Part II

The red shows the current lowest number
The outer loop wants the smallest number. The inner loop will find it
The first number is smaller! Oh joy!
Outer is only supposed to have one "T". You know what does have two Ts?
We found one even smaller–what a world we live in!
Inner loop has finished and now we know the INDEX value of the smallest
Let's reset the smallest index to the otter loop and start over
This animation depends on an insert option to move over the other numbers
Practice, practice, practice
To avoid an infinite repeat, we've got to include a base case
Taken from giantfreakinrobot.com
Why you can't use == to compare the contents of two instantiated objects
Duplicate Borebot
The class must match the name of the file exactly. Please give it an original name.
Bajirao Mastani is a metaphor for the rallying effect of a brand
At least glance through the documentation
Free, popular and loaded with tutorials
They really do a great job of teaching this stuff. I don't have to do anything
While I prefer Adobe XD, I've seen tons of great work on Sketch
Free for students!

You will need to add .

This site's Chapters 3-9:

Take a practice test:

Do some Codingbat:

Okay, so you know how a regular array works
Now a 2D arrays has a whole array in each spot
You don't have to just use dumb old ints. Instantiated objects are cool too
We use row-major to define the 2D array of pixels that makes a picture
2D traversals go row by row and each column between each row

: Web stack contains an operating system (OS), a programming language, database software and a Web server. A full-stack developer is someone capable of building an app or solution that addresses each of these components.

This is what you see on your page. HyperText Markup Language, gives content structure and meaning by defining that content as, for example, headings, paragraphs, or images. CSS, or Cascading Style Sheets, is a presentation language created to style the appearance of content—using, for example, fonts or colors.

is a programming language commonly used in web development. It was originally developed by Netscape as a means to add dynamic and interactive elements to websites. It used to be used solely for client-side purposes, but now servers are running apps build using NodeJS. JavaScript has nothing to do with Java.

: the message system that runs the World Wide Web. This is how website information is sent over the Internet. There are many different types of HTTP requests, including GET and POST, one asks for information from the server and the other submits information to the server.

: In computing, a shell is a user interface for access to an operating system's services. In general, operating system shells use either a command-line interface (CLI) or graphical user interface (GUI). CLI is used to communicate to the shell in the form of text input.

(Secure Sockets Layer) is the standard security technology for establishing an encrypted link between a web server and a browser. This link ensures that all data passed between the web server and browsers remain private and integral.

: An Operating System provides services to both the users and to the programs. It provides programs an environment to execute. It provides users the services to execute the programs in a convenient manner.

: Python is a high-level programming language designed to be easy to read and simple to implement. It is open source, which means it is free to use, even for commercial applications. Python can run on Mac, Windows, and Unix systems and has also been ported to Java and .NET virtual machines. Most Python distributions rely on CPython, which means your code will boil down and run using the C language. Flask is a Python library.

Framework is described as “an abstraction, in which software providing generic functionality can be selectively changed by additional user-written code, thus providing application-specific software, is a software framework that is designed to support the development of web applications including web services, web resources, and web APIs. Web frameworks provide a standard way to build and deploy web applications. Web frameworks aim to automate the overhead associated with common activities performed in web development. For example, many web frameworks provide libraries for database access, templating frameworks, and session management, and they often promote code reuse. (additional )

Structured Query Language, used to request information from a database. SQL has been the favorite query language for database management systems running on and . Increasingly, however, SQL is being by PC database systems because it supports (databases that are spread out over several ). This enables several on a to the same database simultaneously.

: is an (ORDBMS). As a database server, its primary functions are to store data securely and return that data in response to requests from other software applications.

: a computer program that directly executes, i.e. performs, instructions written in a programming or scripting language, without requiring them previously to have been compiled into a machine language program.

: One of the design ideas behind Flask is that there are two different “states” in which code is executed. The application setup state in which the application implicitly is on the module level and request handling.

: encapsulates code and data to implement a particular functionality, has an interface that lets clients to access its functionality in an uniform manner, is easily pluggable with another module that expects its interface, is usually packaged in a single unit so that it can be easily deployed.

: A folder where a copy of all dependencies is kept separate from the system installation. This allows you to work on several apps without having to manually toggle which version of the language interpreter your system is using. It's a safe and responsible way to develop your apps.

: “a collection of implementations of behavior, written in terms of a language, that has a well-defined interface by which the behavior is invoked.”

: A dependency is a file that something you are trying to install requires. These are the required libraries and modules for your app to function.

: is a system for tracking changes in computer files and coordinating work on those files among multiple people. Version control is a system that records changes to a file or set of files over time so that you can recall specific versions later.

: An item in memory with a variable name, location reference, and the instantiated code provided by some class definition. Objects have individuality, and multiple names (in multiple scopes) can be bound to the same object. This is known as aliasing in other languages. This is usually not appreciated on a first glance at Python, and can be safely ignored when dealing with immutable basic types (numbers, strings, tuples).

A method is a function that “belongs to” an object. (In Python, the term method is not unique to class instances: other object types can have methods as well. For example, list objects have methods called append, insert, remove, sort, and so on. However, in the following discussion, we’ll use the term method exclusively to mean methods of class instance objects, unless explicitly stated otherwise.)

This method is not named according to PEP which recommends the use of snake_case

In almost all programming languages, functions accept variables that are used in their code, (i.e. f(x) = x + 1). The parameter is simply the variables that are referenced within a method or behavior. This can also be referred to as an argument. A Python module which can contain submodules or recursively, subpackages. Technically, a package is a Python module with an __path__ attribute. parameter. A named entity in a function (or method) definition that specifies an argument (or in some cases, arguments) that the function can accept.

: In class-based object-oriented programming, a constructor (abbreviation: ctor) is a special type of subroutine called to create an object. It prepares the new object for use, often accepting arguments that the constructor uses to set required member variables.

: Inheritance is a feature that represents the "is a" relationship between different classes. Inheritance allows a class to have the same behavior as another class and extend or tailor that behavior to provide special action for specific needs.

: A string literal specified in source code that is used, like a comment, to document a specific segment of code.

(image taken from djangobook.com)

There are countless ways to organize the files and code used in an application. How does one choose? How do you plan out the parts of your app? There’s big advantages to following best practices, using a pattern that others can recognize. You may hear people references the Gang of Four (GoF) when referring to . MVC is one such pattern, but for reasons I'm still figuring out, Flask uses a conflicting acronym for remarkably similar pattern.

(We will be using a modification of this pattern called MVT)

: Communication diagrams model the interactions between objects in sequence. They describe both the static structure and the dynamic behavior of a system.

: table that associates two other tables in a many-to-many relationship. Let's say you make a website to manage school clubs. Students can be in many different clubs and clubs can have many different students. Somewhere in our database we need to write down a connection between each Student.id and each Club.id. It's the list of connections between two objects. You want to leave the club? Remove the record that links the two id's.

: a technique that lets you query and manipulate data from a database using an object-oriented paradigm. When talking about ORM, most people are referring to a library that implements the Object-Relational Mapping technique, hence the phrase "an ORM". An ORM library is a completely ordinary library written in your language of choice that encapsulates the code needed to manipulate the data, so you don't use SQL anymore; you interact directly with an object in the same language you're using. For example, here is a completely imaginary case with a pseudo language: You have a book class, you want to retrieve all the books of which the author is "Linus". Manually, you would do something like that:

: a method of associating user-defined Python classes with database tables, and instances of those classes (objects) with rows in their corresponding tables.

: the process of transferring data between computer storage types or file formats. If we ever want to change our SQL tables to add new information to every record, we’ll need to migrate the data from the old table to the new table. We’ll use a tool called Alembic to do this.

: moving data from source to destination. Our Flask controller will take requests to, for example, yourwebsite/home and match it to the code that builds the home page

: Session is the time interval when a client logs into a server and logs out of it. The data, which is needed to be held across this session, is stored in a temporary directory on the server.

: generating HTML code from a mix of Python and HTML, this is done in Flask using Jinja2.

: a template engine for the Python programming language. It’s the software that takes the mix of HTML and Python and renders it down to just HTML which is then sent to the user.

All the pieces of our app get bolted on in a structure called an "application factory"

We've got a handy little method that instantiates our app, loads the settings, and straps on all its expansion packs. Let's start our tour of the code where Flask is spawned. From "":

The T part of our MVT all starts with base.html.

The purpose of the base template is to give all the pages in your app common assets. This such as fonts, CSS files, nav bar. Every page must link to the base file. It is kept in the /templates folder, as base.html. The base template is like a picture frame, loading common elements like the nav bar, footer, and your little .

I can't remember where this picture in my notes came from but it's not my creation.

Sass makes CSS easier, even if you have to spend a few minutes here and there refreshing yourself on how to use the Sass tricks and how to compile your Sass down to CSS. I personally use a to manage this automatically.

Pick out a header and a body font at

Flash notification system is a great illustration of the power of templating
There we include the _message.html partial
Those are the options you've got. You can totally add your own.

Register a domain and point your domain’s to DigitalOcean’s nameservers:

Setup your server’s basic settings: This includes our ufw firewall: . Don't forget to disable root ssh login.

Setup python (check on your version of ubuntu). You're not trying to get a demo app online, we're mostly using commands like sudo apt install python3.7-dev: Make sure we have the basics for our database (install, install, install!):

Install and configure nginx, your webserver (remember the ): -[ at this point you should be able to go to http://your-domain and see a blank, nginx page ]-

Update your git repository and (). We’ve got to package your app ready to ship. Calling the deployment of software “shipping” is really cool and people think you’re cool when you say it. So instead of "setting up my app on a remote server" we can say, "shipping a new version." Nice.

Pull your app’s repo and setup your dependencies before serving up your app: Notes to complement the Digital Ocean guide:

Helpful articles if you’re running into some trouble:

(adjust to the version of Ubuntu you're using)

Secure your HTTP connection: sudo apt install python-certbot-nginx sudo certbot --nginx -d mysite.net

If you modified any db.Column then, you need to track that migration on . Reading the is how you can best safeguard your users’ data.

Get ready to handle errors:

is an awesome tool to get notifications of any error happening on your server

From here on out, your project is going to vary from everyone else’s. Once your models are done, you’ve now got to build out each view and template that will serve the workflow of your . Work with your teacher to identify what your MVP needs to do, (we’ll call this your requirements based off of the ). Once we work out what exactly you’re building in your module, we’ll populate your Trello backlog with loads of tasks. And as we solve those weird tasks, we’ll start to build the collection of topics below.

The term decorators in programming refers to a sort of flag or notice put at the start of a method to signal some sort of special treatment. We use @login_required to trigger Flask-Security’s verification that the user is carrying the encrypted token from our system given to a confirmed user. I would imagine verification of authority and privileges is the most common reason to use a decorator in Flask. We use them .

The form is our primary method of collecting information from the user. Depending on your application's need, you may need to looking closely into . Meanwhile, here are a few recipes that have been requested.

The most typically recommended answer is the .

(placeholders)

Let’s say you want to query the database for a user’s contacts with a built-in relationship such as current_user.contacts. You can get a list back from the database with just that one command. However, what if you know you’ll always need additional filters on that query. You don’t want the results quite so fast, instead you’d like the SQLAlchemy query not to complete its task but rather to keep the search open and ready for additional filtering or sorting.

( of a post)

Launch your app and check it out. ?

(go back into psql and connect to our db then what we made)

We use as a sort of bubble that contains our version of Python, Flask, and all the many other libraries used. Each library is likely to see improvements and security fixes. It’s important to keep this codebase updated but it’s an awfully risky process. Updates might change how some of the libraries work and may force you to change or cause new bugs. Best practice is to keep a previous version of your handy and to build thorough .

Before asking to do a lot of work, you may want it upgrade it first: pip install --upgrade pip

Inside docs/ folder are files produced by .

There's a few ways to trigger a database query. I like to call the object statically so I can explain to students about those terms. You'll more often see db.session.query(Post). .

this folder to your codebase
https://runestone.academy/runestone/books/published/apcsareview/index.html
http://ice.cc.gatech.edu/apexam_final/index.jsp
https://codingbat.com/java/AP-1
Stack
HTML and CSS:
JavaScript:
HTTP Request
Shell/CLI
SSL Encryption:
Operating System Service
Python
Framework:
link
SQL:
minicomputers
mainframes
supported
distributed databases
computer systems
users
local-area network
access
PostgreSQL
object-relational database management system
Interpreter
Flask Application Context
Module
Virtual Environment
Libraries
Dependencies
Git Version Control
Object
Method (Python):
Parameter:
Constructor (init method)
Inheritance
DocString Comment
Ping Pong Sprite and Sound Resources
Mario Sprite Sheet
Enemy Sprite Sheet
Flying Enemy Sprite Sheet
Mario Tileset
Breakout Resource Folder
their design patterns
Model-View-Controller:
ER Diagrams/UML
Association Table
ORM
SQL Alchemy
Migration
Route
Flask Session
Render
Jinja2 Template
Demystifying Flask’s Application Factory
See how much of the documentation you can read before your brain wimps out
favicon
VSCode extension
fonts.google.com
/etc/nginx/sites-available/myproject
server {
    server_name flaskinni.org www.flaskinni.org;

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/home/yourname/myproject/flaskinni.sock;
    }

    location /static {
        alias /home/yourname/myproject/app/static;
        expires 2d;
    }

    gzip on;
    gzip_vary on;
    gzip_min_length 10240;
    gzip_proxied expired no-cache no-store private auth;
    gzip_types text/plain text/css text/xml text/javascript application/x-javascript a$
    
}
import random, string
''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(40))
$('.confirmation').on('click', function () { 
return confirm('Are you sure?'); 
});
// HIDE PAID BILLS
function hidePaidBills(){
    $('.bill-paid').each(function() {
        $(this).hide();
    })
models.py

class Company(db.Model):
    """
    An organization that will serve as the primary contact point between projects
    """
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80))    
    description = db.Column(db.Text)
    address = db.Column(db.Text)  # where to send the bill?
    website = db.Column(db.String(120)) 
    active = db.Column(db.Boolean())
    
    # ONE-TO-MANY relationships
    invoices_issued = db.relationship('Invoice', back_populates='issuer', foreign_keys="Invoice.issuer_id", lazy='dynamic')
    invoices_received = db.relationship('Invoice', back_populates='recipient', foreign_keys="Invoice.recipient_id", lazy='dynamic')
    
    # MANY-TO-MANY relationships
    users = db.relationship("Company_User", back_populates="company") # association table: connects a user to a company

    def __repr__(self):
        if self.name:
            return self.name
        else:
            return "Company ID#%d" % self.id
models.py
class Story(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(80))
    subtitle = db.Column(db.String(80))
    description = db.Column(db.Text)
    order_in_series = db.Column(db.Integer)
    image = db.Column(db.String(125))
    slug = db.Column(db.String(125), unique=True)
    publish_date = db.Column(db.DateTime)
    live = db.Column(db.Boolean)
    series_id = db.Column(db.Integer, db.ForeignKey('series.id'))
    
    # relationships
    series = db.relationship("Series", back_populates="stories")
    chapters = db.relationship('Chapter', back_populates='story', lazy='dynamic')
    characters = db.relationship('Character_Story', back_populates='story')
    users = db.relationship("Story_User", back_populates="story")
models.py
class Device(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    name = db.Column(db.String(80))
    model_number = db.Column(db.String(80))
    serial_number = db.Column(db.String(80))
    created_date = db.Column(db.DateTime)
    live = db.Column(db.Boolean)
    
    # relationships
    user = db.relationship("User", back_populates="devices")
    tasks = db.relationship("Task", back_populates="device")

    # return the date in readable English    
    @property
    def created_on(self):
        return humanize.naturaltime(self.created_date)

    def __init__(self, user=None, name=None, model_number=None, serial_number=None, live=True):
            if user:
                self.user_id = user.id

            self.name = name
            self.model_number = model_number
            self.serial_number = serial_number
            self.live = live
            self.created_date = datetime.now()

    def __repr__(self):
        return '<Device %r>' % self.name
models.py
class Group(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80))
    school_id = db.Column(db.Integer, db.ForeignKey('school.id'))
    image = db.Column(db.String(125)) # could be the logo, team photo, whatever..
    live = db.Column(db.Boolean)
    body = db.Column(db.Text)
    meeting_place = db.Column(db.Text)
    meeting_time = db.Column(db.Text)
    
    school = db.relationship('School', back_populates='group')
    users = db.relationship('Membership', back_populates="group")
    announcements = db.relationship('Announcement', back_populates='group')
    # get the whole image path
    @property
    def imgsrc(self):
        if self.image:
            return uploaded_images.url(self.image)
        else:
            return None

    def __init__(self, user=None, name=None, body=None, meeting_place=None, live=True, meeting_time=None):
        self.school_id = user.school_id
        self.name = name 
        self.body = body
        self.meeting_place = meeting_place
        self.meeting_time = meeting_time
        self.live = live

    def __repr__(self):
        if self.name:
            return "Group %s" % self.name
        else:
            return 'Group #%d' % self.id

    def has_member(self, user):
        membership = db.query(Membership).filter_by(user_id=user.id, group_id=self.id).first()
        return bool(membership and "applicant" not in membership.role)
def some_function():
    """
    This function doesn't do anything. It's just an example of building-in 
    the explanations that may one day enable your app to grow. 
    """
    some_object.different_function(example_param)
@app.route('/superadmin')
@roles_required('admin')
def superadmin():
    data = {}
    data['users'] = User.query.all()
    return render_template('my_module/superadmin.html', data=data)
	<tbody>
	    {% for user in data['users'] %}
		<tr>
			<td>{{ user.first_name }}</td>
			<td>{{ user.last_name }}</td>
			<td>{{ user.email }}</td>
			<td>22 Jun 1972</td>
			<td><span class="badge badge-success">Active</span></td>
			<td class="text-center">
				<div class="list-icons">
					<div class="dropdown">
						<a href="#" class="list-icons-item" data-toggle="dropdown">
							<i class="icon-menu9"></i>
						</a>

						<div class="dropdown-menu dropdown-menu-right">
							<a href="{{ url_for('user.edit_view', id=user.id, url=url_for('superadmin')) }}" class="dropdown-item"><i class="icon-pencil"></i> Edit object</a>
						</div>
					</div>
				</div>
			</td>
		</tr>
		{% endfor %}
	</tbody>
LogoTheming Bootstrapgetbootstrap
https://www.youtube.com/watch?v=zOPA0NaeTBkwww.youtube.com
LogoAdobe XD | Fast & Powerful UI/UX Design & Collaboration ToolAdobe
LogoLearn XD Prototyping | Adobe XDAdobe
LogoSketchSketch
LogoFigma: the collaborative interface design tool.Figma
// Make sure that only the active player is able to fire the gun.
// Also, no players should be able to fire if we are between turns 
// (transitioning from player to player)

if (obj_controller.WhoseTurn == myName) and (obj_controller.Transitioning == false){
    
    // Check to see if the the spacebar is released.
    if (keyboard_check_released(vk_space)){
   	 

   	 // The xdistance and ydistance is the difference between the origin 
 // position of the cannon and the end of the barrel at any given rotation.  

 // This value is basic trigonometry for a right triangle if you know the   
 // hypotenuse (the barrel sprite width -- in this case 64) and the angle.
   	 ydistance = 64 * (sin(degtorad(Barrel_Rotation)));
   	 xdistance = 64 * (cos(degtorad(Barrel_Rotation)));
   
   
         // instance_create_depth will create an object at a specific depth.  (100 is generally the
   	 // background.  We are creating obj_bullet at the x and y of the firing turret and shifting the
   	 // bullet based on the angle of the barrel.  
   	 
   	 // Because we are using "with" the things within the { } will apply to the thing being created.
   	 // In this case, we are giving the bullet the barrel rotation value of the turret which is
   	 // shooting it off.  We have to use other. because we are actually doing this from within the
   	 // bullet object, not the turret.

   	 with instance_create_depth(x+xdistance,y-ydistance,50,obj_bullet)
   		 {
   			 direction = other.Barrel_Rotation;
   		 }
   		 
   	 // We are adding an alarm in obj_controller and setting letting the game know we are between turns
   	 // so that players can't fire off multiple bullets and can't accidently fire off their opponent's
   	 // shot.  

   	 // We use room_speed for the alarm because we can multiply our Frames per second by a time in 
   	 // seconds for a more intuitive control.  At 30 FPS, we could have also put in a value of 30.
   	 obj_controller.alarm[1]= room_speed * 1 //seconds;
   	 obj_controller.Transitioning = true;
    }
}

// We will finish off our step event by turning the gravity back on if the turret
// is not moving and there is nothing under it (a box just got destroyed for
// instance) OR if there is fire directly under the turret.  We want the turret
// to fall into the fire.

if ((speed == 0 and place_empty(x,y+1)) or place_meeting(x,y+1,obj_fire))
{
    gravity = 1;
}

138KB
Unity_HotKeys_Win.pdf
pdf
Shortcut reference sheet
142KB
Unity_HotKeys_Mac.pdf
pdf

1: Class Overview

Expectations

We will be learning C# programming and Unity development during this course. All the concepts will be taught through the creation of games. Through tutorials, you will be able to work at your own pace and return to concepts which might be confusing. Mr. Vanek will be available to help if you have bugs that crop up in your programming and to clarify points in the tutorials.

In each unit, you will be responsible for completing an assignment which builds on the concepts you have learned. Feel free to flex your creative design muscles, especially in the assignment portion of the game. Adding extra features or finding new ways to accomplish them will help your game and your learning.

For the final project of the semester, you will be developing your own game. If you have good ideas for the form the game may take during the course of the semester, be sure to write them down.

3D Modeling & Fabrication

This course focuses on what it means to make art in the modern world. Students will use the latest technology to explore digital painting, sculpting using computer controlled wood cutters and 3D printers, and interactive works using programmable electronics motors and sensors.

LogoShuffling - Elementary Sorts | CourseraCoursera
LogoRoyalty Free 2D Game AssetsGame Art 2D
LogoFree 2D Game Assets - CraftPix.netCraftPix.net
LogoOpenGameArt.orgOpenGameArt.org
LogoSprite Game Assets from GraphicRiverGraphicRiver
LogoModular Applications with Blueprints — Flask Documentation (1.0.x)
Flaskinni comes with one blueprint. You'll probably want to add more soon
LogoThe Flask Mega-Tutorial Part II: Templatesmiguelgrinberg
If you give this guide up and follow Mr. Grinberg's exclusively I won't judge.
LogoSass: Sass Basics
LogoBuilding a secure admin interface with Flask-Admin and Flask-SecurityMedium
LogoFlask-Security — Flask-Security 3.0.0 documentation
https://www.digitalocean.com/community/tutorials/how-to-point-to-digitalocean-nameservers-from-common-domain-registrars
https://www.digitalocean.com/community/tutorials/an-introduction-to-digitalocean-dns
https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-18-04
https://www.digitalocean.com/community/tutorials/how-to-setup-a-firewall-with-ufw-on-an-ubuntu-and-debian-cloud-server
https://www.digitalocean.com/community/tutorials/how-to-install-python-3-and-set-up-a-programming-environment-on-ubuntu-18-04-quickstart
https://stackoverflow.com/questions/28253681/you-need-to-install-postgresql-server-dev-x-y-for-building-a-server-side-extensi
overview from the beginning of class
https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-16-04
your requirements.txt
video guide
https://www.digitalocean.com/community/tutorials/how-to-serve-flask-applications-with-uswgi-and-nginx-on-ubuntu-18-04
https://stackoverflow.com/questions/39937071/uwsgi-configuration-with-flaskapp
Setup postresql on your server
https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04
your db
Flask-Migrate documentation
http://flask.pocoo.org/docs/1.0/errorhandling/
Sentry.io
MVP
SRS stage of the IEEE software lifecycle
http://flask.pocoo.org/docs/1.0/patterns/viewdecorators/
in Java to notify the system we’re overriding a parent’s method
wtforms
QuerySelectField
https://stackoverflow.com/questions/46921823/dynamic-choices-wtforms-flask-selectfield
https://stackoverflow.com/questions/9749742/python-wtforms-can-i-add-a-placeholder-attribute-when-i-init-a-field
http://screencast-o-matic.com/watch/cFfb2obVJJ
http://docs.sqlalchemy.org/en/latest/orm/backref.html#relationships-backref
http://docs.sqlalchemy.org/en/latest/orm/loading_relationships.html
let’s add a new record
Not pretty, right
let’s delete
https://pythonhosted.org/Flask-Mail/
https://www.twilio.com/docs/sms/quickstart/python
VirtualEnv
requirements.txt
unit tests
pip
Flaskinni's
Sphinx
http://flask.pocoo.org/docs/0.12/testing/
https://www.codementor.io/sheena/understanding-sqlalchemy-cheat-sheet-du107lawl
https://www.codementor.io/sheena/understanding-sqlalchemy-cheat-sheet-du107lawl
https://www.codepowered.com/manuals/SQLAlchemy-0.6.9-doc/html/orm/query.html
https://www.codementor.io/sheena/understanding-sqlalchemy-cheat-sheet-du107lawl
https://stackoverflow.com/questions/4926757/sqlalchemy-query-where-a-column-contains-a-substring
https://www.codementor.io/sheena/understanding-sqlalchemy-cheat-sheet-du107lawl
https://www.python.org/dev/peps/pep-0257/#what-is-a-docstring
More info for the try-hards

Game 4: Final project

Assignment

For the final project, you will be designing and executing a game of your own design. This will be a proof of concept game. The importance is placed on the game's design and programming, not on how it looks. Make sure that levels are playable before working too much on art assets.

The final project needs to fulfill the following requirements:

  • The program runs with no bugs that break the game.

  • The game should be FUN. This is a game, after all.

  • The project should have a minimum of two workings animation with transitions between them.

  • The project should have a minimum of three levels or be procedurally generated. Levels should have transitions between them.

  • The project should use some aspect of user interface (text) either via instructions or heads up display.

  • The project should have a good use of materials and / or material assets from the asset store.

FAQs

This page will be updated with videos to offer greater clarity or detail about Unity concepts. This is also the repository for student requested videos which are outside the classroom content.

EXTRA DETAIL

INPUTS

CLASSES

GITHUB

STUDENT REQUESTED TUTORIALS

Lerping The Camera

Nav Meshes

Procedural Levels

Terrain

VR

First Person Controller

Game 2: Tanks

Game Overview

Building The Game

1: Tank Design

2: Movement

Movement Part 2

3: Turret Rotation

Turret Rotation Part 2

Turret Rotation - A Quick Fix

4: Controller Diagram

5: Camera Control

6: Particle Effects

16KB
Particle.png
image
Particle File

The above file is for the Tank Particles 1 video if you don't have access to Photoshop or Illustrator.

7: Materials

8: Destructible Environment

9: Audio

10: Split Screen View

11: Tank Targeting and Hit Points

Assignment

Make sure all tutorial sections have been completed and all features are implemented correctly.

Add the following to your game:

1: Make the tanks a target with appropriate health. (Video was added above for this assignment) 2: Add a non-destructible wall with metallic material.

3: Create one extra piece of destructible terrain. 4: Add a secondary fire weapon (missile, artillery, machine gun, laser, mine, etc) with it's own particle system. 5: Make a power up that lasts for a limited amount of time and affects some aspect of the game (speed, fire rate, damage, etc). 6: Create three separate arenas with realistic materials for everything. 7: Create a start screen for your game. When a player hits Start, randomize the arenas and begin the game. 8: Add a win screen to the game and prompt players to restart once they both hit X.

9: Turn in the game through GitHub (make sure you set it up with a Unity GitIgnore).

Learning Targets

OLD: GIT

This video will show you how to prepare your video for version control and turning in projects.

Syncing your project

Installation

Download the fusion 360 software from the link below and install it on your computer. You will have to create an Autodesk account. Please use your Gilmour email.

Publish to Opera

DO NOT DO:

FAQ

// Pac Man Ghost Movement Code
if (place_snapped(64,64)){
	var changed = false;
	var randomDir = irandom_range(1,4);
	
	if (hspeed == 0){
		if (randomDir == 1){
			if (!place_meeting(x - ghostSpeed, y, obj_wall)){
				speed = ghostSpeed
				direction = 180;
				changed = true;
			}
		} else if (randomDir == 2){
			if (!place_meeting(x + ghostSpeed, y, obj_wall)){
				speed = ghostSpeed
				direction = 0;
				changed = true;
			}
		}
	}
	if (vspeed == 0 and changed == false){
		if (randomDir == 1){
			if (!place_meeting(x, y - ghostSpeed, obj_wall)){
				speed = ghostSpeed
				direction = 90; 
			}
		} else if (randomDir == 2){
			if (!place_meeting(x, y + ghostSpeed, obj_wall)){
				speed = ghostSpeed
				direction = 270;
			}
		}
	}
}

Game 3: Third Person Platformer

Finished Game Overview

Building The Game

0: Setup

1: Camera Relative Controls

2. Jumping

3: Physics materials

4: Intro to Animations

5: Building Assets: Probuilder and MagicaVoxel

6: Enemy AI

Assignment

1) Create five levels in which the player needs to explore in a controlled way. The level should have a start point and an end point. Think about how far / high characters can jump to keep parts blocked off.

Make sure you control how the players can progress through the level with terrain. You should use Probuilder, MagicaVoxel, or both to design your level. You can also use other resources such as physics materials.

2) Add at least one "hidden area" to your level.

3) Add at least one area which requires an item to progress.

4) Create one power up for your character (different than the progression item).

5) Use slime enemies in the environment. If your player touches a slime, restart the level (or if you are feeling like a bit of a challenge, make checkpoints and move the player to the last touched checkpoint).

6) Create at least one additional "humanoid" enemy complete with animations. Make sure the player can interact with the enemies in some way (attack, avoid, etc)

Learning Targets

Parametric Modeling

Assignment:

Design and create an invention using parametric modeling.

Your design should:

  • Be parametric (add parameters first, make sure your design doesn't break when you change them) (3 points)

  • Have at least three pieces that come together to function. (6 points)

  • be 3D printable (no overhangs, flat base for printing) (2 points)

  • have no piece greater than 200mm in a direction. (2 points)

  • Include final renders (2 points)

You will be turning in 3 things for this project, the fusion file, the printable STL files, and multiple angle renders of the finished design.

Appearances and Rendering

Patterns

Fusion 360 Interface and Sketch Modeling

Keychain requirements (1 point each)

Your keychain should:

  • Visually tell me something about you (include some image).

  • Be sized appropriately for purpose (60mm x 60mm max)

  • Include your name with the text tool.

  • Have a hole to support keychain rings (6mm).

  • Be a single body.

  • Have a flat, printable bottom.

Primitive Modeling

Assignment:

In your group, you will create a community of buildings which should relate to each other and a theme of your choosing.

Your building should:

  • serve a different purpose in your group's community. (1 points)

  • be integrated into the community via the chosen theme. (2 points)

  • be in scale to the rest of your group's models (10mm = 1ft, for example). (2 points)

  • be modeled from primitives as well as sketch shapes. (4 points)

  • use several of the modify tools. (2 points)

  • include details that are unique to different sides of the building (as a person walks around it, it changes / has unique features). (3 points)

  • have appropriate textures for final renderings. (2 points)

  • include 4 finished renders of the building, each communicating a different detail. (4 points)

OLD: Distance Learning Setup

This page describes how to get setup for distance learning, spring 2020.

In case you forgot what a drop-down looks like?

MagicaVoxel:

https://gamemaker.io/en/tutorials/publish-to-gxgames-tutorial#_ga=2.75440849.2104760815.1662492576-1508294388.1639755424
Mario Resources
http://www.voxelmade.com/magicavoxel/
//Put this code in the update

        for (int i = 0; i < 20; i++)
        {
            if (Input.GetKeyDown("joystick 1 button " + i))
            {
                print("joystick 1 button " + i);
            }
        }


        if (Input.GetAxis("TestInput") != 0 )
        {
            print(Input.GetAxis("TestInput"));
        }

Python review

Functions, Variables, Comments and Simple Data Types

Conditionals: if / elif / else

Loops: for / while

Defined Functions

3D Printing Concerns

Assemblies and Mechanical Design

Software Installation

#!/usr/bin/env pybricks-micropython
from pybricks.hubs import EV3Brick
from pybricks.parameters import Color

# setup section
ev3 = EV3Brick()
screen = ev3.screen
screen.clear()

# Main Program
screen.draw_text(10, 10, "Everything", text_color=Color.BLACK, background_color=None)
screen.draw_text(10, 30, "is", text_color=Color.BLACK, background_color=None)
screen.draw_text(10, 50, "Awesome!", text_color=Color.BLACK, background_color=None)

ev3.speaker.beep()

while (True):
    wait = 0
    

Sculpt Tools

Final Assignment

Find a image of a cartoon character and create a sculpt based on that character. Simpler is better for this project. You should include the entire body of the character.

Building Community Gallery Page 2023

Famous Buildings

Bruno

Gino

Nate


COVID-19 Pandemic Inspired Buildings

Evie

Sam


Cartoon Community

Jesse

Alex

Jonas

Dominic


Fallout Community

Matthew

John

Zane

Calculator

Programming for the Ev3

Basic Drivetrain Setup:

Defining our own functions:

Basic Sensor Setup:

Laser Cutting

#!/usr/bin/env pybricks-micropython
from pybricks.hubs import EV3Brick
from pybricks.ev3devices import (Motor, TouchSensor, ColorSensor,
                                 InfraredSensor, UltrasonicSensor, GyroSensor)
from pybricks.parameters import Port, Stop, Direction, Button, Color
from pybricks.tools import wait, StopWatch, DataLog
from pybricks.robotics import DriveBase
from pybricks.media.ev3dev import SoundFile, ImageFile


# This program requires LEGO EV3 MicroPython v2.0 or higher.
# Click "Open user guide" on the EV3 extension tab for more information.


# Create your objects here.
ev3 = EV3Brick()


# Write your program here.
ev3.speaker.beep()
LogoStudent and Education Software | 1-Year License | Autodesk Education Communityautodesk
Design Analysis of a Level

Setting up for clarity

#!/usr/bin/env pybricks-micropython
from pybricks.hubs import EV3Brick
from pybricks.ev3devices import (Motor, TouchSensor, ColorSensor,
                                 InfraredSensor, UltrasonicSensor, GyroSensor)
from pybricks.parameters import Port, Stop, Direction, Button, Color
from pybricks.tools import wait, StopWatch, DataLog
from pybricks.robotics import DriveBase
from pybricks.media.ev3dev import SoundFile, ImageFile
from movementfunctions import line_follow

class MyRobot():
    def __init__(self):
        pass

    def new_function(parameters):
        pass
 

Kivy Basics

Kivy Video Overviews

// Basic Kivy Code (main.py)
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout

class Interface(BoxLayout):
    pass
    
class LayoutApp(App):
    pass
    
LayoutApp().run()

Widgets

Label

The label widget is used to create text on your screen.

  • text: "Hello World"

    • Displays "Hello World" on the interface

  • color: 1, 0, 0, 1

    • Color takes 4 numbers from 0 - 1. These correspond to RGB and Alpha

  • font_size: 32

    • Sets the font to 32 pt

  • markup: True

    • Allows you to add markups such as bold, italics, font in your text

    • [b] Bold [/b], [i] italics[/i], [font=times] Change the font to times [/font]

    • [s] strikethrough [/s], [u] underline [/u], [color=#hexcolor] change color [/color]

  • size_hint: 0.5, 0.5

    • changes the size of the text box in relation to horizontal width of the window and vertical height of the window.

  • size: 200, 200

    • Changes the size of the text BOX, not the text.


Button


TextInput

Python Turtle

Turtle assignment

Replit

Python basics (trinket.io)

Video 1

Terms:

Variables: Words that can store data. A variable might store a number, a word, a sentence or a list of things.

Operators: Basic math symbols for addition, subtraction, multiplication and division (+, -, *, /)

Functions: Commands which let us do things within the programs. Some functions are built in and some will be created by us!

Video 2

Terms:

Input: Getting information from outside the program. This might come from someone using your program in the case of an app, or from sensor data in the case of a robot.

Changing Variable Types: Sometimes we have to change variable types to allow them to interact. We do this with functions int() and str(). Remember that variables need to be alike if we want them to be able to interact!

Video 3

Terms:

Conditionals: Conditionals let us check for when something happens or when something is true. The most common of these is an if statement (which can be expanded to an if/else or and if / elif / else statement).

Boolean: A boolean is a specific type of variable, a True or False variable.

Assignment!

Competitive Robotics

The guide to getting involved in our school's FIRST Technology Challenge team.

Getting Started

  • Jump In Early: Don't wait! Attend team meetings, observe our workshops, and get a feel for different roles. Identify areas that ignite your interest and offer your help.

  • Choose Your Path: Our team operates through various sub-groups, each playing a crucial role in our robot's success:

    • Marketing Team: Be the face of the team, recruit new members, manage logistics, and prepare presentations for judges. Hone your communication and organizational skills.

    • Software Team: Dive into the world of coding, working alongside hardware engineers and the drive team. Maintain our codebase, troubleshoot issues, and post questions on online forums to expand your knowledge.

    • Hardware Team: Design and build robot components using CAD software, 3D printing, and various hand tools. Develop hands-on engineering skills and fix technical issues during competitions.

    • Drive Team: Take the spotlight by operating the robot during competitions. Strategize gameplays, execute maneuvers based on calls, and practice extensively to become a well-coordinated unit

Additional Resources:

Command Pattern

Conceptual overview of the "what" and "why" of Command pattern

The Command pattern is a fundamental design principle FTCLib uses, and understanding it will significantly enhance your coding experience. This page delves into the "what" and "why" behind this pattern, equipping you to write efficient and maintainable robot code.

What is Command Pattern?

The Command pattern boasts a rich history dating back to the late 1970s and early 1980s. The concept emerged within the Smalltalk and Xerox PARC communities, documented in publications like Anneliese Schürr's 1992 paper "Separation of Concerns and the Command Pattern." Initially focused on graphical user interfaces (GUIs), the pattern's flexibility was adopted in various software development domains.

Its popularity soared with the rise of design patterns in the 1990s, solidified by Erich Gamma et al.'s influential book "Design Patterns: Elements of Reusable Object-Oriented Software." This widespread recognition cemented the Command pattern as a valuable tool for promoting loose coupling, reusability, and maintainability in object-oriented programming.

The Command pattern originates from software design principles and offers a structured way to manage robot actions. Instead of writing long, blocking code sections, you create independent classes called Commands. Each Command encapsulates your robot's specific task, like driving forward, turning, or activating a mechanism.

Why Command Pattern?

Farewell, Blocking Code

Traditional robot programming often involves lengthy code blocks that execute sequentially, potentially hindering responsiveness and multitasking. If your robot is stuck inside of a loop that gradually moves a motor, it's not doing other things. It's blocked until you move on.

Non-blocking commands eliminate the need to do one thing at a time by having repeatedly called execute functions that run until their isFinished condition is reached. This allows the robot to perform multiple actions simultaneously. This means smoother operation and the ability to react to real-time events effectively.

Reusable Gems

Commands are designed for reusability. You can create a generic RotateCommandand adapt it for different distances or speeds across various parts of your code. This reduces code duplication and simplifies maintenance.

Collaborative Codebase

FTCLib encourages modularity with separate Command files. This translates to clear ownership and promotes a collaborative development environment. Team members can work on their specific Commands without worrying about conflicts in common code sections. Version control systems like Git become even more valuable as team members push their Command commits independently.

Utilities in FTCLib

FTCLib does much more than implement the Command pattern. We've got ourselves an extensive toolbox to elevate our robot programming:

Finer Motor Control:

  • Motor Wrappers: Simplify motor control with pre-built classes handling direction, speed, and encoder feedback.

  • PID Control Helpers: Fine-tune motor movements with built-in PID controllers for precise control.

Navigation Expertise:

  • Odometry Support: Implement robust navigation using odometry wheels. FTCLib calculates robot pose from encoder readings, simplifying movement and autonomous routines.

  • Path Following: Define and execute pre-defined paths for complex maneuvers and automated navigation.

Visionary Solutions:

  • EasyOpenCV Integration: Seamlessly incorporate computer vision tasks. Detect objects, track targets, and analyze the environment using EasyOpenCV's intuitive tools.

  • Camera Support: Access and manage multiple cameras on your robot, expanding your visual perception capabilities.

Sensor Fusion Power:

  • Sensor Wrappers: Interact easily with various sensors like gyros, accelerometers, and ultrasonic sensors. Access their data effortlessly for informed decision-making.

  • Data Fusion: Combine data from multiple sensors to better understand your robot's environment, enabling intelligent responses.

Additional Gems:

  • Telemetry: Log and display robot data on the Driver Station for debugging, monitoring, and optimization.

  • Logging: Record robot behavior for analysis and performance improvements.

  • Scheduling: Manage task execution precisely with the built-in scheduler, ensuring coordinated robot actions.

Video Overview

Kivy uses widgets as the basic building block for GUIs (Graphical User Interfaces). Widgets are objects which can be layed out on your screen and which perform specific tasks. Some examples are input fields, buttons and drop down menus. In this section, you will find an example of widgets we will use in the class as well as specific parameters which can control individual widgets. If you feel like digging deeper into your options,

Whether you're joining or a different FIRST Technology Challenge (FTC) team, we hope this guide will ease the process.

Moonshots' website:

FTC official website:

FTCLib documentation:

FTCSim:

Programming Resources:

the kivy documentation can be found here.
Gilmour's Moonshots
https://ga-moonshots.netlify.app/
https://www.firstinspires.org/robotics/ftc
https://docs.ftclib.org/ftclib/
https://ftcsim.org/
https://ftc-docs.firstinspires.org/en/latest/programming_resources/index.html#programming-tutorials
Gamma, Helm, Johnson and Vlissides are sometimes referred to as the Gang of Four or GoF

Subsystem

The composition of hardware components and their basic helper functions

What are subsystems in FTCLib?

An FTCLib Subsystem is like a part of your robot that controls specific tasks, such as driving, lifting an arm, or shooting a game element. Each subsystem has its own job and knows how to control the motors, sensors, or other components related to that job. By breaking the robot into subsystems, your code becomes easier to manage and update because each part is responsible for its own actions. Think of it like different departments in a company—each one has a clear purpose, making the whole robot work smoothly together.

Why do we use this Subsystem design?

The advantage of using subsystems in FTCLib is that it allows for smooth control of multiple parts of your robot at once. Organizing your code this way allows you to run several subsystems without everything happening in one big block. This means one thread can manage multiple subsystems simultaneously without commands blocking each other. For example, the robot can move and operate its arm, and if a new command interrupts a current action—like stopping the drive to shoot a game element—it can smoothly switch tasks without delays or confusion.

Example Subsystem

package org.firstinspires.ftc.teamcode.subsystems;

// EXAMPLE SUBSYSTEM
public class Arm extends SubsystemBase {
    // SUBSYSTEM ASSETS
    private final MyRobot robot;
    private final Servo wristServo, openServo, rollServo;
    public final MotorEx motor;
    // STATE VARIABLES
    private double wristAng = HardwareNames.WRIST_MIN;
    private double rollPos = HardwareNames.ROLL_MAX;
    private boolean isOpen = false;
    private int offset = 0;

    public Arm(MyRobot robot) {
        this.robot = robot;
        HardwareMap hardwareMap = robot.opMode.hardwareMap;

        // shoulder motor
        this.motor = new MotorEx(hardwareMap, HardwareNames.ARM_MOTOR_NAME);
        motor.setRunMode(Motor.RunMode.PositionControl);
        motor.setInverted(true);
        motor.setPositionCoefficient(HardwareNames.ARM_MOTOR_kP);
        motor.setPositionTolerance(HardwareNames.ARM_MOTOR_TOLERANCE);

        // servos
        wristServo = hardwareMap.get(Servo.class, HardwareNames.WRIST_SERVO_NAME);
        openServo = hardwareMap.get(Servo.class, HardwareNames.OPEN_SERVO_NAME);
        rollServo = hardwareMap.get(Servo.class, HardwareNames.ROLL_SERVO_NAME);
        wristServo.setPosition(wristAng);
        openServo.setPosition(HardwareNames.CLAW_CLOSED_POS);
        rollServo.setPosition(rollPos);
    }

    // -- EXAMPLE SERVO COMMANDS --
    public void travelMode() {
        closeClaw();
        wristServo.setPosition(0);
        wristAng = 0;
    }
    public void wristUp() {
        wristAng -= HardwareNames.WRIST_INC;
        wristAng = Range.clip(wristAng, HardwareNames.WRIST_MIN, HardwareNames.WRIST_MAX);
        wristServo.setPosition(wristAng);
    }
    public void wristDown() {
        wristAng += HardwareNames.WRIST_INC;
        wristAng = Range.clip(wristAng, HardwareNames.WRIST_MIN, HardwareNames.WRIST_MAX);
        wristServo.setPosition(wristAng);
    }
    public void openClaw() {
        openServo.setPosition(HardwareNames.CLAW_OPEN_POS);
        isOpen = true;
    }
    public void closeClaw() {
        openServo.setPosition(HardwareNames.CLAW_CLOSED_POS);
        isOpen = false;
    }
    public void toggleOpen() {
        if(isOpen) {
            closeClaw();
        } else {
            openClaw();
        }
    }
    public void toggleRoll() {
        if(rollServo.getPosition() >= .5){
            rollServo.setPosition(HardwareNames.ROLL_MIN);
            rollPos = HardwareNames.ROLL_MIN;
        } else{
            rollServo.setPosition(HardwareNames.ROLL_MAX);
            rollPos = HardwareNames.ROLL_MAX;
        }
    }

    @NonNull
    @Override
    public String toString() {
        return String.format(Locale.ENGLISH, "OPR: (%f, %f, %f)",
                openServo.getPosition(), wristServo.getPosition(), rollServo.getPosition());
    }
}

Hardware and Setup:

The Arm subsystem in our example demonstrates essential aspects of subsystem creation:

  1. Hardware References: Declares member variables like motor, wristServo, etc., linking them to hardware names from a centralized place for these "magic strings," such as HardwareNames.

  2. Motor Configuration: Sets up the motor for precise position control using MotorEx, defining parameters like PID coefficients and tolerances.

  3. Servo Initialization: Retrieves servo objects from the hardwareMap and sets their initial positions.

Helpful Methods:

Subsystems often include convenience methods to control hardware directly. The Arm class provides examples:

  • travelMode(): Sets the arm for driving by closing the claw, adjusting the wrist, and storing the new wrist position.

  • wristUp()/wristDown(): Increment/decrement the wrist servo position within set limits.

  • openClaw()/closeClaw(): Manipulate the claw servo based on an isOpen boolean flag.

  • toggleOpen()/toggleRoll(): Implement button-pressable actions using conditional logic.

State Management:

Subsystems can maintain internal state using variables like isOpen for the claw. The toString() method provides a human-readable snapshot of the subsystem's current state (servo positions in this case).

Where do state variables go?

There are state variables like wristAng and isOpen in this subsystem. Does every subsystem get unique state variables? Should we consolidate them into the MyRobotfile? These are organizational guidelines that are flexible and will need to be discussed so all programmers know how things ought to be organized.

Beyond Commands:

Remember, not every action needs a dedicated Command. Servos like the wrist can be adjusted directly using methods like wristUp(). They're instantaneous and aren't a threat to block off other commands. So here's how we can bind these to a button (more details in Running Your Code).

    Button dPadUpP2 = new GamepadButton(player2, GamepadKeys.Button.DPAD_UP);
    dPadUpP2.whileHeld(new InstantCommand(() -> {
        arm.wristUp();
    }));

Next Steps:

While this explanation covers the basics of subsystems, exploring the provided Robot OpMode will reveal how these subsystems are integrated and controlled within your robot's overall behavior. Remember, effectively utilizing subsystems is vital in writing well-structured and maintainable robot code in FTCLib.

https://docs.ftclib.org/ftclib/

Example Command

A function-by-function discussion of a Command's essential components

Commands are the heart of FTCLib, promoting clean and organized robot code. Before we get too technical, let's dissect a basic Command example, exploring its critical sections.

public class ExampleCommand extends CommandBase {

    private final double timeout;
    private Timing.Timer timer;

    // Constructor
    public ExampleCommand(double timeout) {
        this.timeout = timeout;
        // configure any other instance variables that may be helpful
        
        // which subsystem(s) are required for this command? 
        addRequirements(subsystem);
    }

    // Initialization
    @Override
    public void initialize() {
        timer.start(); // Start the timer
        
        // set any other starting variables required
    }

    // Execution loop
    @Override
    public void execute() {
        // command logic may as simple as keep power on and update sensors
 
    }

    // Check for completion
    @Override
    public boolean isFinished() {
        return timer.elapsedTime() > timeout;
        // add additional conditions to this to see if you're done
    }

    // Post-execution actions
    @Override
    public void end(boolean interrupted) {
        // cut power and clean up
    }
}

Constructor

When crafting a Command, the constructor serves as its architect, defining essential elements before the Command's execution:

1. Establishing Requirements:

  • Timeout: Specifies the maximum duration for the Command's execution, ensuring it doesn't run indefinitely. This is a default feature but can be eliminated for commands that run by default (like the DriveCommand)

  • Subsystem Dependencies: Identifies which robot subsystems (e.g., drive, arm, elevator) are crucial for the Command's operation. This declaration is accomplished through the addRequirements(subsystem) call. That subsystem will cancel any other commands when this one is run.

  • Handy References: Creates shortcuts to frequently used robot components, streamlining code and enhancing readability. Connection to our robot object allows us to check on its state variables.

2. Pre-Execution Setup:

  • The constructor executes during robot setup, preparing the Command before its actual launch. This separation from the initialize() method, which runs immediately before execution, allows for careful configuration and resource management.

Initialize

The initialize() method acts as the Command's launchpad, performing critical setup tasks right before execution:

1. Setting the Stage:

  • Timer Activation: Initializes the timeout timer using timer.start() to enforce the Command's duration.

  • Target Calculation:

    • RoadRunner: Constructs an Action object using actionBuilder for complex trajectories.

      action = drive.actionBuilder(drive.pose)
          .lineTo(new Pose2d(xCoordinate, yCoordinate, desiredHeading))
          .build();

2. Key Considerations:

  • Once and Done: initialize() executes only once before the Command's execution loop begins.

  • Preparation Focus: Its primary responsibility lies in configuring initial values, targets, and action plans, setting the stage for successful execution.

Essential Reminder:

  • Although initialize() lays the groundwork, the execute() method, covered next, drives the Command's actions and interacts with the robot's physical systems. This non-blocking and concurrent nature can be a new concept for high school programmers.

Execute

The execute() method is the Command's heart and soul, translating plans into action.

1. The Execution Loop:

Imagine execute() as a conductor, continuously calling the shots throughout the Command's lifespan. It doesn't have a set duration; it will keep getting called until its isFinished() method signals completion. However, it's crucial to avoid blocking calls like while loops or sleep() that would halt the entire robot program.

2. Concurrent Commands: Sharing the Stage Gracefully:

Remember our analogy of multiple Commands as athletes? They might perform simultaneously, especially if they don't require the same resources. execute() needs to consider this possibility, ensuring smooth cooperation and avoiding conflicts.

3. Key Principles:

  • Non-Blocking: Steer clear of blocking calls that would freeze the robot program. Instead, favor short, focused actions within execute() and rely on isFinished() for termination.

  • Concurrent-Friendly: Design your execute() logic to function correctly even when other Commands are running concurrently, as long as they don't interfere with the required resources.

4. Understanding the Challenge:

This non-blocking and concurrent nature can be a new concept for high school programmers. Here's an analogy to help:

Imagine juggling. Each Command is a ball you keep in the air. You can't hold onto any ball for too long (blocking call), or you'll drop the others (other Commands needing resources). But by quickly tossing and catching each ball (short actions), you can keep them all going simultaneously (concurrently).

Remember:

  • execute() is the action stage, but design it wisely to avoid blocking and ensure smooth cooperation with other concurrent Commands. It's like the insides of the while loops we're avoiding because they're blocking (and the condition of this avoided while loops is the isFinished)

  • Embrace non-blocking techniques and keep your execute() methods focused and efficient for optimal robot performance.

isFinished + end

The final act of our Command play unfolds in these two methods:

isFinished(): The Curtain Call Condition

Think of isFinished() as the stage manager, waiting for the right moment to signal the end of the Command's performance. Similar to the condition in a while loop, it continuously evaluates whether the Command has achieved its goal. If isFinished() returns true, the curtain falls, and the Command gracefully exits.

Key Considerations:

  • Exit Criteria: Define clear conditions for completion within isFinished(). Common criteria include:

    • Time elapsing (using the timer started in initialize())

    • Sensor readings reaching desired values

    • External signals (e.g., button press)

  • Concurrent Awareness: Remember other Commands might be waiting in the wings. Ensure your isFinished() logic doesn't hold onto resources unnecessarily, preventing other Commands from running.

@Override
public boolean isFinished() {
    return timer.elapsedTime() > timeout
        || robot.sensor.getValue() > targetValue;
}

end(): Taking a Bow (Even Interrupted)

The end() method serves as the post-performance cleanup crew, ensuring everything is left tidy after the Command finishes, whether naturally or interrupted by another Command.

Key Considerations:

  • Power Down: Stop motors, reset servos, and release any acquired resources.

  • State Management: If using an ENUM to track subsystem state, ensure it reflects the actual final state, especially if interrupted. Update the ENUM variable accordingly in end().

  • Cleanup Thoroughness: Leave the robot and subsystems ready for the next Command without lingering effects.

@Override
public void end(boolean interrupted) {
    robot.motor.stopMotor();
    robot.servo.setPosition(0.0);
    if (interrupted) {
        robot.subsystemState = STATE_UNFINISHED; // Update state if interrupted
    }
}

Hardware Team

Much of the CAD work discussed in this section uses skills built in our 3D Modeling & Fabrication class.

Software Team

Our team uses Java to program our robots. Many of the coding skills can be learned from our AP Computer Science course.

FTCLib: Calculates the encoder target position for precise motor control. See examples here:

https://docs.ftclib.org/ftclib/features/hardware/motors
https://code.visualstudio.com/code.visualstudio.com
3D Modeling & Fabrication
AP Computer Science

Under the Hood

The files that drive FTCLib

Before looking under the hood of our code, programmers should study the Command pattern's goals of organized, non-blocking code. We've done that ✅. You don't need to go past this point. We hardly ever need to touch these files. Programmers can contribute to a team by knowing how Command and Subsystem work together and how to run their code. Proceeding on means you want the next level. You're comfortable and open-minded about how this all works.

Robot.java

The secret to understanding how we turned FTC's code into a Command pattern is how the following two files connect. They sit in our utils folder, working their magic--we may never need to touch them. Let's start with Robot.java.

This file acts as an invisible layer, providing essential functionalities:

  • Shared State: The isDisabled static variable is a central flag accessible throughout your code, indicating robot state (enabled/disabled). The disable() and enable() methods allow external control over the robot's state during transitions between autonomous and teleop periods.

  • Command Control Center: Methods like reset(), run(), schedule(), and register() grant access to the CommandScheduler, the mastermind behind command execution and resource management. Think of it as the conductor of your robot's actions.

Beyond isDisabled: Expanding State Variables

Remember, the way the isDisabled variable controls state is not how we need to track our robot's current status. It doesn't need a static variable; we'll have easy access to the instance of our robot. We're not restricted to booleans. We'll use custom state variables of all sorts--here's an example that uses enums to represent various robot conditions:

CommandOpMode

Here's the most straightforward connection point between Command and FTC. This file is our translator.

Lifecycle Integration

CommandOpMode runs LinearOpMode's critical method runOpMode()method. That's it 🤯. Sure, we can also post telemetry updates, but the real essential bit is just that stupid run() call. That keeps our CommandScheduler working while satisfying the requirements for FTC gameplay.

Reset

The reset() method within both Robot and CommandOpMode plays a crucial role in managing Commands during various FTC gameplay scenarios. Here are some practical examples of when you might utilize it:

1. Autonomous Period Transitions:

  • Switching Strategies: During autonomous, imagine your robot first performs a pre-determined path using a pre-scheduled set of Commands. If external sensors detect an unexpected obstacle, you can call reset() in Robot or CommandOpMode to clear all running Commands and initiate a new set of Commands for obstacle avoidance or adaptation.

  • Recovering from Errors: If a sensor reading is deemed unreliable or a Command encounters an error, resetting can clear the current action and allow you to initiate a new Command for recovery or safe shutdown.

2. Teleop Period:

  • Button-Triggered Resets: Consider a button press on your gamepad that triggers reset() in CommandOpMode. This could be used to:

    • Cancel an ongoing movement Command if the driver wants to stop abruptly.

    • Reset arm or claw positions to known starting points for precise manipulation.

    • Restart a specific Command sequence for a repeated action.

3. Testing and Debugging:

  • Isolating Command Behavior: During testing, you might use reset() after each test run to isolate specific Commands and verify their functionality without interference from previous actions.

  • Reproducing Issues: If your robot exhibits unexpected behavior, strategically placing reset() calls can help reproduce the issue for easier debugging and troubleshooting.

public abstract class Robot {

    public static boolean isDisabled = false;

    /**
     * Cancels all previous commands
     */
    public void reset() {
        CommandScheduler.getInstance().reset();
    }

    /**
     * Runs the {@link CommandScheduler} instance
     */
    public void run() {
        CommandScheduler.getInstance().run();
    }

    /**
     * Schedules {@link com.arcrobotics.ftclib.command.Command} objects to the scheduler
     */
    public void schedule(Command... commands) {
        CommandScheduler.getInstance().schedule(commands);
    }

    /**
     * Registers {@link com.arcrobotics.ftclib.command.Subsystem} objects to the scheduler
     */
    public void register(Subsystem... subsystems) {
        CommandScheduler.getInstance().registerSubsystem(subsystems);
    }

    public static void disable() {
        isDisabled = true;
    }

    public static void enable() {
        isDisabled = false;
    }

}
public class MyRobot extends Robot {
    // ... other code
    public enum AprilTagToAlign {
        LEFT, CENTER, RIGHT, NONE
    }
    public AprilTagToAlign target;

    // ... any other subsystem will have access to check which target we want
}
public abstract class CommandOpMode extends LinearOpMode {
    /**
     * Cancels all previous commands
     */
    public void reset() {
        CommandScheduler.getInstance().reset();
    }

    /**
     * Runs the {@link CommandScheduler} instance
     */
    public void run() {
        CommandScheduler.getInstance().run();
    }

    /**
     * Schedules {@link com.arcrobotics.ftclib.command.Command} objects to the scheduler
     */
    public void schedule(Command... commands) {
        CommandScheduler.getInstance().schedule(commands);
    }

    /**
     * Registers {@link com.arcrobotics.ftclib.command.Subsystem} objects to the scheduler
     */
    public void register(Subsystem... subsystems) {
        CommandScheduler.getInstance().registerSubsystem(subsystems);
    }

    @Override
    public void runOpMode() throws InterruptedException {
        telemetry = new MultipleTelemetry(telemetry, FtcDashboard.getInstance().getTelemetry());
        initialize();

        waitForStart();

        // run the scheduler
        while (!isStopRequested() && opModeIsActive()) {
            run();
            telemetry.addData("hi", "hi");
            telemetry.update();
        }
        reset();
    }

    public abstract void initialize();

    public static void disable() {
        Robot.disable();
    }

    public static void enable() {
        Robot.enable();
    }

}

Running Your Code

Where our commands meet our subsystems

Starting Points

From the little Android driver station, here's where we select our autonomous or teleop opModes. Our autonomous entry point can have some options to indicate where the robot is starting on the field and any decisions about scoring that need to be made.

@Autonomous(name = "Autonomous - Primary")
public class AutoMcAutty extends CommandOpMode {
    /**
     * Set up robot such that it asks the player what our starting position is and kicks off
     * a FTCLib-style RoadRunner.
     */
    @Override
    public void initialize() {
        // QUERY USER TO DETERMINE OUR STARTING COORDINATES
        boolean isLeft = false;
        boolean isRed = false;
        boolean goForBoard = false;
        boolean gotoOpposite = false;
        // give player time to enter selection
        while(opModeInInit()) {
            // press X for blue and B for red
            if (gamepad1.x)
                isRed = false;
            else if (gamepad1.b && !gamepad1.start)
                isRed = true;
            // press dpad LEFT for left and RIGHT for right
            if (gamepad1.dpad_left)
                isLeft = true;
            else if (gamepad1.dpad_right)
                isLeft = false;
            // press Y to go for 45 and A just to park
            if (gamepad1.y)
                goForBoard = true;
            else if (gamepad1.a && !gamepad1.start)
                goForBoard = false;
            // DISPLAY SELECTION
            telemetry.addData("Position", "%s Team, %s Side", isRed ? "Red" : "Blue",
                    isLeft ? "Left" : "Right");
            telemetry.addData("Target Points", "%s", goForBoard ? "45" : "25");
            telemetry.update();
        }
        /*
         We build our robot. From here on out, we don't need this file. When we build the robot,
         all of our buttons are bound to commands and this class's parent, CommandOpMode, will
         continuously run any scheduled commands. We now slide into the WPILib style.
         We pass in our autonomous config variables, which signals to the robot we want to be in
         autonomous mode instead of in teleop mode, which would take no params besides this.
         */
        Robot m_robot = new MyRobot(this, isRed, isLeft, goForBoard);
    }

The teleop kick-off is much simpler:

@TeleOp(name="TeleOp - Primary")
public class DriveyMcDriverson extends CommandOpMode {

    /**
     * Autonomous is over. It's time to drive. Forget RoadRunner's need to track our position
     */
    @Override
    public void initialize() {
        /*
         We build our robot. From here on out, we don't need this file. When we build the robot,
         all of our buttons are bound to commands and this class's parent, CommandOpMode, will
         continuously run any scheduled commands. We now slide into the WPILib style.
         */
        Robot m_robot = new MyRobot(this);
    }

}

These two opModes go to the same place but get there using different constructors. The robot knows whether to run autonomous or teleop based on which constructor is being called.

MyRobot

This is where Commands get lined up for autonomous mode or bound to controller inputs in teleop. MyRobot is a soulless filename; typically, we'll rename this file each year after our robot.

public class MyRobot extends Robot {

    // INSTANCE VARIABLES
    public LinearOpMode opMode;
    public GamepadEx player1;
    public GamepadEx player2;
    public enum AprilTagToAlign {
        LEFT, CENTER, RIGHT, NONE
    }
    public AprilTagToAlign targetApril = AprilTagToAlign.NONE;

    // SUBSYSTEMS
    public MecanumDrive drive;
    public Arm arm;

    /**
     * Welcome to the Command pattern. Here we assemble the robot and kick-off the command
     * @param opMode The selected operation mode
     */
    public MyRobot(LinearOpMode opMode) {
        this.opMode = opMode;
        player1 = new GamepadEx(opMode.gamepad1);
        player2 = new GamepadEx(opMode.gamepad2);
        initTele();
    }
    // OVERLOADED CONSTRUCTOR THAT RESPONDS TO AUTONOMOUS OPMODE USER QUERY
    public MyRobot(LinearOpMode opMode, boolean isRed, boolean isLeft, boolean goForBoard) {
        this.opMode = opMode;
        initAuto(isRed, isLeft, goForBoard);
    }

    /**
     * Set teleOp's default commands and player control bindings
     */
    public void initTele() {
        // throw-away pose because we're not localizing anymore
        drive = new MecanumDrive(this, new Pose2d(0,0,0));
        register(drive);
        drive.setDefaultCommand(new DriveCommand(this));
        // start arm
        arm = new Arm(this);
        register(arm);

        /*
                .__                                      ____
        ______  |  |  _____   ___.__.  ____ _______     /_   |
        \____ \ |  |  \__  \ <   |  |_/ __ \\_  __ \     |   |
        |  |_> >|  |__ / __ \_\___  |\  ___/ |  | \/     |   |
        |   __/ |____/(____  // ____| \___  >|__|        |___|
        |__|               \/ \/          \/
        */
        Button aButtonP1 = new GamepadButton(player1, GamepadKeys.Button.A);
        aButtonP1.whenPressed(new InstantCommand(() -> {
            drive.toggleFieldCentric();
        }));

        Button bButtonP1 = new GamepadButton(player1, GamepadKeys.Button.B);
        bButtonP1.whenPressed(new InstantCommand(() -> {
            drive.resetFieldCentricTarget();
        }));

        Button xButtonP1 = new GamepadButton(player1, GamepadKeys.Button.X);
        Button yButtonP1 = new GamepadButton(player1, GamepadKeys.Button.Y);
        Button dPadUpP1 = new GamepadButton(player1, GamepadKeys.Button.DPAD_UP);
        Button dPadDownP1 = new GamepadButton(player1, GamepadKeys.Button.DPAD_DOWN);
        Button dPadLeftP1 = new GamepadButton(player1, GamepadKeys.Button.DPAD_LEFT);
        Button dPadRightP1 = new GamepadButton(player1, GamepadKeys.Button.DPAD_RIGHT);

        /*
                _                                    __
               (_ )                                /'__`\
         _ _    | |    _ _  _   _    __   _ __    (_)  ) )
        ( '_`\  | |  /'_` )( ) ( ) /'__`\( '__)      /' /
        | (_) ) | | ( (_| || (_) |(  ___/| |       /' /( )
        | ,__/'(___)`\__,_)`\__, |`\____)(_)      (_____/'
        | |                ( )_| |
        (_)                `\___/'
         */
        Button aButtonP2 = new GamepadButton(player2, GamepadKeys.Button.A);
        aButtonP2.whenPressed(new InstantCommand(() -> {
            arm.travelMode();
        }));

        Button bButtonP2 = new GamepadButton(player2, GamepadKeys.Button.B);
        bButtonP2.whenPressed(new InstantCommand(() -> {
            arm.toggleOpen();
        }));

        Button xButtonP2 = new GamepadButton(player2, GamepadKeys.Button.X);
        xButtonP2.whenHeld(new ArmMoveTo(this, ArmMoveTo.ArmPosition.GROUND));

        Button yButtonP2 = new GamepadButton(player2, GamepadKeys.Button.Y);
        yButtonP2.whenHeld(new ArmMoveTo(this, ArmMoveTo.ArmPosition.HIGH_DROP));

        Button dPadUpP2 = new GamepadButton(player2, GamepadKeys.Button.DPAD_UP);
        dPadUpP2.whileHeld(new InstantCommand(() -> {
            arm.wristUp();
        }));

        Button dPadDownP2 = new GamepadButton(player2, GamepadKeys.Button.DPAD_DOWN);
        dPadDownP2.whileHeld(new InstantCommand(() -> {
            arm.wristDown();
        }));

        Button dPadLeftP2 = new GamepadButton(player2, GamepadKeys.Button.DPAD_LEFT);
        dPadLeftP2.whileHeld(new InstantCommand(() -> {
            arm.rollNegative();
        }));

        Button dPadRightP2 = new GamepadButton(player2, GamepadKeys.Button.DPAD_RIGHT);
        dPadRightP2.whileHeld(new InstantCommand(() -> {
            arm.rollPositive();
        }));

    }

    /**
     * Used given starting position and call the corresponding commands
     */
    public void initAuto(boolean isRed, boolean isLeft, boolean goForBoard) {
        // TODO: Calculate pose for each of the four starting positions
        Pose2d start;
        // RED LEFT
        if(isRed && isLeft)
            start = new Pose2d(new Vector2d(0, 0), 0.0);
        // RED RIGHT
        else if(isRed)
            start = new Pose2d(new Vector2d(0, 0), 0.0);
        // BLUE LEFT
        else if(isLeft)
            start = new Pose2d(new Vector2d(0, 0), 0.0);
        // BLUE RIGHT
        else
            start = new Pose2d(new Vector2d(0, 0), 0.0);

        drive = new MecanumDrive(this, start);
        register(drive);
        arm = new Arm(this);
        register(arm);
        

        // locate prop, drop piece, withdraw and straighten out
        new SequentialCommandGroup(
                new ScanForProp(this,0,20, 4),
                new TurnToProp(this, 1),
                new InstantCommand(() -> {
                    arm.openClaw();
                    opMode.sleep(25);
                    arm.travelMode();
                }),
                new StrafeByDistance(this, 0, -2, 0.5),
                new RotateToZero(this, 2)
        ).schedule();

        // TODO: complete autonomous command sequence

    }
}

Two Constructors

  • One for teleop, requiring only the opMode object.

  • Another for autonomous, taking additional parameters so we know our starting position and what script to run (isRed, isLeft, goForBoard)

initTele

Default Command

Once our drive train drive is registered, we give it a default command, DriveCommand

  • defaultCommand is a special command assigned to a subsystem that continuously runs unless interrupted by another higher-priority command.

  • The DriveCommand will constantly watch joystick inputs as well as apply dead zones and field-orientated drive

  • If you press a button that triggers another command for the drive system (e.g., rotating), that command will interrupt the DriveCommand temporarily until it finishes.

  • Once the other command finishes, the DriveCommand automatically resumes as the defaultCommand, listening to joystick inputs again.

Keybindings

The MyRobot code demonstrates different ways to connect gamepad buttons with robot actions using FTCLib. Here's a breakdown of the standard methods and how they translate to gameplay scenarios:

1. whenPressed:

  • Definition: Executes a command once when the button is initially pressed.

  • Example: Pressing the A button on Gamepad 1 toggles the driving mode.

  • FTC Gameplay:

    • Use this for actions that only need to happen once per button press, like activating a boost ability or triggering a quick arm movement.

2. whenReleased:

  • Definition: Executes a command once when the button is released.

  • Example: Releasing the B button on Gamepad 2 closes the arm claw.

  • FTC Gameplay:

    • This is useful for actions that occur when you stop pressing the button, like stopping arm movement or ending a special ability.

3. whileHeld:

  • Definition: Continuously executes a command while the button is held down.

  • Example: Holding the d-pad on Gamepad 2 raises or lowers the arm's wrist.

4. toggleWhenActive:

  • Definition: Starts/stops a command each time the button is pressed, regardless of previous state.

  • Example: Not used in the provided code, but it could be used for toggling a light or other on/off functionality.

  • FTC Gameplay:

    • This is helpful for quickly activating and deactivating abilities without keeping the button held down.

Here's an example of how to link a button with a command using whileHeld:

Button dPadUpButton = new GamepadButton(gamepad2, GamepadKeys.Button.DPAD_UP);
dPadUpButton.whileHeld(new InstantCommand(() -> {
    arm.wristUp();
}));

This code creates a button listener for the up d-pad on Gamepad 2. When held down, it continuously executes a command that raises the arm's wrist.

initAuto

In MyRobot's initAuto function, the autonomous script takes shape. But how do you structure your commands? Let's delve into the options:

1. Sequential Commands:

  • Commands execute one after another, completing before the next starts.

  • Think of it as a step-by-step recipe: scan for the prop, turn towards it, open the claw, move closer, etc.

  • Benefits:

    • Easy to understand and troubleshoot.

    • Ensures each action finishes cleanly before proceeding.

  • Drawbacks:

    • Might be slower if some actions could happen simultaneously.

    • Less flexibility for complex maneuvers involving interactions or timing dependencies.

2. Concurrent Commands:

  • Multiple commands run simultaneously, sharing resources and potentially interacting dynamically.

  • Imagine multitasking: turning while moving closer or raising the wrist while opening the claw.

  • Benefits:

    • Can be more efficient if actions don't rely on each other's completion.

    • Offers greater flexibility for intricate robot behaviors.

  • Drawbacks:

    • Requires careful planning to avoid conflicts and ensure smooth coordination.

    • Debugging can be more challenging.

Writing the Script:

initAuto provides flexibility:

  • Within initAuto: You can build your entire autonomous sequence directly in our robot file using a new SequentialCommandGroup() with nested commands. This approach keeps everything centralized and concise.

  • Separate File: Files are kept shorter if we keep the autonomous procedure in its own SequentialCommandGroup file. This means a programmer tasked with this job could push changes to our GitHub repo with less concern for conflicts. 🤝

LogoA Visual Introduction to Pythontrinket.io
Logotrinket: run code anywheretrinket.io
Logo24.5. turtle — Turtle graphics for Tk — Python 2.7.18 documentation
Logotrinket: run code anywheretrinket.io
Logotrinket: run code anywheretrinket.io
Logotrinket: run code anywheretrinket.io
Logotrinket: run code anywheretrinket.io
LogoIntroductiongetbootstrap
Check that you're looking at the latest version
LogoCoding Tests & Assessments for Interviews - CodeSignalCodeSignal
psst... start with the arcade
This is probably woefully out of date by now.
A full example of theme implementation
Note to self: replace this old video. Many items here are outdated
https://www.youtube.com/watch?v=K5LBC3hLl8wwww.youtube.com
PrettyPrinted is an awesome channel and I recommend buying his courses
LogoBig O notationWikipedia
Respect the YouTube level grind.
LogoInsertion Sort vs. Selection SortStack Overflow