├── .gitignore ├── Gemfile ├── modules ├── hiring │ ├── img │ │ └── hiring.jpg │ ├── hiring_algorithm.zip │ ├── index.md │ ├── stories.md │ ├── instructions.md │ └── code │ │ └── hiring.py ├── input │ ├── img │ │ └── university.jpg │ ├── code │ │ └── validation.py │ ├── stories.md │ ├── index.md │ └── instructions.md ├── ethicalengine1 │ ├── img │ │ ├── people.jpg │ │ └── moralmachine.png │ ├── index.md │ ├── stories.md │ └── instructions.md └── ethicalengine2 │ ├── img │ ├── rescue.jpg │ └── moralmachine.png │ ├── code │ ├── main.py │ ├── docs.md │ ├── engine.py │ └── scenario.py │ ├── index.md │ └── instructions.md ├── _site ├── modules │ ├── hiring │ │ ├── img │ │ │ └── hiring.jpg │ │ ├── hiring_algorithm.zip │ │ ├── code │ │ │ └── hiring.py │ │ ├── index.html │ │ ├── stories.html │ │ └── instructions.html │ ├── input │ │ ├── img │ │ │ └── university.jpg │ │ ├── code │ │ │ └── validation.py │ │ ├── stories.html │ │ └── index.html │ ├── ethicalengine1 │ │ ├── img │ │ │ ├── people.jpg │ │ │ └── moralmachine.png │ │ ├── index.html │ │ └── stories.html │ └── ethicalengine2 │ │ ├── img │ │ ├── rescue.jpg │ │ └── moralmachine.png │ │ ├── code │ │ ├── main.py │ │ ├── engine.py │ │ └── scenario.py │ │ └── index.html ├── README.md ├── js │ └── common.js ├── feed.xml ├── jekyll │ └── update │ │ └── 2017 │ │ └── 08 │ │ └── 04 │ │ └── welcome-to-jekyll.html ├── docs │ └── faq.html └── assets │ ├── main.css │ └── minima-social-icons.svg ├── _includes ├── icon-github.html ├── icon-twitter.html ├── analytics.html ├── disqus_comments.html ├── icon-twitter.svg ├── head.html ├── icon-github.svg ├── footer.html └── header.html ├── _layouts ├── page.html ├── default.html ├── home.html └── post.html ├── README.md ├── js └── common.js ├── _posts └── 2017-08-04-welcome-to-jekyll.markdown ├── _config.yml ├── docs └── faq.md ├── index.md └── Gemfile.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'github-pages', group: :jekyll_plugins 3 | -------------------------------------------------------------------------------- /modules/hiring/img/hiring.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asg017/ethicalcs.github.io/master/modules/hiring/img/hiring.jpg -------------------------------------------------------------------------------- /modules/input/img/university.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asg017/ethicalcs.github.io/master/modules/input/img/university.jpg -------------------------------------------------------------------------------- /_site/modules/hiring/img/hiring.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asg017/ethicalcs.github.io/master/_site/modules/hiring/img/hiring.jpg -------------------------------------------------------------------------------- /modules/ethicalengine1/img/people.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asg017/ethicalcs.github.io/master/modules/ethicalengine1/img/people.jpg -------------------------------------------------------------------------------- /modules/ethicalengine2/img/rescue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asg017/ethicalcs.github.io/master/modules/ethicalengine2/img/rescue.jpg -------------------------------------------------------------------------------- /modules/hiring/hiring_algorithm.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asg017/ethicalcs.github.io/master/modules/hiring/hiring_algorithm.zip -------------------------------------------------------------------------------- /_site/modules/input/img/university.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asg017/ethicalcs.github.io/master/_site/modules/input/img/university.jpg -------------------------------------------------------------------------------- /_site/modules/hiring/hiring_algorithm.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asg017/ethicalcs.github.io/master/_site/modules/hiring/hiring_algorithm.zip -------------------------------------------------------------------------------- /_site/modules/ethicalengine1/img/people.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asg017/ethicalcs.github.io/master/_site/modules/ethicalengine1/img/people.jpg -------------------------------------------------------------------------------- /_site/modules/ethicalengine2/img/rescue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asg017/ethicalcs.github.io/master/_site/modules/ethicalengine2/img/rescue.jpg -------------------------------------------------------------------------------- /modules/ethicalengine1/img/moralmachine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asg017/ethicalcs.github.io/master/modules/ethicalengine1/img/moralmachine.png -------------------------------------------------------------------------------- /modules/ethicalengine2/img/moralmachine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asg017/ethicalcs.github.io/master/modules/ethicalengine2/img/moralmachine.png -------------------------------------------------------------------------------- /_site/modules/ethicalengine1/img/moralmachine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asg017/ethicalcs.github.io/master/_site/modules/ethicalengine1/img/moralmachine.png -------------------------------------------------------------------------------- /_site/modules/ethicalengine2/img/moralmachine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asg017/ethicalcs.github.io/master/_site/modules/ethicalengine2/img/moralmachine.png -------------------------------------------------------------------------------- /_includes/icon-github.html: -------------------------------------------------------------------------------- 1 | {% include icon-github.svg %}{{ include.username }} 2 | -------------------------------------------------------------------------------- /_includes/icon-twitter.html: -------------------------------------------------------------------------------- 1 | {% include icon-twitter.svg %}{{ include.username }} 2 | -------------------------------------------------------------------------------- /_layouts/page.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 |
5 | 6 | 7 | 8 | 9 |
10 |

{{ page.title | escape }}

11 |
12 |
13 | {{ content }} 14 |
15 | 16 |
17 | -------------------------------------------------------------------------------- /_includes/analytics.html: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% include head.html %} 5 | 6 | 7 | 8 | 9 | 10 | 11 | {% include header.html %} 12 | 13 |
14 |
15 | {{ content }} 16 |
17 |
18 | 19 | {% include footer.html %} 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Ethical Reflection Modules 3 | This is the Jekyll-generated back-end to [https://ethicalcs.github.io/](https://ethicalcs.github.io/). Most useful information is there. In particular, check out the [FAQ](https://ethicalcs.github.io/docs/faq.html) 4 | 5 | ## License 6 | Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License 7 | -------------------------------------------------------------------------------- /_site/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Ethical Reflection Modules 3 | This is the Jekyll-generated back-end to [https://ethicalcs.github.io/](https://ethicalcs.github.io/). Most useful information is there. In particular, check out the [FAQ](https://ethicalcs.github.io/docs/faq.html) 4 | 5 | ## License 6 | Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License 7 | -------------------------------------------------------------------------------- /_layouts/home.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | 5 |
6 | 7 | {{ content }} 8 | 9 | 21 | 22 | 23 | 24 |
25 | -------------------------------------------------------------------------------- /_includes/disqus_comments.html: -------------------------------------------------------------------------------- 1 | {% if page.comments != false and jekyll.environment == "production" %} 2 | 3 |
4 | 19 | 20 | {% endif %} 21 | -------------------------------------------------------------------------------- /_includes/icon-twitter.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /js/common.js: -------------------------------------------------------------------------------- 1 | var repoPath = "https://github.com/ethicalcs/ethicalcs.github.io/"; 2 | 3 | function getThisPath() 4 | { 5 | var path = window.location.pathname; 6 | if (path === "/") 7 | { 8 | path = "/index/"; 9 | path = path.slice(0, -1); 10 | } 11 | path = path.replace(".html",""); 12 | return path 13 | } 14 | 15 | function createPullRequestURL() 16 | { 17 | return repoPath + "edit/master" + getThisPath() + ".md"; 18 | } 19 | 20 | function createFileBugURL() 21 | { 22 | var title = "Fix content problem on " + getThisPath() + ".md"; 23 | return repoPath + "issues/new/?title=" + encodeURIComponent(title); 24 | } 25 | 26 | function runMainScript() 27 | { 28 | $("#file-bug-anchor").attr("href", createFileBugURL()); 29 | $("#pull-request-anchor").attr("href", createPullRequestURL()); 30 | } 31 | -------------------------------------------------------------------------------- /_site/js/common.js: -------------------------------------------------------------------------------- 1 | var repoPath = "https://github.com/ethicalcs/ethicalcs.github.io/"; 2 | 3 | function getThisPath() 4 | { 5 | var path = window.location.pathname; 6 | if (path === "/") 7 | { 8 | path = "/index/"; 9 | path = path.slice(0, -1); 10 | } 11 | path = path.replace(".html",""); 12 | return path 13 | } 14 | 15 | function createPullRequestURL() 16 | { 17 | return repoPath + "edit/master" + getThisPath() + ".md"; 18 | } 19 | 20 | function createFileBugURL() 21 | { 22 | var title = "Fix content problem on " + getThisPath() + ".md"; 23 | return repoPath + "issues/new/?title=" + encodeURIComponent(title); 24 | } 25 | 26 | function runMainScript() 27 | { 28 | $("#file-bug-anchor").attr("href", createFileBugURL()); 29 | $("#pull-request-anchor").attr("href", createPullRequestURL()); 30 | } 31 | -------------------------------------------------------------------------------- /_includes/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {% if page.title %}{{ page.title | escape }}{% else %}{{ site.title | escape }}{% endif %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | {% if site.google_analytics and jekyll.environment == 'production' %} 14 | {% include analytics.html %} 15 | {% endif %} 16 | 17 | -------------------------------------------------------------------------------- /_includes/icon-github.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /_layouts/post.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 |
5 | 6 |
7 |

{{ page.title | escape }}

8 | 16 |
17 | 18 |
19 | {{ content }} 20 |
21 | 22 | {% if site.disqus.shortname %} 23 | {% include disqus_comments.html %} 24 | {% endif %} 25 |
26 | -------------------------------------------------------------------------------- /modules/ethicalengine2/code/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from scenario import ( 3 | set_seed, 4 | Scenario 5 | ) 6 | from engine import ( 7 | ruleset1, 8 | ruleset2, 9 | ruleset3, 10 | my_decision 11 | ) 12 | 13 | 14 | def runSimulation(seed): 15 | print("===========================================") 16 | print("THE ETHICAL ENGINE") 17 | print("===========================================") 18 | print() 19 | 20 | set_seed(seed) 21 | keepRunning = True 22 | while keepRunning: 23 | scene = Scenario() 24 | print(scene) 25 | print() 26 | result = ruleset1(scene) 27 | # result = ruleset2(scene) 28 | # result = ruleset3(scene) 29 | # result = my_decision(scene) 30 | print() 31 | input('Hit any key to see decision: ') 32 | print('I choose to save the', result) 33 | print() 34 | 35 | # For breaking the loop 36 | response = input("Hit 'q' to quit or 'enter' to continue: ") 37 | if response == 'q': 38 | keepRunning = False 39 | 40 | print('Done') 41 | 42 | 43 | if __name__ == '__main__': 44 | seed = 42 45 | if len(sys.argv) >= 2: 46 | seed = int(sys.argv[1]) 47 | runSimulation(seed) 48 | -------------------------------------------------------------------------------- /_site/modules/ethicalengine2/code/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from scenario import ( 3 | set_seed, 4 | Scenario 5 | ) 6 | from engine import ( 7 | ruleset1, 8 | ruleset2, 9 | ruleset3, 10 | my_decision 11 | ) 12 | 13 | 14 | def runSimulation(seed): 15 | print("===========================================") 16 | print("THE ETHICAL ENGINE") 17 | print("===========================================") 18 | print() 19 | 20 | set_seed(seed) 21 | keepRunning = True 22 | while keepRunning: 23 | scene = Scenario() 24 | print(scene) 25 | print() 26 | result = ruleset1(scene) 27 | # result = ruleset2(scene) 28 | # result = ruleset3(scene) 29 | # result = my_decision(scene) 30 | print() 31 | input('Hit any key to see decision: ') 32 | print('I choose to save the', result) 33 | print() 34 | 35 | # For breaking the loop 36 | response = input("Hit 'q' to quit or 'enter' to continue: ") 37 | if response == 'q': 38 | keepRunning = False 39 | 40 | print('Done') 41 | 42 | 43 | if __name__ == '__main__': 44 | seed = 42 45 | if len(sys.argv) >= 2: 46 | seed = int(sys.argv[1]) 47 | runSimulation(seed) 48 | -------------------------------------------------------------------------------- /_posts/2017-08-04-welcome-to-jekyll.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Welcome to Jekyll!" 4 | date: 2017-08-04 10:04:48 -0400 5 | categories: jekyll update 6 | --- 7 | You’ll find this post in your `_posts` directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run `jekyll serve`, which launches a web server and auto-regenerates your site when a file is updated. 8 | 9 | To add new posts, simply add a file in the `_posts` directory that follows the convention `YYYY-MM-DD-name-of-post.ext` and includes the necessary front matter. Take a look at the source for this post to get an idea about how it works. 10 | 11 | Jekyll also offers powerful support for code snippets: 12 | 13 | {% highlight ruby %} 14 | def print_hi(name) 15 | puts "Hi, #{name}" 16 | end 17 | print_hi('Tom') 18 | #=> prints 'Hi, Tom' to STDOUT. 19 | {% endhighlight %} 20 | 21 | Check out the [Jekyll docs][jekyll-docs] for more info on how to get the most out of Jekyll. File all bugs/feature requests at [Jekyll’s GitHub repo][jekyll-gh]. If you have questions, you can ask them on [Jekyll Talk][jekyll-talk]. 22 | 23 | [jekyll-docs]: https://jekyllrb.com/docs/home 24 | [jekyll-gh]: https://github.com/jekyll/jekyll 25 | [jekyll-talk]: https://talk.jekyllrb.com/ 26 | -------------------------------------------------------------------------------- /modules/ethicalengine1/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Ethical Engine - Representation 4 | exclude: true 5 | --- 6 | 7 | ![university](img/people.jpg) 8 | 9 | - **Course:** CS 1/2 10 | - **Language:** Python 11 | - **Practice:** OOP design 12 | - **Approx. Time:** 1 hour 13 | 14 | ## Scenario: Teluta's Autonomous Cars 15 | _Teluta_ - an autonomous vehicle company - has made extraordinary strides in self-driving cars and is ready to go to market. But there is a corner case that needs to be addressed. In the rare instances in which _Teluta_ vehicles can sense an impending crash, they need a mechanism to quickly assess and value human life. Your job is to create the code for _Teluta_ that models a person. 16 | 17 | ## Assignment 18 | 19 | - [Part 1: Instructions](instructions.html) 20 | - [Part 2: Stories](stories.html) 21 | 22 | ## Supplemental Reading 23 | - [Facebook Lets Advertisers Exclude Users by Race](https://www.propublica.org/article/facebook-lets-advertisers-exclude-users-by-race) 24 | - [Dozens of Companies are Using Facebook to Exclude Older Workers from Job Ads](https://www.propublica.org/article/facebook-ads-age-discrimination-targeting) 25 | - [Minority Neighborhoods Pay Higher Car Insurance Premiums Than White Areas with the Same Risk](https://www.propublica.org/article/minority-neighborhoods-higher-car-insurance-premiums-white-areas-same-risk) 26 | - [Facial Recognition is Accurate, if You're a White Guy](https://www.nytimes.com/2018/02/09/technology/facial-recognition-race-artificial-intelligence.html) 27 | -------------------------------------------------------------------------------- /modules/input/code/validation.py: -------------------------------------------------------------------------------- 1 | 2 | def form(): 3 | """The form function that collects info from users""" 4 | # Get street number 5 | streetNum = get_street_num() 6 | # Get the age 7 | age = get_age() 8 | 9 | # Collect more pieces of information by writing more functions 10 | 11 | # Then, print out all our collected info in a form 12 | print("=====================") 13 | print("We've collected the following information:") 14 | print("- Street Number:", streetNum) 15 | print("- Age:", age) 16 | # add more 17 | print("=====================") 18 | 19 | 20 | def get_street_num(): 21 | """ EXAMPLE: Gets the user's street number. 22 | Repeats until a valid street number is given. 23 | Output: 24 | - streetNum: an integer representing the user's street number 25 | """ 26 | streetNum = input("Enter the street number of your address: ") 27 | 28 | # Check to see if it's empty! 29 | if streetNum == "": 30 | print("SORRY! You forgot to input your street number!\n") 31 | return get_street_num() 32 | # Check to see if it's a number! 33 | elif streetNum.isdigit() == False: 34 | print("SORRY! Your street number should be a positive number\n") 35 | return get_street_num() 36 | else: 37 | return streetNum 38 | 39 | def get_age(): 40 | """ Gets the user's age 41 | Repeats until a valid age is given 42 | """ 43 | age = input("Enter your age: ") 44 | # WRITE MORE CODE HERE 45 | return age 46 | 47 | 48 | # TODO: WRITE MORE FUNCTIONS THAT CHECK INPUT! 49 | 50 | 51 | # Runs the primary program 52 | form() 53 | -------------------------------------------------------------------------------- /_site/modules/input/code/validation.py: -------------------------------------------------------------------------------- 1 | 2 | def form(): 3 | """The form function that collects info from users""" 4 | # Get street number 5 | streetNum = get_street_num() 6 | # Get the age 7 | age = get_age() 8 | 9 | # Collect more pieces of information by writing more functions 10 | 11 | # Then, print out all our collected info in a form 12 | print("=====================") 13 | print("We've collected the following information:") 14 | print("- Street Number:", streetNum) 15 | print("- Age:", age) 16 | # add more 17 | print("=====================") 18 | 19 | 20 | def get_street_num(): 21 | """ EXAMPLE: Gets the user's street number. 22 | Repeats until a valid street number is given. 23 | Output: 24 | - streetNum: an integer representing the user's street number 25 | """ 26 | streetNum = input("Enter the street number of your address: ") 27 | 28 | # Check to see if it's empty! 29 | if streetNum == "": 30 | print("SORRY! You forgot to input your street number!\n") 31 | return get_street_num() 32 | # Check to see if it's a number! 33 | elif streetNum.isdigit() == False: 34 | print("SORRY! Your street number should be a positive number\n") 35 | return get_street_num() 36 | else: 37 | return streetNum 38 | 39 | def get_age(): 40 | """ Gets the user's age 41 | Repeats until a valid age is given 42 | """ 43 | age = input("Enter your age: ") 44 | # WRITE MORE CODE HERE 45 | return age 46 | 47 | 48 | # TODO: WRITE MORE FUNCTIONS THAT CHECK INPUT! 49 | 50 | 51 | # Runs the primary program 52 | form() 53 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Jekyll! 2 | # 3 | # This config file is meant for settings that affect your whole blog, values 4 | # which you are expected to set up once and rarely edit after that. If you find 5 | # yourself editing this file very often, consider using Jekyll's data files 6 | # feature for the data you need to update frequently. 7 | # 8 | # For technical reasons, this file is *NOT* reloaded automatically when you use 9 | # 'bundle exec jekyll serve'. If you change this file, please restart the server process. 10 | 11 | # Site settings 12 | # These are used to personalize your new site. If you look in the HTML files, 13 | # you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. 14 | # You can create any custom variable you would like, and they will be accessible 15 | # in the templates via {{ site.myvariable }}. 16 | title: Ethical CS 17 | email: evan.peck@bucknell.edu 18 | description: > # this means to ignore newlines until "baseurl:" 19 | baseurl: "" # the subpath of your site, e.g. /blog 20 | url: "" # the base hostname & protocol for your site, e.g. http://example.com 21 | github_username: ethicalCS 22 | 23 | # Build settings 24 | markdown: kramdown 25 | theme: minima 26 | plugins: 27 | - jekyll-feed 28 | 29 | # Google Analytics 30 | google_analytics: UA-127206371-1 31 | 32 | # Exclude from processing. 33 | # The following items will not be processed, by default. Create a custom list 34 | # to override the default setting. 35 | # exclude: 36 | # - Gemfile 37 | # - Gemfile.lock 38 | # - node_modules 39 | # - vendor/bundle/ 40 | # - vendor/cache/ 41 | # - vendor/gems/ 42 | # - vendor/ruby/ 43 | -------------------------------------------------------------------------------- /_includes/footer.html: -------------------------------------------------------------------------------- 1 | 55 | -------------------------------------------------------------------------------- /modules/hiring/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Ethical Hiring Algorithms 4 | exclude: true 5 | --- 6 | 7 | ![ethical hiring](img/hiring.jpg) 8 | 9 | - **Course:** CS 1 10 | - **Language:** Python 11 | - **Practice:** `for` loops, conditionals, `lists` 12 | - **Approx. Time:** 1-2 hours (depending on revisions) 13 | 14 | ## Scenario: Moogle's Hiring Filter 15 | Imagine you are working for _Moogle_, a well-known tech company that receives tens of thousands of job applications from graduating seniors every year. 16 | 17 | Since the company receives too many job applications for HR to individually assess in a reasonable amount of time, you are asked to create a program that algorithmically analyzes applications and selects the ones most worth passing onto HR. 18 | 19 | ## Assignment 20 | Students are presented _Part 1_ without **any** ethical framing or knowledge of _Part 2_. 21 | - [Part 1: Instructions](instructions.html) 22 | - [Part 2: Stories](stories.html) 23 | 24 | - [Zipped Instruction PDFs + Code (Updated 10/12/18)](hiring_algorithm.zip) 25 | 26 | ## Supplemental Reading 27 | - [Amazon scraps secret AI recruiting tool that showed bias against women](https://www.reuters.com/article/us-amazon-com-jobs-automation-insight/amazon-scraps-secret-ai-recruiting-tool-that-showed-bias-against-women-idUSKCN1MK08G) 28 | - [Hiring Algorithms are Not Neutral (Gideon Manna and Cathy O'Neil)](https://hbr.org/2016/12/hiring-algorithms-are-not-neutral) 29 | - [Can an Algorithm Hire Better Than a Human?](https://www.nytimes.com/2015/06/26/upshot/can-an-algorithm-hire-better-than-a-human.html) 30 | - [Now Algorithms Are Deciding Whom to Hire, Based on Voice](https://www.npr.org/sections/alltechconsidered/2015/03/23/394827451/now-algorithms-are-deciding-whom-to-hire-based-on-voice) 31 | -------------------------------------------------------------------------------- /_includes/header.html: -------------------------------------------------------------------------------- 1 | 35 | -------------------------------------------------------------------------------- /modules/ethicalengine1/stories.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Person Model - Stories 4 | exclude: true 5 | --- 6 | ![university](img/people.jpg) 7 | 8 | ## From Teluta to Facebook 9 | In part 1 of your work, we situated you as a worker of a hypothetical company called _Teluta_. But real-world companies constantly collect and represent our personal characteristics - at times, with terrible consequences. Read the stories below about instances about real companies... 10 | 11 | _What are the potential consequences of including characteristics in code?_ 12 | - [Facebook Lets Advertisers Exclude Users by Race](https://www.propublica.org/article/facebook-lets-advertisers-exclude-users-by-race) 13 | - [Dozens of Companies are Using Facebook to Exclude Older Workers from Job Ads](https://www.propublica.org/article/facebook-ads-age-discrimination-targeting) 14 | 15 | _What are the possible challenges of inferring characteristics?_ 16 | - [Facial Recognition is Accurate, if You're a White Guy](https://www.nytimes.com/2018/02/09/technology/facial-recognition-race-artificial-intelligence.html) 17 | 18 | 19 | ### Reflection Questions 20 | 21 | - Imagine that _Teluta_ cars tried to infer your characteristics on-the-fly using a suite of state-of-the-art sensors. Do you think that any of your characteristics could be misclassified? What would the implications of that misclassification be? 22 | 23 | - While you currently trust the leadership at _Teluta_, what if more morally dubious (or oblivious?) leaders took over the company after you had left. Do you think that any of your design decisions could be abused by the company? How? 24 | 25 | - Given this reflection, which characteristics would you remove from your code? Why? 26 | 27 | - Are there any tradeoffs to removing too many characteristics from _Teluta_'s code? What are they? 28 | -------------------------------------------------------------------------------- /modules/ethicalengine2/code/docs.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Ethical Engine Documentation 4 | exclude: true 5 | --- 6 | 7 | This documentation will help you implement your decision engine for an autonomous robot. 8 | 9 | Fill in the `decide` method with a program that analyzes the given scenario and returns a string to indicate which group to save: `"loc1people"` or `"loc2people"`. See below for the data available in each scenario. 10 | 11 | ## Scenario Information 12 | 13 | | Attribute | Details | Type | 14 | |-----------|---------|------| 15 | | `scenario.loc1people` | Access the people who are passengers | list | 16 | | `scenario.loc2people` | Access the people who are pedestrians | list | 17 | | `scenario.youInLoc1` | Check if you are one of the people in location 1 | boolean | 18 | | `scenario.trespassing` | Check if the pedestrians in location 2 are trespassing | boolean | 19 | 20 | ## Accessing Person Objects 21 | 22 | You can loop over all of the people at location 1 or 2 like so: 23 | 24 | ```python 25 | for person in scenario.loc1people: 26 | print(person.charType) 27 | ``` 28 | 29 | You can also select a specific person by their index: 30 | 31 | ```python 32 | if len(scenario.loc2people) >= 1: 33 | firstped = scenario.loc2people[0] 34 | print(firstped.charType) 35 | ``` 36 | 37 | ## Person Information 38 | 39 | | Attribute | Details | Type | 40 | |-----------|---------|------| 41 | | `person.charType` | Check the type of character | string: `"human"`, `"cat"`, or `"dog"` | 42 | | `person.age` | If human, check their age group | string: `"baby"`, `"child"`, `"adult"`, `"elderly"` | 43 | | `person.gender` | If human, check their gender | string: `"male"`, `"female"` | 44 | | `person.profession` | If human adult, check their profession | string: `"doctor"`, `"CEO"`, `"criminal"`, `"homeless"`, `"unemployed"`, `"unknown"` | 45 | | `person.bodyType` | If human adult, check their body type | string: `"overweight"`, `"athletic"`, `"average"` | 46 | | `person.pregnant` | If human female, check if they are pregnant | boolean (`True` or `False`)| 47 | -------------------------------------------------------------------------------- /modules/ethicalengine2/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Robotoni's Disaster Relief Robot 4 | exclude: true 5 | --- 6 | 7 | ![rescue](img/rescue.jpg) 8 | 9 | _This scenario was developed by [Evan Peck (Bucknell University)](http://www.eg.bucknell.edu/~emp017/). Parts of the instructions and exercise were created by [Vinesh Kannan (Mimir HQ](https://github.com/vingkan)_ 10 | 11 | 12 | - **Course:** CS 1 13 | - **Language:** Python 14 | - **Practice:** conditionals, use of API and objects 15 | - **Approx. Time:** 1-2 hours for individual, longer if group prioritization is done 16 | 17 | ## Scenario: Robotoni's Disaster-Relief Robot 18 | You are working for an emerging robotics company, _Robotoni_, that is taking the admiral stance of developing robots to aid in life-threatening events. Their current objective is to build a fleet of autonomous robots that will rescue people in who are caught in two natural disasters: wildfires and floods. 19 | 20 | _Robotoni_ has already built a robot that can navigate unknown terrain and successfully rescue people who are in need of help. However, for _Robotoni_ robots to act autonomously and maximize their impact, they must also make hard decisions. In effect, the _Robotoni_ robot must **prioritize who to save**. 21 | 22 | Your job is to write a comparison algorithm for the _Robotoni Disaster-Relief Robot_ in which it compares two groups of people and decides which group to prioritize for relief. 23 | 24 | ## Assignment 25 | _Note: This assignment can either follow [Ethical Engine 1](../ethicalengine1) or act as a standalone assignment._ 26 | - [Instructions](instructions.html) 27 | - [Code (in Repository)](https://github.com/EthicalCS/ethicalcs.github.io/tree/master/modules/ethicalengine2/code) 28 | 29 | ## Supplemental Reading 30 | - [Machine Bias (Pro Publica)](https://www.propublica.org/article/machine-bias-risk-assessments-in-criminal-sentencing) 31 | - [What moral decisions should driverless cars make? (from TEDx Cambridge)](https://www.ted.com/talks/iyad_rahwan_what_moral_decisions_should_driverless_cars_make?language=en) 32 | -------------------------------------------------------------------------------- /modules/input/stories.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Harwall University Forms - Stories 4 | exclude: true 5 | --- 6 | ![university](img/university.jpg) 7 | 8 | Now that you feel good about your form, consider the two vignettes below: 9 | 10 | _Vignette 1:_ 11 | > Chun Ying Tsang (20) is an exchange student from Birmingham, West Midlands, England. He is here as an exchange student and only just moved into his dorm yesterday. Although Chun Ying has an email address (Terrif.Ying@yahoo.com), he only has his UK cell phone +44 075 9921 9264. 12 | 13 | _Vignette 2:_ 14 | > Ash O'Connell-Chapman Jr. (33) has been invited to speak at an event co-hosted by CODE and Project SAFE. Drawing on personal experience growing up in Portage, MI, Ash will be talking about the discrimination faced by the transgender community, and how allies can support those who are transitioning. Due to previous harassment, Ash refused to give out a phone number or an email, instead directing you to the [National Center for Transgender Equality](https://transequality.org/) website. 15 | 16 | Before continuing, try to encode the information from these visitors with your program. What happens? Does your program work? Where does it fail? 17 | 18 | 19 | #### The Beliefs We Hold 20 | Read through the following webpages: 21 | 22 | - [Falsehoods Programmers Believe about Names](https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/) 23 | - [Falsehoods Programmers Believe about Addresses](https://www.mjt.me.uk/posts/falsehoods-programmers-believe-about-addresses/) 24 | - [Falsehoods Programmers Believe about Geography](https://wiesmann.codiferes.net/wordpress/?p=15187) 25 | 26 | #### Reflection Questions 27 | 28 | - Would your program work for the visitors at the beginning of Part 2? If not, why not? What assumptions did you make about the personal information of the visitors? What assumptions did you make about how this information would be entered? 29 | 30 | - How would you change your program so that it wouldn't fail? What are the advantages **and disadvantages** of doing this? You do not have to actually make the changes, only describe what you would do. 31 | 32 | - Look through the links above. Why might programmers care about these things? How might you approach these problems differently in the future? 33 | -------------------------------------------------------------------------------- /modules/input/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Ethical Input Validation 4 | exclude: true 5 | --- 6 | ![university](img/university.jpg) 7 | 8 | _This exercise was developed by [Justin Li (Occidental College)](https://justinnhli.com/). It was adapted by Evan Peck (Bucknell)_ 9 | 10 | - **Course:** CS 1 11 | - **Language:** Python 12 | - **Practice:** conditionals, data types, functions 13 | - **Approx. Time:** 1-2 hours (depending on revisions) 14 | 15 | ## Scenario: Harwall University's Visitors 16 | You are working for the prestigious Harwall university to meet the joint needs of _Admissions_, _Alumni Relations_, and _Communications_. People are constantly visiting campus - to see someone they know, to check out the school as a prospective, to give a talk, to interview, to come back to the school (alumni!), or for a variety of reasons. 17 | 18 | It would be valuable to know who is on a campus throughout the year, so you are asked to write a standard form that Harwall can give visitors to collect their information. Harwall intends to use the information from this form later on to communicate with potential donors or reach out to prospective students. 19 | 20 | Since Harwall wants to make sure that this data is useful, they have also asked you to validate whatever information is entered into the form. That is your job. 21 | 22 | ## Assignment 23 | Students are presented _Part 1_ without **any** ethical framing or knowledge of _Part 2_. 24 | - [Part 1: Instructions](instructions.html) 25 | - [Part 2: Stories](stories.html) 26 | 27 | _Instructor Notes:_ Our sequencing of CS 1 (based off [Harvey Mudd's _CS for All_](https://www.cs.hmc.edu/csforall/)) teaches recursion _before_ for and while loops. As a result, you'll see that the template code uses recursion to repeat a function - feel free to change this based on the sequence in your course (most likely to a `while` loop). 28 | 29 | ## Supplemental Reading 30 | - [Falsehoods Programmers Believe about Names](https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/) 31 | - [Falsehoods Programmers Believe about Addresses](https://www.mjt.me.uk/posts/falsehoods-programmers-believe-about-addresses/) 32 | - [Falsehoods Programmers Believe about Geography](https://wiesmann.codiferes.net/wordpress/?p=15187) 33 | - [Facebook suspends Native Americans over 'real name' policy](https://www.theguardian.com/technology/2015/feb/16/facebook-real-name-policy-suspends-native-americans) 34 | - [Airport body scan machines flag transgender passengers as threats](http://time.com/4044914/transgender-tsa-body-scan/) 35 | -------------------------------------------------------------------------------- /modules/hiring/stories.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Moogle's Hiring Algorithm - Stories 4 | exclude: true 5 | --- 6 | ![ethical hiring](img/hiring.jpg) 7 | 8 | Now that you feel good about your algorithm, let's highlight some of those applicant and reveal the stories between them. For each of the following, reflect on whether you think that your algorithm _does the right thing._ If not, how could you change it? 9 | 10 | #### **Story 1:** Misread the Instructions 11 | What if an excellent applicant thinks they should put in letter grades? 12 | 13 | `[‘A’, ‘A’, ‘A’, ‘A’, ‘A’, ‘A’, ‘A’]` 14 | 15 | ... or how about their grades on 4-point scale? 16 | 17 | `[4, 3.9, 4, 4, 3.95, 4, 3.9]` 18 | 19 | #### **Story 2:** Bad Assumptions 20 | What if one of your applicants skipped _Intro to Computer Science_? When they saw your form, they froze, and decided that putting `-1` in the input field would make it obvious... 21 | 22 | `[-1, 95, 99, 94, 96, 98, 95]` 23 | 24 | 25 | #### **Story 3:** Mistake in the Input 26 | What if one of your applicants accidentally put in a number > 100? 27 | 28 | `[681, 68, 73, 70, 81, 91, 59]` 29 | 30 | That might seem easy enough for a program to catch, but what if they accidentally dropped a `0`? 31 | 32 | `[100, 100, 100, 100, 100, 100, 10]` 33 | 34 | A person would catch that mistake easily, does your algorithm? 35 | 36 | 37 | #### **Story 4:** The Awful Semester 38 | What if your applicant had a medical emergency one semester? Or a personal tragedy? 39 | 40 | `[95, 93, 50, 91, 98, 90, 90]` 41 | 42 | 43 | #### **Story 5:** Inverse Trajectories 44 | What if one of your applicants came from an underprivileged background and really struggled at the beginning of college... but showed extraordinary growth by the end? 45 | 46 | `[65, 75, 85, 95, 100, 100, 80]` 47 | 48 | What if one of your applicants came to college with extraordinary potential? They easily aced their first few classes and then gradually grew apathetic about their education - getting nothing but barely-passing grades by the time they were a senior? 49 | 50 | `[100, 100, 95, 85, 75, 65, 80]` 51 | 52 | _Does your algorithm treat them equally?_ 53 | 54 | ## Reflection Questions 55 | There are often no easy answers to these questions... but we need to reflect on the tradeoffs of our decisions. 56 | 57 | - What systemic advantages/disadvantages are your algorithms likely to amplify? 58 | - What does it mean to design a _fair_ algorithm? 59 | - What is the human cost of efficiency? More permissive algorithms may capture more interesting candidates, but it also means more costly, human work. What is the ideal balance? 60 | -------------------------------------------------------------------------------- /docs/faq.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: FAQ 4 | --- 5 | 6 | ### Can I contribute? 7 | 8 | Sure! If you take a look at [some of my modules in the repository](https://github.com/EthicalCS/ethicalcs.github.io/tree/master/modules), you'll see that they have a similar structure. I write everything up in markdown and then use Jekyll to create the nice website you see here. Currently, I'm looking for modules that fit the following criteria: 9 | 10 | - Appropriate for students in CS 1 (or CS 2) 11 | - Is practice-based - students externalize their beliefs directly in code. 12 | - Pairs with existing curriculum (for example, the exercise can double as practice for writing `for` loops) 13 | 14 | You can either email me at `evan.peck@bucknell.edu` or submit a pull request in [the repository](https://github.com/EthicalCS/ethicalcs.github.io). 15 | 16 | ### How do you see these modules being improved? 17 | 18 | Many, many ways. 19 | 20 | - **Assessment** (I don't have any right now!) 21 | - More readings 22 | - Better scaffolding of concepts 23 | - More reflection questions 24 | - Better alignment with [processes that help students navigate ethical dilemmas](https://www.scu.edu/ethics-in-technology-practice/). 25 | - Improved code. 26 | 27 | I see these modules more as conversation-starters than polished, finished assignments. I hope they are enough to encourage other educators to use them, but I also hope that people make them better! 28 | 29 | ### How effective are these modules? 30 | 31 | Anecdotally, I have had fantastic responses from my students - both during lectures themselves and afterwards in teaching evaluations. **BUT..** 32 | 33 | _Anecdotally_ is the key word here. There is no research behind their effectiveness, and I don't pretend to be a CS ed researcher. Personally, I believe that learning ethical reflection habits _alongside_ programming habits will be more effective than standalone ethics courses... but I have no evidence to back this up. While it's in my longterm plan to quantify the impact of these modules, the bottom line here is that you should listen to CS education researchers over me. 34 | 35 | 36 | ### How will I have time to insert these in my (very full) CS 1 courses? 37 | 38 | The intention of these modules is that they pair directly with your existing curriculum. For example, I often set aside lecture or two for students to practice `for` loops on tiny functions. I still take that time, but instead of situating it on abstract functions, I situate that practice in an ethical reflection scenario. 39 | 40 | I don't want to claim that these modules take _NO_ more time, but I've found the impact to be minimal in my course. 41 | 42 | 49 | 50 | #### _More soon..._ 51 | -------------------------------------------------------------------------------- /modules/ethicalengine2/code/engine.py: -------------------------------------------------------------------------------- 1 | from scenario import Scenario 2 | 3 | """ 4 | The following set of exercises was developed by Vinesh Kanna (MimirHQ) based 5 | on an activity by Evan Peck (Bucknell University). It was modifed by Evan Peck 6 | to match a disaster-relief scenario. 7 | """ 8 | 9 | def ruleset1(scenario: Scenario) -> str: 10 | """ 11 | Decides whether your robot will save the people location 1 or location 2 12 | - Save the person in location 1, if and ONLY if they are pregnant. 13 | 14 | Note: in this activity, there will only be one person in each location 15 | @param scenario: details about the scenario 16 | @return: "loc1people" or "loc2people" depending on who you want to save 17 | """ 18 | passenger = scenario.loc1people[0] 19 | pedestrian = scenario.loc2people[0] 20 | # TODO: Fill in the method 21 | return "loc1people" 22 | 23 | 24 | def ruleset2(scenario: Scenario) -> str: 25 | """ 26 | Decides whether your robot will save the people location 1 or location 2 27 | - Save the person in location 2, if they are NOT trespassing or if they are a child. 28 | 29 | Note: in this activity, there will only be one person in each location 30 | @param scenario: details about the scenario 31 | @return: "loc1people" or "loc2people" depending on who you want to save 32 | """ 33 | passenger = scenario.loc1people[0] 34 | pedestrian = scenario.loc2people[0] 35 | # TODO: Fill in the method 36 | return "loc1people" 37 | 38 | 39 | def ruleset3(scenario: Scenario) -> str: 40 | """ 41 | Decides whether your robot will save the people location 1 or location 2 42 | - The first priority is to save the person who is a baby. 43 | - The second priority is to save athletic people. 44 | - The third priority is to save people who are either a doctor or a CEO. 45 | - The fourth priority is to save females. 46 | - The fifth priority is to save the passenger. 47 | 48 | Note: in this activity, there will only be one person in each location 49 | @param scenario: details about the scenario 50 | @return: "loc1people" or "loc2people" depending on who you want to save 51 | """ 52 | passenger = scenario.loc1people[0] 53 | pedestrian = scenario.loc2people[0] 54 | # TODO: Fill in the method 55 | return "loc1people" 56 | 57 | 58 | def my_decision(scenario: Scenario) -> str: 59 | """ 60 | Decides whether your robot will save the people location 1 or location 2 61 | - Your own decision algorithm. 62 | 63 | Note: in this activity, there will only be one person in each location 64 | @param scenario: details about the scenario 65 | @return: "loc1people" or "loc2people" depending on who you want to save 66 | """ 67 | passenger = scenario.loc1people[0] 68 | pedestrian = scenario.loc2people[0] 69 | # TODO: Fill in the method 70 | return "loc1people" 71 | -------------------------------------------------------------------------------- /_site/modules/ethicalengine2/code/engine.py: -------------------------------------------------------------------------------- 1 | from scenario import Scenario 2 | 3 | """ 4 | The following set of exercises was developed by Vinesh Kanna (MimirHQ) based 5 | on an activity by Evan Peck (Bucknell University). It was modifed by Evan Peck 6 | to match a disaster-relief scenario. 7 | """ 8 | 9 | def ruleset1(scenario: Scenario) -> str: 10 | """ 11 | Decides whether your robot will save the people location 1 or location 2 12 | - Save the person in location 1, if and ONLY if they are pregnant. 13 | 14 | Note: in this activity, there will only be one person in each location 15 | @param scenario: details about the scenario 16 | @return: "loc1people" or "loc2people" depending on who you want to save 17 | """ 18 | passenger = scenario.loc1people[0] 19 | pedestrian = scenario.loc2people[0] 20 | # TODO: Fill in the method 21 | return "loc1people" 22 | 23 | 24 | def ruleset2(scenario: Scenario) -> str: 25 | """ 26 | Decides whether your robot will save the people location 1 or location 2 27 | - Save the person in location 2, if they are NOT trespassing or if they are a child. 28 | 29 | Note: in this activity, there will only be one person in each location 30 | @param scenario: details about the scenario 31 | @return: "loc1people" or "loc2people" depending on who you want to save 32 | """ 33 | passenger = scenario.loc1people[0] 34 | pedestrian = scenario.loc2people[0] 35 | # TODO: Fill in the method 36 | return "loc1people" 37 | 38 | 39 | def ruleset3(scenario: Scenario) -> str: 40 | """ 41 | Decides whether your robot will save the people location 1 or location 2 42 | - The first priority is to save the person who is a baby. 43 | - The second priority is to save athletic people. 44 | - The third priority is to save people who are either a doctor or a CEO. 45 | - The fourth priority is to save females. 46 | - The fifth priority is to save the passenger. 47 | 48 | Note: in this activity, there will only be one person in each location 49 | @param scenario: details about the scenario 50 | @return: "loc1people" or "loc2people" depending on who you want to save 51 | """ 52 | passenger = scenario.loc1people[0] 53 | pedestrian = scenario.loc2people[0] 54 | # TODO: Fill in the method 55 | return "loc1people" 56 | 57 | 58 | def my_decision(scenario: Scenario) -> str: 59 | """ 60 | Decides whether your robot will save the people location 1 or location 2 61 | - Your own decision algorithm. 62 | 63 | Note: in this activity, there will only be one person in each location 64 | @param scenario: details about the scenario 65 | @return: "loc1people" or "loc2people" depending on who you want to save 66 | """ 67 | passenger = scenario.loc1people[0] 68 | pedestrian = scenario.loc2people[0] 69 | # TODO: Fill in the method 70 | return "loc1people" 71 | -------------------------------------------------------------------------------- /modules/hiring/instructions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Moogle's Hiring Algorithm 4 | exclude: true 5 | --- 6 | 7 | ![ethical hiring](img/hiring.jpg) 8 | 9 | ## Scenario: Moogle's Hiring Filter 10 | Imagine you are working for _Moogle_, a well-known tech company that receives tens of thousands of job applications from graduating seniors every year. 11 | 12 | Since the company receives too many job applications for HR to individually assess in a reasonable amount of time, you are asked to create a program that algorithmically analyzes applications and selects the ones most worth passing onto HR. 13 | 14 | ### Applicant Data 15 | It's difficult to create these first-pass cuts, so _Moogle_ designs their application forms to get some numerical data about their applicants' education. Job applications must enter the grades they received in 6 core CS courses, as well as their overall GPA. For your convenience, this will be stored in a python `list` that you can access. For example, a student who received the following scores... 16 | 17 | - **Intro to CS:** 100 18 | - **Data Structures:** 95 19 | - **Software Engineering:** 80 20 | - **Algorithms:** 89 21 | - **Computer Organization:** 91 22 | - **Operative Systems:** 75 23 | - **Overall GPA:** 83 24 | 25 | ... would result in the following list: `[100, 95, 80, 89, 91, 75, 83]`. You can assume that index `0` is _always_ Intro to CS, `1` is _always_ Data Structures, and so on. 26 | 27 | Because you are processing many applications, your program will receive a _list of lists_. For example, this would be the information for 3 applicants: 28 | 29 | `[ [100, 95, 80, 89, 91, 75, 83], [75, 80, 85, 90, 85, 88, 90], [85, 70, 99, 100, 81, 82, 91] ]` 30 | 31 | ### Your Task 32 | Your job is to: 33 | 1. Determine how you are going to select the top applicants to pass onto HR. 34 | 2. Given a list of applicant data (a _list of lists_), write a function returns a new list of worthwhile candidates. 35 | 36 | ### Your Code 37 | To get you started, we're provided some template code: 38 | 39 | - [`hiring.py`](code/hiring.py) a template where you will write your applicant-selection algorithm based on a small set of dummy data. 40 | - [`lottaApps.py`](code/lottaApps.py) a module that contains a list of ten-thousand randomly generated applicants you can try once you have completed your code. 41 | 42 | In `hiring.py`, you will be writing a series of predefined `analyze_applicant` methods which apply different criteria to applicants. Through this process, you will not only get a sense of the tradeoffs of different criteria, but also get practice writing various `for` loops. (_Note: this is meant to give you practice with for loops, so don't use python's built in functions such as `sum()` or `min()`_) 43 | 44 | Complete the following methods: 45 | - `analyze_applicant1` accepts applicants that have an overall GPA above 80. (Does _not_ need a for loop) 46 | - `analyze_applicant2` accepts applicants that have no grade below 65. 47 | - `analyze_applicant3` accepts applicants that have at least 4 grades above 85. 48 | - `analyze_applicant4` accepts applicants that have an average above 85. 49 | 50 | After writing, testing, and considering the tradeoffs of these four methods, write your own criteria in `your_analysis`. 51 | 52 | 53 | ### Questions you should answer: 54 | 55 | 1. What criteria did you choose to select finalists? How did you choose that criteria? 56 | 57 | 2. Roughly what percentage of applicants does your algorithm pass on as finalists? Is that enough? If _Moogle_ asked you to take a more aggressive approach with your algorithm, are there any tradeoffs? 58 | -------------------------------------------------------------------------------- /_site/feed.xml: -------------------------------------------------------------------------------- 1 | Jekyll2018-10-12T12:37:54-04:00http://localhost:4000/Ethical CSWelcome to Jekyll!2017-08-04T10:04:48-04:002017-08-04T10:04:48-04:00http://localhost:4000/jekyll/update/2017/08/04/welcome-to-jekyll<p>You’ll find this post in your <code class="highlighter-rouge">_posts</code> directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run <code class="highlighter-rouge">jekyll serve</code>, which launches a web server and auto-regenerates your site when a file is updated.</p> 2 | 3 | <p>To add new posts, simply add a file in the <code class="highlighter-rouge">_posts</code> directory that follows the convention <code class="highlighter-rouge">YYYY-MM-DD-name-of-post.ext</code> and includes the necessary front matter. Take a look at the source for this post to get an idea about how it works.</p> 4 | 5 | <p>Jekyll also offers powerful support for code snippets:</p> 6 | 7 | <figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">def</span> <span class="nf">print_hi</span><span class="p">(</span><span class="nb">name</span><span class="p">)</span> 8 | <span class="nb">puts</span> <span class="s2">"Hi, </span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">"</span> 9 | <span class="k">end</span> 10 | <span class="n">print_hi</span><span class="p">(</span><span class="s1">'Tom'</span><span class="p">)</span> 11 | <span class="c1">#=&gt; prints 'Hi, Tom' to STDOUT.</span></code></pre></figure> 12 | 13 | <p>Check out the <a href="https://jekyllrb.com/docs/home">Jekyll docs</a> for more info on how to get the most out of Jekyll. File all bugs/feature requests at <a href="https://github.com/jekyll/jekyll">Jekyll’s GitHub repo</a>. If you have questions, you can ask them on <a href="https://talk.jekyllrb.com/">Jekyll Talk</a>.</p>You’ll find this post in your _posts directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run jekyll serve, which launches a web server and auto-regenerates your site when a file is updated. -------------------------------------------------------------------------------- /modules/hiring/code/hiring.py: -------------------------------------------------------------------------------- 1 | """ 2 | Use this file as a template to develop Moogle's Hiring Filter 3 | 4 | 0: Intro to CS 5 | 1: Data Structures 6 | 2: Software Engineering 7 | 3: Algorithms 8 | 4: Computer Organization 9 | 5: Operating Systems 10 | 6: Overall College GPA 11 | 12 | The list representing a single application would look like this: 13 | [100, 95, 80, 89, 91, 75, 83] 14 | """ 15 | 16 | # When you have something working, uncomment this line! 17 | #from lottaApps import * 18 | 19 | example_list = [[93, 89, 63, 88, 60, 73, 80], [100, 63, 57, 96, 58, 71, 78], [81, 91, 99, 78, 57, 87, 86], [81, 73, 100, 57, 91, 60, 66], [86, 89, 64, 81, 69, 93, 92], [78, 63, 88, 95, 59, 98, 90], [55, 74, 68, 55, 69, 94, 80], [64, 77, 75, 92, 77, 72, 83], [95, 58, 92, 62, 77, 64, 59], [94, 78, 84, 83, 68, 63, 76]] 20 | 21 | 22 | def get_best_applicants(app_list): 23 | """ 24 | Given applicant data, return the most qualified applications 25 | 26 | @param app_list: a 2D list containing lists of application data 27 | @return a 2D list of the best applications 28 | """ 29 | finalists = list() 30 | 31 | for app in app_list: 32 | # Where we decide whether to 33 | if analyze_applicant1(app) == True: 34 | finalists += [app] 35 | 36 | return finalists 37 | 38 | def analyze_applicant1(applicant): 39 | """ 40 | Given the GPAs of a single applicant, return True if they are qualified 41 | Qualification: An applicant is qualified if... 42 | - their Overall College GPA is above 80 43 | 44 | @param applicant: a list of GPAs (integers) 45 | @return True if the applicant qualifies 46 | """ 47 | return True 48 | 49 | 50 | def analyze_applicant2(applicant): 51 | """ 52 | Given the GPAs of a single applicant, return True if they are qualified 53 | Qualification: An applicant is qualified if... 54 | - they have no grade below a 65 55 | 56 | @param applicant: a list of GPAs (integers) 57 | @return True if the applicant qualifies 58 | """ 59 | return True 60 | 61 | def analyze_applicant3(applicant): 62 | """ 63 | Given the GPAs of a single applicant, return True if they are qualified 64 | Qualification: An applicant is qualified if... 65 | - they have at least 4 grades above 85 66 | 67 | @param applicant: a list of GPAs (integers) 68 | @return True if the applicant qualifies 69 | """ 70 | return True 71 | 72 | def analyze_applicant4(applicant): 73 | """ 74 | Given the GPAs of a single applicant, return True if they are qualified 75 | Qualification: An applicant is qualified if... 76 | - the average GPA of their CS courses (all but Overall) is above 85 77 | 78 | @param applicant: a list of GPAs (integers) 79 | @return True if the applicant qualifies 80 | """ 81 | return True 82 | 83 | def your_analysis(applicant): 84 | """ 85 | Given the GPAs of a single applicant, return True if they are qualified 86 | Qualification: An applicant is qualified if... 87 | - YOUR DECISION. WRITE IT HERE. 88 | 89 | @param applicant: a list of GPAs (integers) 90 | @return True if the applicant qualifies 91 | """ 92 | return True 93 | 94 | 95 | # When you have it working on example_list, uncomment the import above 96 | # and then replace example_list with lottaApps 97 | applicants = example_list 98 | finalists = get_best_applicants(applicants) 99 | 100 | print('') 101 | print("-------------------------") 102 | print() 103 | print("The finalists are...") 104 | for finalist in finalists: 105 | print(finalist) 106 | print("Your algorithm kept", round(len(finalists)/len(applicants)*100), "percent of applicants") 107 | -------------------------------------------------------------------------------- /_site/modules/hiring/code/hiring.py: -------------------------------------------------------------------------------- 1 | """ 2 | Use this file as a template to develop Moogle's Hiring Filter 3 | 4 | 0: Intro to CS 5 | 1: Data Structures 6 | 2: Software Engineering 7 | 3: Algorithms 8 | 4: Computer Organization 9 | 5: Operating Systems 10 | 6: Overall College GPA 11 | 12 | The list representing a single application would look like this: 13 | [100, 95, 80, 89, 91, 75, 83] 14 | """ 15 | 16 | # When you have something working, uncomment this line! 17 | #from lottaApps import * 18 | 19 | example_list = [[93, 89, 63, 88, 60, 73, 80], [100, 63, 57, 96, 58, 71, 78], [81, 91, 99, 78, 57, 87, 86], [81, 73, 100, 57, 91, 60, 66], [86, 89, 64, 81, 69, 93, 92], [78, 63, 88, 95, 59, 98, 90], [55, 74, 68, 55, 69, 94, 80], [64, 77, 75, 92, 77, 72, 83], [95, 58, 92, 62, 77, 64, 59], [94, 78, 84, 83, 68, 63, 76]] 20 | 21 | 22 | def get_best_applicants(app_list): 23 | """ 24 | Given applicant data, return the most qualified applications 25 | 26 | @param app_list: a 2D list containing lists of application data 27 | @return a 2D list of the best applications 28 | """ 29 | finalists = list() 30 | 31 | for app in app_list: 32 | # Where we decide whether to 33 | if analyze_applicant1(app) == True: 34 | finalists += [app] 35 | 36 | return finalists 37 | 38 | def analyze_applicant1(applicant): 39 | """ 40 | Given the GPAs of a single applicant, return True if they are qualified 41 | Qualification: An applicant is qualified if... 42 | - their Overall College GPA is above 80 43 | 44 | @param applicant: a list of GPAs (integers) 45 | @return True if the applicant qualifies 46 | """ 47 | return True 48 | 49 | 50 | def analyze_applicant2(applicant): 51 | """ 52 | Given the GPAs of a single applicant, return True if they are qualified 53 | Qualification: An applicant is qualified if... 54 | - they have no grade below a 65 55 | 56 | @param applicant: a list of GPAs (integers) 57 | @return True if the applicant qualifies 58 | """ 59 | return True 60 | 61 | def analyze_applicant3(applicant): 62 | """ 63 | Given the GPAs of a single applicant, return True if they are qualified 64 | Qualification: An applicant is qualified if... 65 | - they have at least 4 grades above 85 66 | 67 | @param applicant: a list of GPAs (integers) 68 | @return True if the applicant qualifies 69 | """ 70 | return True 71 | 72 | def analyze_applicant4(applicant): 73 | """ 74 | Given the GPAs of a single applicant, return True if they are qualified 75 | Qualification: An applicant is qualified if... 76 | - the average GPA of their CS courses (all but Overall) is above 85 77 | 78 | @param applicant: a list of GPAs (integers) 79 | @return True if the applicant qualifies 80 | """ 81 | return True 82 | 83 | def your_analysis(applicant): 84 | """ 85 | Given the GPAs of a single applicant, return True if they are qualified 86 | Qualification: An applicant is qualified if... 87 | - YOUR DECISION. WRITE IT HERE. 88 | 89 | @param applicant: a list of GPAs (integers) 90 | @return True if the applicant qualifies 91 | """ 92 | return True 93 | 94 | 95 | # When you have it working on example_list, uncomment the import above 96 | # and then replace example_list with lottaApps 97 | applicants = example_list 98 | finalists = get_best_applicants(applicants) 99 | 100 | print('') 101 | print("-------------------------") 102 | print() 103 | print("The finalists are...") 104 | for finalist in finalists: 105 | print(finalist) 106 | print("Your algorithm kept", round(len(finalists)/len(applicants)*100), "percent of applicants") 107 | -------------------------------------------------------------------------------- /modules/ethicalengine1/instructions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Teluta's Person Model 4 | exclude: true 5 | --- 6 | ![university](img/people.jpg) 7 | 8 | ## Scenario: Teluta's Autonomous Cars 9 | _Teluta_ - an autonomous vehicle company - has made extraordinary strides in self-driving cars and is ready to go to market. But there is a corner case that needs to be addressed. In the rare instances in which _Teluta_ vehicles can sense an impending crash, they need a mechanism to quickly assess and value human life. That is, the car must rapidly _choose who to save_. 10 | 11 | While prioritizing _who to save_ will be decided by other employees of the company, your job is to decide which factors should be considered by their algorithms. To do this, you'll use object-oriented programming to create a template for _Teluta_ that models a person. 12 | 13 | ### Familiarize yourself with the Moral Machine 14 | Visit MIT's [Moral Machine](http://moralmachine.mit.edu/). From their website: 15 | 16 | > From self-driving cars on public roads to self-piloting reusable rockets landing on self-sailing ships, machine intelligence is supporting or entirely taking over ever more complex human activities at an ever increasing pace. The greater autonomy given machine intelligence in these roles can result in situations where they have to make autonomous choices involving human life and limb. This calls for not just a clearer understanding of how humans make such choices, but also a clearer understanding of how humans perceive machine intelligence making such choices. 17 | 18 | Briefly, the _Moral Machine_ is an online simulator that lets you experiment with the kinds of scenarios that _Teluta_ outlined above. 19 | 20 | ![moralmachine](img/moralmachine.png) 21 | 22 | Click the `Start Judging` buttons and make yourself go through a handful of scenarios. Consider the different characteristics of people and animals that are represented in the demonstration. 23 | 24 | ### Identifying Characteristics 25 | On a sheet of paper (or in a file) write the following: 26 | - A list of all the characteristics about entities (people or animals) that you think should be represented in your program. 27 | - For each characteristic, identify the type of data that will be stored (`string`, `int`, `float`, `list`). 28 | - For each characteristic, identify what the possible values might be for this attribute 29 | - For example, if you kept track of `years_old`, you might say that it is a positive integer from `0` to `100`. 30 | 31 | Compare your list with a classmate. What similarities did you have? What differences? Record what drove those differences. 32 | 33 | ### From Visuals to Code 34 | 35 | Now that you've run through the scenarios a few times, let's take a look at some code. We're going to practice object-oriented programming design and construct a `Person` class 36 | 37 | (_NOTE: our `Person` can actually be an animal too. This representation is best done through inheritance relationships, but at this point, we've constructed this assignment to fit very early exposure to OOP. Feel free to modify to fit your own circumstances!_) 38 | 39 | Your code will accomplish two different goals: 40 | 1. It will articulate all your characteristics as attributes of the `Person` classmate 41 | - Example below: `self.charType` represents the 'character' type each entity - whether it is a person or an animal. You should include more characteristics. 42 | - For each attribute, give it a default parameter of `None` in the constructor (`__init__`). 43 | 2. It will allow for the creation of a randomly generated `Person`. 44 | - Once completed, typing `person = Person()` should generate an entity with random attributes. 45 | - Currently, our `CHAR_TYPES` variable contains not only the possible values for `self.charType`, but also lists them in the same probability with which they appear. For example, `CHAR_TYPES` contains `human` 6 times and `cat` and `dog` 1 time each. That means that `human` is 3x more likely to appear if someone uses this code to generate a random person. This also forces you to externalize the possible values you generated earlier and represent them directly in your code. 46 | 47 | ```python 48 | class Person: 49 | 50 | CHAR_TYPES = ["human", "human", "human", "human", "human", "human", "dog", "cat"] 51 | 52 | # Constructor - you'll need to add more parameters than this 53 | def __init__(self, charType=None): 54 | self.charType = charType 55 | if charType is None: 56 | self.charType = random.choice(self.CHAR_TYPES) 57 | ``` 58 | 59 | Once you feel comfortable with your code, feel free to move onto part 2. 60 | -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # You don't need to edit this file, it's empty on purpose. 3 | # Edit theme's home layout instead if you wanna make some changes 4 | # See: https://jekyllrb.com/docs/themes/#overriding-theme-defaults 5 | layout: home 6 | exclude: true 7 | --- 8 | 9 | # Ethical Reflection Modules for CS 1 10 | 11 | While standalone ethics courses are increasingly common in computer science, I found that there are a lack of resources for integrating practice-based (coding!) reflection directly into CS 1 or 2 courses. This space acts as a repository of ethical reflection modules that I have created over the past couple of years. The goal of these modules is to: 12 | 1. Introduce ethical reflection in CS 1 courses 13 | 2. Develop ethical reflection habits _alongside_ coding (all modules involve programming!) 14 | 3. Pair directly with _existing_ CS 1 curriculum (students practice for loops - but instead of practicing on trivial problems, their practice is situated in ethical design scenarios) 15 | 16 | By reducing the barrier to adoption, my hope is that ethical reflection can be implemented more broadly in CS curriculum as a critical habit. Please read the [FAQ](docs/faq.html) for more information. 17 | 18 | -------------------- 19 | ## [Hiring Algorithms: Developers as Decision-Makers](modules/hiring) 20 | 21 | ![ethical hiring](modules/hiring/img/hiring.jpg) 22 | 23 | _What does it mean to design a fair algorithm? What is the human cost of efficiency? What systemic advantages/disadvantages are your algorithms likely to amplify?_ 24 | - *Scenario:* Develop an algorithm that filters job applications based on GPA 25 | - [Material](modules/hiring) 26 | - *Practice:* loops, conditionals, python lists 27 | - *Writeup:* [Ethical Design in CS 1: Building Hiring Algorithms in 1 Hour (Evan Peck)](https://medium.com/bucknell-hci/ethical-design-in-cs-1-building-hiring-algorithms-in-1-hour-41d8c913859f) 28 | - *Author:* [Evan Peck (Bucknell University)](http://www.eg.bucknell.edu/~emp017/) 29 | 30 | -------------------- 31 | ## [Input Validation: Developers as Gatekeepers](modules/input) 32 | ![university](modules/input/img/university.jpg) 33 | 34 | _What assumptions do we make about the people using our technology? What are the consequences of those assumptions? - who might we exclude? How do we capture diversity through design?_ 35 | - *Scenario:* Collect and validate personal information of people visiting a university 36 | - [Material](modules/input) 37 | - *Practice:* conditionals, functions, data types 38 | - *Author:* [Justin Li (Occidental College)](https://justinnhli.com/), Adapted by [Evan Peck (Bucknell University)](http://www.eg.bucknell.edu/~emp017/) 39 | 40 | -------------------- 41 | ## [Ethical Engine 1: Developers as Definers of Identity](modules/ethicalengine1) 42 | ![rescue](modules/ethicalengine1/img/people.jpg) 43 | 44 | _How can we adequately represent people in code? What characteristics of people should we **NOT** include in code? What are the implications of our representation decisions?_ 45 | 46 | - *Scenario:* In code, represent a person so that autonomous cars can make life-critical decisions 47 | - [Material](modules/ethicalengine1) 48 | - *Practice:* OOP design, data types 49 | - *Author:* [Evan Peck (Bucknell University)](http://www.eg.bucknell.edu/~emp017/) 50 | 51 | -------------------- 52 | ## [Ethical Engine 2: Developers as Moral Arbiters](modules/ethicalengine2) 53 | ![rescue](modules/ethicalengine2/img/rescue.jpg) 54 | 55 | _What is 'moral' behavior in the context of a computer? How do we write code that is forced to assign value to people?_ 56 | - *Scenario:* Program a disaster-relief robot to prioritize which distressed people to saves 57 | - [Material](modules/ethicalengine2) 58 | - *Practice:* conditionals, use of APIs and objects, dictionaries (in optional last part) 59 | - *Write ups:* 60 | - [The Ethical Engine: Integrating Ethical Design into Intro Computer Science (Evan Peck)](https://medium.com/bucknell-hci/ethical-design-in-cs-1-building-hiring-algorithms-in-1-hour-41d8c913859f) 61 | - [Write Up the Ethical Engine Lab (Justin Li)](https://howtostartacsdept.wordpress.com/2018/01/13/step-86-write-up-the-ethical-engine-lab/) 62 | - *Author:* [Evan Peck (Bucknell University)](http://www.eg.bucknell.edu/~emp017/), parts of activity by [Vinesh Kannan (Mimir HQ)](https://github.com/vingkan) 63 | 64 | --------------------- 65 | 66 | 67 | ## _In Progress..._ 68 | - Module on data privacy and data ethics 69 | - Module on algorithm auditing (related to [ethical engine]((https://medium.com/bucknell-hci/ethical-design-in-cs-1-building-hiring-algorithms-in-1-hour-41d8c913859f))) 70 | 71 | 72 | 75 | --------------------- 76 | 77 | ## License 78 | Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License 79 | -------------------------------------------------------------------------------- /modules/input/instructions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Harwall University's Forms 4 | exclude: true 5 | --- 6 | 7 | ![university](img/university.jpg) 8 | 9 | You are working for the prestigious Harwall university to meet the joint needs of _Admissions_, _Alumni Relations_, and _Communications_. People are constantly visiting campus - to see someone they know, to check out the school as a prospective, to give a talk, to interview, to come back to the school (alumni!), or for a variety of reasons. 10 | 11 | It would be valuable to know who is on a campus throughout the year, so you are asked to write a standard form that Harwall can give visitors to collect their information. Harwall intends to use the information from this form later on to communicate with potential donors or reach out to prospective students. 12 | 13 | Since Harwall wants to make sure that this data is useful, they have also asked you to validate whatever information is entered into the form. That is your job. 14 | 15 | 16 | ### The Visitors 17 | Here are a couple of examples of people who may be visiting campus: 18 | 19 | **Vignette 1:** 20 | > Beverly (52) and Robert (55) Deason are bringing their daughter Mary (17) for a college visit. Mary is a junior in high school, and is thinking about Harwall because of the Engineering College. Coming from Cambridge, MA, the family is traveling across a number of colleges in Pennsylvania. Mary says that you can email her at mlp231@mac.com or text her at (617) 431-5817. 21 | 22 | **Vignette 2:** 23 | > Terrell Hughes is on campus to interview for the tenure-track Computer Science faculty position. He is currently a visiting scholar at Cornell University in Ithaca, NY, having been there since he got his Ph.D. from NYU a year ago. You have his business card, which lists his contact information as thughes14211@cornell.edu and 607 151 4561. Terrel laughed when you asked for his age, and just said to put down 30. 24 | 25 | **Vignette 3:** 26 | > Rolf Feierabend has lived in Mifflinburg, PA since 1961, when his parents immigrated to the US, bringing then-seventeen Rolf in tow. He has been retired for a couple of years now, and takes his husky lab Winston on walks through campus on occasion. Although he has an email account feierabend411@aol.com he doesn’t really check it anymore. He says to just call him at 570-511-5161 27 | 28 | Answer the following questions: 29 | - Which information should we collect from each visitor? 30 | - In the context of a form, what fields will the form have? 31 | - For each field, how can you validate the input? 32 | 33 | 34 | ### The Code 35 | 36 | Rather than a typical online form, we'll be designing our via the command-line in Python. You've been provided a template to build off of in [validation.py](code/validation.py). We'll highlight the key parts here. 37 | 38 | 39 | #### The Form Function 40 | `form()` acts as the main function of the program. It's where we assign each of the fields that we would like to collect, and also where we report the collected information afterwards. 41 | 42 | ```python 43 | def form(): 44 | """The form function that collects info from users""" 45 | # Get street number 46 | streetNum = get_street_num() 47 | # Get the age 48 | age = get_age() 49 | 50 | # Collect more pieces of information by writing more functions 51 | 52 | # Then, print out all our collected info in a form 53 | print("=====================") 54 | print("We've collected the following information:") 55 | print("- Street Number:", streetNum) 56 | print("- Age:", age) 57 | # add more 58 | print("=====================") 59 | ``` 60 | 61 | #### Validation Functions 62 | While there are many ways to validate input in programming languages, we'll use `if` `elif` `else` statements in order to practice conditional logic. For each field that you want to collect, you should have a corresponding validation function that you create. We've completed one for you as an example: `get_street_num()` 63 | 64 | Conceptually, `get_street_num()` gets input from the user and then checks a couple of basic 'bad' cases (you may want to check more): 65 | - Is the field empty? 66 | - Is the field something other than an number? 67 | 68 | If the user's input matches one of our bad cases, the function is repeated until the input passes all cases (when the code reaches the `else` statement below) 69 | 70 | ```python 71 | 72 | def get_street_num(): 73 | """ EXAMPLE: Gets the user's street number. 74 | Repeats until a valid street number is given. 75 | Output: 76 | - streetNum: an integer representing the user's street number 77 | """ 78 | streetNum = input("Enter the street number of your address: ") 79 | 80 | # Check to see if it's empty! 81 | if streetNum == "": 82 | print("SORRY! You forgot to input your street number!\n") 83 | return get_street_num() 84 | # Check to see if it's a number! 85 | elif streetNum.isdigit() == False: 86 | print("SORRY! Your street number should be a positive number\n") 87 | return get_street_num() 88 | else: 89 | return streetNum 90 | ``` 91 | 92 | ### What you should do 93 | 94 | - First, completely the partially finished `get_age()` function. Provide suitable checks that someone has entered a reasonable age (for example, no one should be 800 years old). 95 | 96 | - Next, create new fields and new functions to validate those fields. 97 | 98 | - Once you are satisfied, move onto the next part of this assignment... 99 | -------------------------------------------------------------------------------- /modules/ethicalengine2/instructions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Disaster Relief Robot 4 | exclude: true 5 | --- 6 | 7 | ![rescue](img/rescue.jpg) 8 | 9 | 10 | ## Scenario: Disaster Relief Robot 11 | 12 | You are working for an emerging robotics company, _Robotoni_, that is taking the admiral stance of developing robots to aid in life-threatening events. Their current objective is to build a fleet of autonomous robots that will rescue people in who are caught in two natural disasters: wildfires and floods. 13 | 14 | _Robotoni_ has already built a robot that can navigate unknown terrain and successfully rescue people who are in need of help. However, for _Robotoni_ robots to act autonomously and maximize their impact, they must also make hard decisions. In effect, the _Robotoni_ robot must **prioritize who to save**. 15 | 16 | Your job is to write a comparison algorithm for the _Robotoni Disaster-Relief Robot_ in which it compares two groups of people and decides which group to prioritize for relief. 17 | 18 | 19 | ### Explore the Moral Machine 20 | While not situated in the context of disaster-relief robots, similar questions have been asked in the context of autonomous vehicles. To explore this context, visit MIT's [Moral Machine](http://moralmachine.mit.edu/). From their website: 21 | 22 | > From self-driving cars on public roads to self-piloting reusable rockets landing on self-sailing ships, machine intelligence is supporting or entirely taking over ever more complex human activities at an ever increasing pace. The greater autonomy given machine intelligence in these roles can result in situations where they have to make autonomous choices involving human life and limb. This calls for not just a clearer understanding of how humans make such choices, but also a clearer understanding of how humans perceive machine intelligence making such choices. 23 | 24 | Briefly, the _Moral Machine_ is an online simulator that lets you experiment with the kinds of scenarios that _Teluta_ outlined above. 25 | 26 | ![moralmachine](img/moralmachine.png) 27 | 28 | Click the `Start Judging` buttons and make yourself go through a handful of scenarios. Try to reflect on exactly how you're making your decisions. 29 | 30 | ### From Values to Code 31 | 32 | Instead of deciding between people in a car vs. pedestrians in a crosswalk, your algorithm must decide between two groups of people at different locations who are stranded and need to be rescued (for example, two different locations in the city during a flash-flood). 33 | 34 | _Who will your algorithm prioritize?_ 35 | 36 | We've created python code that replicates the random scenarios that are generated in the _Moral Machine_. The entities you must save may be people or animals. The people may be of various ages, genders, and professions. To access all of this information and program the _Robotoni Disaster-Relief Robot_, you'll use the _Ethical Engine API_, which allows you to analyze details about scenarios using python code: 37 | 38 | - [Ethical Engine API](code/docs.html) 39 | 40 | You are given access to a few python files which you will use to various degrees: 41 | - [`scenario.py`](code/scenario.py) contains our code that automatically generates random scenarios that your robot must navigate. You do _not_ need to alter this code. However, it is worth reading through and seeing if you understand it. 42 | - [`engine.py`](code/engine.py) contains the code that you'll write that _decides_ which people to prioritize and save. This is where you'll do most of your work. 43 | - [`main.py`](code/main.py) is the code you'll run that puts all the pieces together. You'll need to comment or uncomment a line or two here to switch between your various decision implementations. 44 | - To run this file, simply type `python3 main.py` in the command line. 45 | 46 | 47 | ### Coding Predefined Priorities 48 | Below are written descriptions of rulesets for sample decision algorithms. Your job is to write and test three different decision methods in `engine.py` that precisely implement each ruleset: 49 | 50 | - `ruleset1`: Save the person in location 2, if and only if they are pregnant. 51 | - `ruleset2` Save the person in location 1, if they are **not** trespassing or if they are a child. 52 | - `ruleset3` The first priority is to save the person who is a baby. The second priority is to save athletic people. The third priority is to save people who are either a doctor or a CEO. The fourth priority is to save females. The fifth priority is to save the person in location 1. 53 | 54 | Fill in the appropriate methods in `engine.py`. When you want to test one of the decision methods, edit line `23` of `main.py` to choose the target method. Then execute the following command in your terminal to run the program: 55 | 56 | _Helpful Tip:_ Scenarios are generated randomly. You can also generate pseudo-random scenarios, where the _same_ scenarios are run each time the program runs. Specify a seed for the random generator as a runtime argument like so: 57 | 58 | ```bash 59 | $ python3 main.py 12 60 | ``` 61 | 62 | ### From Gut Feelings to Code: Individuals 63 | 64 | Now that you have experience using the [Ethical Engine API](code/docs.html), design your own decision algorithm in `my_decision` that decides between one person in each location! You can refer to your notes from the Moral Machine scenarios or come up with an entirely new method of deciding. 65 | 66 | Before writing your code, write a description of how you want the decision to be made. 67 | 68 | ### Reflection Questions 69 | - Are there any discrepancies between your written description and the python algorithm? 70 | - Why do you think that your algorithm is the _right_ one? What are the tradeoffs? 71 | - Is it possible that your algorithm could amplify systemic biases if it was used at scale? 72 | 73 | ## From Gut Feelings to Code: Groups 74 | While you may be able to accomplish the previous sections with a set of complex conditional statements, the problem gets a lot more complicated when you need to choose between _groups_ of people. 75 | 76 | First, let's change the code in `scenario.py` so that it will create scenarios fo groups instead of individuals. Find the following code: 77 | 78 | ```python 79 | # The minimum/maximum number of people at each location 80 | MIN_LOCATION1 = 1 81 | MAX_LOCATION1 = 1 82 | MIN_LOCATION2 = 1 83 | MAX_LOCATION2 = 1 84 | ``` 85 | Change `MAX_LOCATION1` to be equal to `4` and `MAX_LOCATION2` to be equal to `4`. Next, find the constructor for the `Scenario` class: 86 | 87 | ```python 88 | def __init__(self, loc1people=None, loc2people=None, youInLoc1=None, 89 | trespassing=None, sameNum=True): 90 | ``` 91 | 92 | Change `sameNum` so that it is `sameNum=False`. This will change the random generation of scenarios so that each group _may not be the same size_. Think carefully about how you can handle these situations. How can you possibly compare groups of people? 93 | 94 | One possible method is to come up with a _point system_ to value people. That is, assign each person with a point value based on their characteristics, and then save the group that is valued with the most amount of points. 95 | 96 | ### More Reflection 97 | - How does the switch from conditionals to a point system change how you feel about this program? Why? 98 | - Suppose your algorithm was repurposed for military operations - do you still feel as confident in your approach? 99 | - In this activity, we forced you to use a set of characteristics that were already defined for you. But suppose that you could create your own... what would or wouldn't you include? 100 | -------------------------------------------------------------------------------- /_site/modules/ethicalengine1/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Ethical Engine - Representation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 108 | 109 | 110 |
111 |
112 |
113 | 114 | 115 | 116 | 117 |
118 |

Ethical Engine - Representation

119 |
120 |
121 |

university

122 | 123 |
    124 |
  • Course: CS 1/2
  • 125 |
  • Language: Python
  • 126 |
  • Practice: OOP design
  • 127 |
  • Approx. Time: 1 hour
  • 128 |
129 | 130 |

Scenario: Teluta’s Autonomous Cars

131 |

Teluta - an autonomous vehicle company - has made extraordinary strides in self-driving cars and is ready to go to market. But there is a corner case that needs to be addressed. In the rare instances in which Teluta vehicles can sense an impending crash, they need a mechanism to quickly assess and value human life. Your job is to create the code for Teluta that models a person.

132 | 133 |

Assignment

134 | 135 | 139 | 140 |

Supplemental Reading

141 | 147 | 148 |
149 | 150 |
151 | 152 |
153 |
154 | 155 | 205 | 206 | 207 | 208 | 209 | 210 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | activesupport (4.2.10) 5 | i18n (~> 0.7) 6 | minitest (~> 5.1) 7 | thread_safe (~> 0.3, >= 0.3.4) 8 | tzinfo (~> 1.1) 9 | addressable (2.5.2) 10 | public_suffix (>= 2.0.2, < 4.0) 11 | coffee-script (2.4.1) 12 | coffee-script-source 13 | execjs 14 | coffee-script-source (1.11.1) 15 | colorator (1.1.0) 16 | commonmarker (0.17.11) 17 | ruby-enum (~> 0.5) 18 | concurrent-ruby (1.0.5) 19 | dnsruby (1.61.2) 20 | addressable (~> 2.5) 21 | em-websocket (0.5.1) 22 | eventmachine (>= 0.12.9) 23 | http_parser.rb (~> 0.6.0) 24 | ethon (0.11.0) 25 | ffi (>= 1.3.0) 26 | eventmachine (1.2.7) 27 | execjs (2.7.0) 28 | faraday (0.15.2) 29 | multipart-post (>= 1.2, < 3) 30 | ffi (1.9.25) 31 | forwardable-extended (2.6.0) 32 | gemoji (3.0.0) 33 | github-pages (190) 34 | activesupport (= 4.2.10) 35 | github-pages-health-check (= 1.8.1) 36 | jekyll (= 3.7.3) 37 | jekyll-avatar (= 0.6.0) 38 | jekyll-coffeescript (= 1.1.1) 39 | jekyll-commonmark-ghpages (= 0.1.5) 40 | jekyll-default-layout (= 0.1.4) 41 | jekyll-feed (= 0.10.0) 42 | jekyll-gist (= 1.5.0) 43 | jekyll-github-metadata (= 2.9.4) 44 | jekyll-mentions (= 1.4.1) 45 | jekyll-optional-front-matter (= 0.3.0) 46 | jekyll-paginate (= 1.1.0) 47 | jekyll-readme-index (= 0.2.0) 48 | jekyll-redirect-from (= 0.14.0) 49 | jekyll-relative-links (= 0.5.3) 50 | jekyll-remote-theme (= 0.3.1) 51 | jekyll-sass-converter (= 1.5.2) 52 | jekyll-seo-tag (= 2.5.0) 53 | jekyll-sitemap (= 1.2.0) 54 | jekyll-swiss (= 0.4.0) 55 | jekyll-theme-architect (= 0.1.1) 56 | jekyll-theme-cayman (= 0.1.1) 57 | jekyll-theme-dinky (= 0.1.1) 58 | jekyll-theme-hacker (= 0.1.1) 59 | jekyll-theme-leap-day (= 0.1.1) 60 | jekyll-theme-merlot (= 0.1.1) 61 | jekyll-theme-midnight (= 0.1.1) 62 | jekyll-theme-minimal (= 0.1.1) 63 | jekyll-theme-modernist (= 0.1.1) 64 | jekyll-theme-primer (= 0.5.3) 65 | jekyll-theme-slate (= 0.1.1) 66 | jekyll-theme-tactile (= 0.1.1) 67 | jekyll-theme-time-machine (= 0.1.1) 68 | jekyll-titles-from-headings (= 0.5.1) 69 | jemoji (= 0.10.1) 70 | kramdown (= 1.16.2) 71 | liquid (= 4.0.0) 72 | listen (= 3.1.5) 73 | mercenary (~> 0.3) 74 | minima (= 2.5.0) 75 | nokogiri (>= 1.8.2, < 2.0) 76 | rouge (= 2.2.1) 77 | terminal-table (~> 1.4) 78 | github-pages-health-check (1.8.1) 79 | addressable (~> 2.3) 80 | dnsruby (~> 1.60) 81 | octokit (~> 4.0) 82 | public_suffix (~> 2.0) 83 | typhoeus (~> 1.3) 84 | html-pipeline (2.8.4) 85 | activesupport (>= 2) 86 | nokogiri (>= 1.4) 87 | http_parser.rb (0.6.0) 88 | i18n (0.9.5) 89 | concurrent-ruby (~> 1.0) 90 | jekyll (3.7.3) 91 | addressable (~> 2.4) 92 | colorator (~> 1.0) 93 | em-websocket (~> 0.5) 94 | i18n (~> 0.7) 95 | jekyll-sass-converter (~> 1.0) 96 | jekyll-watch (~> 2.0) 97 | kramdown (~> 1.14) 98 | liquid (~> 4.0) 99 | mercenary (~> 0.3.3) 100 | pathutil (~> 0.9) 101 | rouge (>= 1.7, < 4) 102 | safe_yaml (~> 1.0) 103 | jekyll-avatar (0.6.0) 104 | jekyll (~> 3.0) 105 | jekyll-coffeescript (1.1.1) 106 | coffee-script (~> 2.2) 107 | coffee-script-source (~> 1.11.1) 108 | jekyll-commonmark (1.2.0) 109 | commonmarker (~> 0.14) 110 | jekyll (>= 3.0, < 4.0) 111 | jekyll-commonmark-ghpages (0.1.5) 112 | commonmarker (~> 0.17.6) 113 | jekyll-commonmark (~> 1) 114 | rouge (~> 2) 115 | jekyll-default-layout (0.1.4) 116 | jekyll (~> 3.0) 117 | jekyll-feed (0.10.0) 118 | jekyll (~> 3.3) 119 | jekyll-gist (1.5.0) 120 | octokit (~> 4.2) 121 | jekyll-github-metadata (2.9.4) 122 | jekyll (~> 3.1) 123 | octokit (~> 4.0, != 4.4.0) 124 | jekyll-mentions (1.4.1) 125 | html-pipeline (~> 2.3) 126 | jekyll (~> 3.0) 127 | jekyll-optional-front-matter (0.3.0) 128 | jekyll (~> 3.0) 129 | jekyll-paginate (1.1.0) 130 | jekyll-readme-index (0.2.0) 131 | jekyll (~> 3.0) 132 | jekyll-redirect-from (0.14.0) 133 | jekyll (~> 3.3) 134 | jekyll-relative-links (0.5.3) 135 | jekyll (~> 3.3) 136 | jekyll-remote-theme (0.3.1) 137 | jekyll (~> 3.5) 138 | rubyzip (>= 1.2.1, < 3.0) 139 | jekyll-sass-converter (1.5.2) 140 | sass (~> 3.4) 141 | jekyll-seo-tag (2.5.0) 142 | jekyll (~> 3.3) 143 | jekyll-sitemap (1.2.0) 144 | jekyll (~> 3.3) 145 | jekyll-swiss (0.4.0) 146 | jekyll-theme-architect (0.1.1) 147 | jekyll (~> 3.5) 148 | jekyll-seo-tag (~> 2.0) 149 | jekyll-theme-cayman (0.1.1) 150 | jekyll (~> 3.5) 151 | jekyll-seo-tag (~> 2.0) 152 | jekyll-theme-dinky (0.1.1) 153 | jekyll (~> 3.5) 154 | jekyll-seo-tag (~> 2.0) 155 | jekyll-theme-hacker (0.1.1) 156 | jekyll (~> 3.5) 157 | jekyll-seo-tag (~> 2.0) 158 | jekyll-theme-leap-day (0.1.1) 159 | jekyll (~> 3.5) 160 | jekyll-seo-tag (~> 2.0) 161 | jekyll-theme-merlot (0.1.1) 162 | jekyll (~> 3.5) 163 | jekyll-seo-tag (~> 2.0) 164 | jekyll-theme-midnight (0.1.1) 165 | jekyll (~> 3.5) 166 | jekyll-seo-tag (~> 2.0) 167 | jekyll-theme-minimal (0.1.1) 168 | jekyll (~> 3.5) 169 | jekyll-seo-tag (~> 2.0) 170 | jekyll-theme-modernist (0.1.1) 171 | jekyll (~> 3.5) 172 | jekyll-seo-tag (~> 2.0) 173 | jekyll-theme-primer (0.5.3) 174 | jekyll (~> 3.5) 175 | jekyll-github-metadata (~> 2.9) 176 | jekyll-seo-tag (~> 2.0) 177 | jekyll-theme-slate (0.1.1) 178 | jekyll (~> 3.5) 179 | jekyll-seo-tag (~> 2.0) 180 | jekyll-theme-tactile (0.1.1) 181 | jekyll (~> 3.5) 182 | jekyll-seo-tag (~> 2.0) 183 | jekyll-theme-time-machine (0.1.1) 184 | jekyll (~> 3.5) 185 | jekyll-seo-tag (~> 2.0) 186 | jekyll-titles-from-headings (0.5.1) 187 | jekyll (~> 3.3) 188 | jekyll-watch (2.0.0) 189 | listen (~> 3.0) 190 | jemoji (0.10.1) 191 | gemoji (~> 3.0) 192 | html-pipeline (~> 2.2) 193 | jekyll (~> 3.0) 194 | kramdown (1.16.2) 195 | liquid (4.0.0) 196 | listen (3.1.5) 197 | rb-fsevent (~> 0.9, >= 0.9.4) 198 | rb-inotify (~> 0.9, >= 0.9.7) 199 | ruby_dep (~> 1.2) 200 | mercenary (0.3.6) 201 | mini_portile2 (2.3.0) 202 | minima (2.5.0) 203 | jekyll (~> 3.5) 204 | jekyll-feed (~> 0.9) 205 | jekyll-seo-tag (~> 2.1) 206 | minitest (5.11.3) 207 | multipart-post (2.0.0) 208 | nokogiri (1.8.4) 209 | mini_portile2 (~> 2.3.0) 210 | octokit (4.10.0) 211 | sawyer (~> 0.8.0, >= 0.5.3) 212 | pathutil (0.16.1) 213 | forwardable-extended (~> 2.6) 214 | public_suffix (2.0.5) 215 | rb-fsevent (0.10.3) 216 | rb-inotify (0.9.10) 217 | ffi (>= 0.5.0, < 2) 218 | rouge (2.2.1) 219 | ruby-enum (0.7.2) 220 | i18n 221 | ruby_dep (1.5.0) 222 | rubyzip (1.2.1) 223 | safe_yaml (1.0.4) 224 | sass (3.5.7) 225 | sass-listen (~> 4.0.0) 226 | sass-listen (4.0.0) 227 | rb-fsevent (~> 0.9, >= 0.9.4) 228 | rb-inotify (~> 0.9, >= 0.9.7) 229 | sawyer (0.8.1) 230 | addressable (>= 2.3.5, < 2.6) 231 | faraday (~> 0.8, < 1.0) 232 | terminal-table (1.8.0) 233 | unicode-display_width (~> 1.1, >= 1.1.1) 234 | thread_safe (0.3.6) 235 | typhoeus (1.3.0) 236 | ethon (>= 0.9.0) 237 | tzinfo (1.2.5) 238 | thread_safe (~> 0.1) 239 | unicode-display_width (1.4.0) 240 | 241 | PLATFORMS 242 | ruby 243 | 244 | DEPENDENCIES 245 | github-pages 246 | 247 | BUNDLED WITH 248 | 1.16.3 249 | -------------------------------------------------------------------------------- /_site/jekyll/update/2017/08/04/welcome-to-jekyll.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Welcome to Jekyll! 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 108 | 109 | 110 |
111 |
112 |
113 | 114 |
115 |

Welcome to Jekyll!

116 | 122 |
123 | 124 |
125 |

You’ll find this post in your _posts directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run jekyll serve, which launches a web server and auto-regenerates your site when a file is updated.

126 | 127 |

To add new posts, simply add a file in the _posts directory that follows the convention YYYY-MM-DD-name-of-post.ext and includes the necessary front matter. Take a look at the source for this post to get an idea about how it works.

128 | 129 |

Jekyll also offers powerful support for code snippets:

130 | 131 |
def print_hi(name)
132 |   puts "Hi, #{name}"
133 | end
134 | print_hi('Tom')
135 | #=> prints 'Hi, Tom' to STDOUT.
136 | 137 |

Check out the Jekyll docs for more info on how to get the most out of Jekyll. File all bugs/feature requests at Jekyll’s GitHub repo. If you have questions, you can ask them on Jekyll Talk.

138 | 139 | 140 |
141 | 142 | 143 |
144 | 145 |
146 |
147 | 148 | 198 | 199 | 200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /_site/modules/ethicalengine1/stories.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Person Model - Stories 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 108 | 109 | 110 |
111 |
112 |
113 | 114 | 115 | 116 | 117 |
118 |

Person Model - Stories

119 |
120 |
121 |

university

122 | 123 |

From Teluta to Facebook

124 |

In part 1 of your work, we situated you as a worker of a hypothetical company called Teluta. But real-world companies constantly collect and represent our personal characteristics - at times, with terrible consequences. Read the stories below about instances about real companies…

125 | 126 |

What are the potential consequences of including characteristics in code?

127 | 131 | 132 |

What are the possible challenges of inferring characteristics?

133 | 136 | 137 |

Reflection Questions

138 | 139 |
    140 |
  • 141 |

    Imagine that Teluta cars tried to infer your characteristics on-the-fly using a suite of state-of-the-art sensors. Do you think that any of your characteristics could be misclassified? What would the implications of that misclassification be?

    142 |
  • 143 |
  • 144 |

    While you currently trust the leadership at Teluta, what if more morally dubious (or oblivious?) leaders took over the company after you had left. Do you think that any of your design decisions could be abused by the company? How?

    145 |
  • 146 |
  • 147 |

    Given this reflection, which characteristics would you remove from your code? Why?

    148 |
  • 149 |
  • 150 |

    Are there any tradeoffs to removing too many characteristics from Teluta’s code? What are they?

    151 |
  • 152 |
153 | 154 |
155 | 156 |
157 | 158 |
159 |
160 | 161 | 211 | 212 | 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /_site/modules/hiring/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Ethical Hiring Algorithms 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 108 | 109 | 110 |
111 |
112 |
113 | 114 | 115 | 116 | 117 |
118 |

Ethical Hiring Algorithms

119 |
120 |
121 |

ethical hiring

122 | 123 |
    124 |
  • Course: CS 1
  • 125 |
  • Language: Python
  • 126 |
  • Practice: for loops, conditionals, lists
  • 127 |
  • Approx. Time: 1-2 hours (depending on revisions)
  • 128 |
129 | 130 |

Scenario: Moogle’s Hiring Filter

131 |

Imagine you are working for Moogle, a well-known tech company that receives tens of thousands of job applications from graduating seniors every year.

132 | 133 |

Since the company receives too many job applications for HR to individually assess in a reasonable amount of time, you are asked to create a program that algorithmically analyzes applications and selects the ones most worth passing onto HR.

134 | 135 |

Assignment

136 |

Students are presented Part 1 without any ethical framing or knowledge of Part 2.

137 | 144 | 145 |

Supplemental Reading

146 | 152 | 153 |
154 | 155 |
156 | 157 |
158 |
159 | 160 | 210 | 211 | 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /_site/modules/ethicalengine2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Robotoni's Disaster Relief Robot 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 108 | 109 | 110 |
111 |
112 |
113 | 114 | 115 | 116 | 117 |
118 |

Robotoni's Disaster Relief Robot

119 |
120 |
121 |

rescue

122 | 123 |

This scenario was developed by Evan Peck (Bucknell University). Parts of the instructions and exercise were created by Vinesh Kannan (Mimir HQ

124 | 125 |
    126 |
  • Course: CS 1
  • 127 |
  • Language: Python
  • 128 |
  • Practice: conditionals, use of API and objects
  • 129 |
  • Approx. Time: 1-2 hours for individual, longer if group prioritization is done
  • 130 |
131 | 132 |

Scenario: Robotoni’s Disaster-Relief Robot

133 |

You are working for an emerging robotics company, Robotoni, that is taking the admiral stance of developing robots to aid in life-threatening events. Their current objective is to build a fleet of autonomous robots that will rescue people in who are caught in two natural disasters: wildfires and floods.

134 | 135 |

Robotoni has already built a robot that can navigate unknown terrain and successfully rescue people who are in need of help. However, for Robotoni robots to act autonomously and maximize their impact, they must also make hard decisions. In effect, the Robotoni robot must prioritize who to save.

136 | 137 |

Your job is to write a comparison algorithm for the Robotoni Disaster-Relief Robot in which it compares two groups of people and decides which group to prioritize for relief.

138 | 139 |

Assignment

140 |

Note: This assignment can either follow Ethical Engine 1 or act as a standalone assignment.

141 | 145 | 146 |

Supplemental Reading

147 | 151 | 152 |
153 | 154 |
155 | 156 |
157 |
158 | 159 | 209 | 210 | 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /_site/modules/input/stories.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Harwall University Forms - Stories 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 108 | 109 | 110 |
111 |
112 |
113 | 114 | 115 | 116 | 117 |
118 |

Harwall University Forms - Stories

119 |
120 |
121 |

university

122 | 123 |

Now that you feel good about your form, consider the two vignettes below:

124 | 125 |

Vignette 1:

126 |
127 |

Chun Ying Tsang (20) is an exchange student from Birmingham, West Midlands, England. He is here as an exchange student and only just moved into his dorm yesterday. Although Chun Ying has an email address (Terrif.Ying@yahoo.com), he only has his UK cell phone +44 075 9921 9264.

128 |
129 | 130 |

Vignette 2:

131 |
132 |

Ash O’Connell-Chapman Jr. (33) has been invited to speak at an event co-hosted by CODE and Project SAFE. Drawing on personal experience growing up in Portage, MI, Ash will be talking about the discrimination faced by the transgender community, and how allies can support those who are transitioning. Due to previous harassment, Ash refused to give out a phone number or an email, instead directing you to the National Center for Transgender Equality website.

133 |
134 | 135 |

Before continuing, try to encode the information from these visitors with your program. What happens? Does your program work? Where does it fail?

136 | 137 |

The Beliefs We Hold

138 |

Read through the following webpages:

139 | 140 | 145 | 146 |

Reflection Questions

147 | 148 |
    149 |
  • 150 |

    Would your program work for the visitors at the beginning of Part 2? If not, why not? What assumptions did you make about the personal information of the visitors? What assumptions did you make about how this information would be entered?

    151 |
  • 152 |
  • 153 |

    How would you change your program so that it wouldn’t fail? What are the advantages and disadvantages of doing this? You do not have to actually make the changes, only describe what you would do.

    154 |
  • 155 |
  • 156 |

    Look through the links above. Why might programmers care about these things? How might you approach these problems differently in the future?

    157 |
  • 158 |
159 | 160 |
161 | 162 |
163 | 164 |
165 |
166 | 167 | 217 | 218 | 219 | 220 | 221 | 222 | -------------------------------------------------------------------------------- /_site/modules/input/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Ethical Input Validation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 108 | 109 | 110 |
111 |
112 |
113 | 114 | 115 | 116 | 117 |
118 |

Ethical Input Validation

119 |
120 |
121 |

university

122 | 123 |

This exercise was developed by Justin Li (Occidental College). It was adapted by Evan Peck (Bucknell)

124 | 125 |
    126 |
  • Course: CS 1
  • 127 |
  • Language: Python
  • 128 |
  • Practice: conditionals, data types, functions
  • 129 |
  • Approx. Time: 1-2 hours (depending on revisions)
  • 130 |
131 | 132 |

Scenario: Harwall University’s Visitors

133 |

You are working for the prestigious Harwall university to meet the joint needs of Admissions, Alumni Relations, and Communications. People are constantly visiting campus - to see someone they know, to check out the school as a prospective, to give a talk, to interview, to come back to the school (alumni!), or for a variety of reasons.

134 | 135 |

It would be valuable to know who is on a campus throughout the year, so you are asked to write a standard form that Harwall can give visitors to collect their information. Harwall intends to use the information from this form later on to communicate with potential donors or reach out to prospective students.

136 | 137 |

Since Harwall wants to make sure that this data is useful, they have also asked you to validate whatever information is entered into the form. That is your job.

138 | 139 |

Assignment

140 |

Students are presented Part 1 without any ethical framing or knowledge of Part 2.

141 | 145 | 146 |

Instructor Notes: Our sequencing of CS 1 (based off Harvey Mudd’s CS for All) teaches recursion before for and while loops. As a result, you’ll see that the template code uses recursion to repeat a function - feel free to change this based on the sequence in your course (most likely to a while loop).

147 | 148 |

Supplemental Reading

149 | 156 | 157 |
158 | 159 |
160 | 161 |
162 |
163 | 164 | 214 | 215 | 216 | 217 | 218 | 219 | -------------------------------------------------------------------------------- /_site/docs/faq.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | FAQ 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 108 | 109 | 110 |
111 |
112 |
113 | 114 | 115 | 116 | 117 |
118 |

FAQ

119 |
120 |
121 |

Can I contribute?

122 | 123 |

Sure! If you take a look at some of my modules in the repository, you’ll see that they have a similar structure. I write everything up in markdown and then use Jekyll to create the nice website you see here. Currently, I’m looking for modules that fit the following criteria:

124 | 125 |
    126 |
  • Appropriate for students in CS 1 (or CS 2)
  • 127 |
  • Is practice-based - students externalize their beliefs directly in code.
  • 128 |
  • Pairs with existing curriculum (for example, the exercise can double as practice for writing for loops)
  • 129 |
130 | 131 |

You can either email me at evan.peck@bucknell.edu or submit a pull request in the repository.

132 | 133 |

How do you see these modules being improved?

134 | 135 |

Many, many ways.

136 | 137 | 145 | 146 |

I see these modules more as conversation-starters than polished, finished assignments. I hope they are enough to encourage other educators to use them, but I also hope that people make them better!

147 | 148 |

How effective are these modules?

149 | 150 |

Anecdotally, I have had fantastic responses from my students - both during lectures themselves and afterwards in teaching evaluations. BUT..

151 | 152 |

Anecdotally is the key word here. There is no research behind their effectiveness, and I don’t pretend to be a CS ed researcher. Personally, I believe that learning ethical reflection habits alongside programming habits will be more effective than standalone ethics courses… but I have no evidence to back this up. While it’s in my longterm plan to quantify the impact of these modules, the bottom line here is that you should listen to CS education researchers over me.

153 | 154 |

How will I have time to insert these in my (very full) CS 1 courses?

155 | 156 |

The intention of these modules is that they pair directly with your existing curriculum. For example, I often set aside lecture or two for students to practice for loops on tiny functions. I still take that time, but instead of situating it on abstract functions, I situate that practice in an ethical reflection scenario.

157 | 158 |

I don’t want to claim that these modules take NO more time, but I’ve found the impact to be minimal in my course.

159 | 160 | 167 | 168 |

More soon…

169 | 170 |
171 | 172 |
173 | 174 |
175 |
176 | 177 | 227 | 228 | 229 | 230 | 231 | 232 | -------------------------------------------------------------------------------- /_site/modules/hiring/stories.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Moogle's Hiring Algorithm - Stories 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 108 | 109 | 110 |
111 |
112 |
113 | 114 | 115 | 116 | 117 |
118 |

Moogle's Hiring Algorithm - Stories

119 |
120 |
121 |

ethical hiring

122 | 123 |

Now that you feel good about your algorithm, let’s highlight some of those applicant and reveal the stories between them. For each of the following, reflect on whether you think that your algorithm does the right thing. If not, how could you change it?

124 | 125 |

Story 1: Misread the Instructions

126 |

What if an excellent applicant thinks they should put in letter grades?

127 | 128 |

[‘A’, ‘A’, ‘A’, ‘A’, ‘A’, ‘A’, ‘A’]

129 | 130 |

… or how about their grades on 4-point scale?

131 | 132 |

[4, 3.9, 4, 4, 3.95, 4, 3.9]

133 | 134 |

Story 2: Bad Assumptions

135 |

What if one of your applicants skipped Intro to Computer Science? When they saw your form, they froze, and decided that putting -1 in the input field would make it obvious…

136 | 137 |

[-1, 95, 99, 94, 96, 98, 95]

138 | 139 |

Story 3: Mistake in the Input

140 |

What if one of your applicants accidentally put in a number > 100?

141 | 142 |

[681, 68, 73, 70, 81, 91, 59]

143 | 144 |

That might seem easy enough for a program to catch, but what if they accidentally dropped a 0?

145 | 146 |

[100, 100, 100, 100, 100, 100, 10]

147 | 148 |

A person would catch that mistake easily, does your algorithm?

149 | 150 |

Story 4: The Awful Semester

151 |

What if your applicant had a medical emergency one semester? Or a personal tragedy?

152 | 153 |

[95, 93, 50, 91, 98, 90, 90]

154 | 155 |

Story 5: Inverse Trajectories

156 |

What if one of your applicants came from an underprivileged background and really struggled at the beginning of college… but showed extraordinary growth by the end?

157 | 158 |

[65, 75, 85, 95, 100, 100, 80]

159 | 160 |

What if one of your applicants came to college with extraordinary potential? They easily aced their first few classes and then gradually grew apathetic about their education - getting nothing but barely-passing grades by the time they were a senior?

161 | 162 |

[100, 100, 95, 85, 75, 65, 80]

163 | 164 |

Does your algorithm treat them equally?

165 | 166 |

Reflection Questions

167 |

There are often no easy answers to these questions… but we need to reflect on the tradeoffs of our decisions.

168 | 169 |
    170 |
  • What systemic advantages/disadvantages are your algorithms likely to amplify?
  • 171 |
  • What does it mean to design a fair algorithm?
  • 172 |
  • What is the human cost of efficiency? More permissive algorithms may capture more interesting candidates, but it also means more costly, human work. What is the ideal balance?
  • 173 |
174 | 175 |
176 | 177 |
178 | 179 |
180 |
181 | 182 | 232 | 233 | 234 | 235 | 236 | 237 | -------------------------------------------------------------------------------- /modules/ethicalengine2/code/scenario.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | 4 | def set_seed(seed): 5 | random.seed(seed); 6 | 7 | 8 | class Scenario: 9 | """ Packages all of the information needed to create an ethical scenario. 10 | Automatically construct a random scenario in which an autonomous robot must 11 | decide whether to save the people in location 1 vs. location 2 12 | 13 | Args: 14 | sameNum (bool, optional): if True, enforces that the number of 15 | people in location1 is the same as location2 16 | Attributes: 17 | numLoc1 (int): the number of entities at location 1 18 | numLoc2 (int): the number of entities at location 2 19 | loc1people (list): list of entities at location 1 20 | loc2people (list): list of entities at location 2 21 | youInLoc1 (bool): True if you are one of the people at location 1 22 | trespassing (bool): True if loc2people are currently trespassing 23 | """ 24 | # The minimum/maximum number of people at each location 25 | MIN_LOCATION1 = 1 26 | MAX_LOCATION1 = 1 27 | MIN_LOCATION2 = 1 28 | MAX_LOCATION2 = 1 29 | 30 | # The following variables are lists that represent the probabilities of 31 | # each feature happening. For example, in YOU_CHANCE, there is a 1 in 4 32 | # chance that that 'you' are in the vehicle. Similarly, in TRESPASSING_CHANCE, 33 | # there is a 2 in 3 chance that the loc2people are crossing the street 34 | # legally (the walk sign is on) 35 | YOU_CHANCE = [True, False, False, False] 36 | TRESPASSING_CHANCE = [True, True, False] 37 | 38 | def __init__(self, loc1people=None, loc2people=None, youInLoc1=None, trespassing=None, 39 | sameNum=True): 40 | # Create a random number of people in location 2 41 | numLoc2 = random.randint(self.MIN_LOCATION2, self.MAX_LOCATION2) 42 | 43 | # If sameNum is true, create the same number of people in location 1 44 | # Otherwise, create a random number of people in location 1 45 | if not sameNum: 46 | numLoc1 = random.randint(self.MIN_LOCATION1, self.MAX_LOCATION1) 47 | else: 48 | numLoc1 = numLoc2 49 | 50 | # DETERMINE THE PEOPLE IN LOCATION 1 51 | if loc1people is not None: 52 | self.loc1people = loc1people 53 | else: 54 | # Create randomly generated people for location 1 55 | self.loc1people = [Person() for numPeople in range(numLoc1)] 56 | 57 | # If you are in location 1, replace one of the people there with you. 58 | if youInLoc1 is not None: 59 | self.youInLoc1 = youInLoc1 60 | else: 61 | self.youInLoc1 = random.choice(self.YOU_CHANCE) 62 | 63 | if self.youInLoc1 is True: 64 | # Feel free to change these attributes if you'd like. 65 | youPerson = Person("you") 66 | if numLoc1 > 0: 67 | self.loc1people[0] = youPerson 68 | else: 69 | self.loc1people += [youPerson] 70 | 71 | # DETERMINE THE PEOPLE IN LOCATION 2 72 | if loc2people is not None: 73 | self.loc2people = loc2people 74 | else: 75 | self.loc2people = [Person() for numPeople in range(numLoc2)] 76 | 77 | # Determine if the people in location 2 are trespassing 78 | if trespassing is not None: 79 | self.trespassing = trespassing 80 | else: 81 | self.trespassing = random.choice(self.TRESPASSING_CHANCE) 82 | 83 | 84 | def __repr__(self): 85 | """ Method that helps python understand how to print a Scenario 86 | For example, you can now create a scenario in your code somewhere: 87 | scenario = Scenario() 88 | and then print that scenario: 89 | print(scenario) 90 | This will print a readable form of the scenario in your program 91 | """ 92 | readable = 'People at Location 1: \n' 93 | for entity in self.loc1people: 94 | readable += '-' + str(entity) + '\n' 95 | 96 | readable += '\n' 97 | readable += 'People at Location 2: \n' 98 | for entity in self.loc2people: 99 | readable += '-' + str(entity) + '\n' 100 | if self.trespassing: 101 | readable += '- This group is trespassing\n' 102 | readable += '\n' 103 | 104 | return readable 105 | 106 | 107 | class Person: 108 | """ Packages all the info needed for a person. 109 | Every scenario is composed of characters - many of which are people. Each 110 | of those people can contain a variety of characteristics. The Person class 111 | will automatically create a random person or animal. 112 | Attributes: 113 | charType (string): 'human', 'you', 'cat', 'dog' 114 | age (string): humans can be a 'baby', 'child', or 'adult' 115 | profession (string): adults are assigned a profession: 'doctor', 'CEO', 116 | 'criminal', 'homeless', 'unemployed', 'unknown' 117 | gender (string): 'male' or 'female' TODO: add more diverse options 118 | bodyType (string): adults are classified as 'average', 'athletic', 119 | or 'overweight' 120 | pregnant (bool): adult women may also be pregnant. True if pregant. 121 | """ 122 | # The following variables not only contain the possibilities of different 123 | # attributes of people/animals, but also the probability with which they 124 | # appear. For example, CHAR_TYPES contains 'human' 4 times and 'animal' 125 | # just 1 time. That means that 'human' is 4x more likely to appear. 126 | 127 | # Choose between a human or animal 128 | CHAR_TYPES = ["human", "human", "human", "animal", "human"] 129 | # If it's an animal, choose between cat or dog 130 | ANIMAL_TYPES = ["cat", "dog"] 131 | # Possible ages of humans 132 | AGE_TYPES = ["baby", "child", "adult", "adult", "adult", "elderly"] 133 | # Possible professions of adults 134 | PROF_TYPES = ["doctor", "CEO", "criminal", "homeless", "unemployed", 135 | "unknown", "unknown", "unknown"] 136 | # Possible genders of humans 137 | GENDER_TYPES = ["male", "female"] 138 | # Select whether a female is pregnant (currently 25% chance) 139 | PREGNANT_CHANCE = [True, False, False, False] 140 | # Select the bodytype of each non-child. 141 | BODYWEIGHT_CHANCE = ["overweight", "athletic", "average", "average"] 142 | 143 | def __init__(self, charType=None, age=None, profession=None, 144 | gender=None, bodyType=None, pregnant=None): 145 | ''' Create a person by randomly selecting their attributes 146 | All of the parameters in this method are OPTIONAL. This means that by 147 | default, a random person is made if no information is given. For 148 | example: 149 | person = Person() 150 | However, you can also create a custom person by filling in any 151 | number of those parameters. For example, the following code would 152 | create an adult woman with an average body type, but still allow 153 | the program to randomly select her profession: 154 | person = Person(charType="human", age="adult", gender="female", 155 | bodyType="average") 156 | ''' 157 | self.charType = charType 158 | self.profession = profession 159 | self.age = age 160 | self.gender = gender 161 | self.bodyType = bodyType 162 | self.pregnant = pregnant 163 | 164 | # set type of character (human or animal?) 165 | if charType is None: 166 | self.charType = random.choice(self.CHAR_TYPES) 167 | 168 | # If it's an animal, choose which type 169 | if self.charType == "animal": 170 | self.charType = random.choice(self.ANIMAL_TYPES) 171 | # If it's a person, set the characteristics 172 | if self.charType == "human": 173 | self.age = random.choice(self.AGE_TYPES) 174 | self.gender = random.choice(self.GENDER_TYPES) 175 | 176 | # Set adult characteristics. 177 | if self.age == "adult": 178 | self.bodyType = random.choice(self.BODYWEIGHT_CHANCE) 179 | if self.gender == "female": 180 | self.pregnant = random.choice(self.PREGNANT_CHANCE) 181 | self.profession = random.choice(self.PROF_TYPES) 182 | 183 | def __repr__(self): 184 | """ Method that helps python understand how to print a Person 185 | For example, you can now create a person in your code somewhere: 186 | person = Person() 187 | and then print that person to see what charecteristics it has: 188 | print(person) 189 | """ 190 | if self.charType == "human": 191 | readable = '[' 192 | if self.bodyType: 193 | readable += self.bodyType + ' ' 194 | if self.age: 195 | readable += self.age 196 | if self.gender: 197 | readable += ' ' + self.gender + ']' 198 | if self.profession: 199 | readable += ' job:' + self.profession 200 | if self.pregnant: 201 | readable += ', pregnant' 202 | else: 203 | readable = self.charType 204 | return readable 205 | -------------------------------------------------------------------------------- /_site/modules/ethicalengine2/code/scenario.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | 4 | def set_seed(seed): 5 | random.seed(seed); 6 | 7 | 8 | class Scenario: 9 | """ Packages all of the information needed to create an ethical scenario. 10 | Automatically construct a random scenario in which an autonomous robot must 11 | decide whether to save the people in location 1 vs. location 2 12 | 13 | Args: 14 | sameNum (bool, optional): if True, enforces that the number of 15 | people in location1 is the same as location2 16 | Attributes: 17 | numLoc1 (int): the number of entities at location 1 18 | numLoc2 (int): the number of entities at location 2 19 | loc1people (list): list of entities at location 1 20 | loc2people (list): list of entities at location 2 21 | youInLoc1 (bool): True if you are one of the people at location 1 22 | trespassing (bool): True if loc2people are currently trespassing 23 | """ 24 | # The minimum/maximum number of people at each location 25 | MIN_LOCATION1 = 1 26 | MAX_LOCATION1 = 1 27 | MIN_LOCATION2 = 1 28 | MAX_LOCATION2 = 1 29 | 30 | # The following variables are lists that represent the probabilities of 31 | # each feature happening. For example, in YOU_CHANCE, there is a 1 in 4 32 | # chance that that 'you' are in the vehicle. Similarly, in TRESPASSING_CHANCE, 33 | # there is a 2 in 3 chance that the loc2people are crossing the street 34 | # legally (the walk sign is on) 35 | YOU_CHANCE = [True, False, False, False] 36 | TRESPASSING_CHANCE = [True, True, False] 37 | 38 | def __init__(self, loc1people=None, loc2people=None, youInLoc1=None, trespassing=None, 39 | sameNum=True): 40 | # Create a random number of people in location 2 41 | numLoc2 = random.randint(self.MIN_LOCATION2, self.MAX_LOCATION2) 42 | 43 | # If sameNum is true, create the same number of people in location 1 44 | # Otherwise, create a random number of people in location 1 45 | if not sameNum: 46 | numLoc1 = random.randint(self.MIN_LOCATION1, self.MAX_LOCATION1) 47 | else: 48 | numLoc1 = numLoc2 49 | 50 | # DETERMINE THE PEOPLE IN LOCATION 1 51 | if loc1people is not None: 52 | self.loc1people = loc1people 53 | else: 54 | # Create randomly generated people for location 1 55 | self.loc1people = [Person() for numPeople in range(numLoc1)] 56 | 57 | # If you are in location 1, replace one of the people there with you. 58 | if youInLoc1 is not None: 59 | self.youInLoc1 = youInLoc1 60 | else: 61 | self.youInLoc1 = random.choice(self.YOU_CHANCE) 62 | 63 | if self.youInLoc1 is True: 64 | # Feel free to change these attributes if you'd like. 65 | youPerson = Person("you") 66 | if numLoc1 > 0: 67 | self.loc1people[0] = youPerson 68 | else: 69 | self.loc1people += [youPerson] 70 | 71 | # DETERMINE THE PEOPLE IN LOCATION 2 72 | if loc2people is not None: 73 | self.loc2people = loc2people 74 | else: 75 | self.loc2people = [Person() for numPeople in range(numLoc2)] 76 | 77 | # Determine if the people in location 2 are trespassing 78 | if trespassing is not None: 79 | self.trespassing = trespassing 80 | else: 81 | self.trespassing = random.choice(self.TRESPASSING_CHANCE) 82 | 83 | 84 | def __repr__(self): 85 | """ Method that helps python understand how to print a Scenario 86 | For example, you can now create a scenario in your code somewhere: 87 | scenario = Scenario() 88 | and then print that scenario: 89 | print(scenario) 90 | This will print a readable form of the scenario in your program 91 | """ 92 | readable = 'People at Location 1: \n' 93 | for entity in self.loc1people: 94 | readable += '-' + str(entity) + '\n' 95 | 96 | readable += '\n' 97 | readable += 'People at Location 2: \n' 98 | for entity in self.loc2people: 99 | readable += '-' + str(entity) + '\n' 100 | if self.trespassing: 101 | readable += '- This group is trespassing\n' 102 | readable += '\n' 103 | 104 | return readable 105 | 106 | 107 | class Person: 108 | """ Packages all the info needed for a person. 109 | Every scenario is composed of characters - many of which are people. Each 110 | of those people can contain a variety of characteristics. The Person class 111 | will automatically create a random person or animal. 112 | Attributes: 113 | charType (string): 'human', 'you', 'cat', 'dog' 114 | age (string): humans can be a 'baby', 'child', or 'adult' 115 | profession (string): adults are assigned a profession: 'doctor', 'CEO', 116 | 'criminal', 'homeless', 'unemployed', 'unknown' 117 | gender (string): 'male' or 'female' TODO: add more diverse options 118 | bodyType (string): adults are classified as 'average', 'athletic', 119 | or 'overweight' 120 | pregnant (bool): adult women may also be pregnant. True if pregant. 121 | """ 122 | # The following variables not only contain the possibilities of different 123 | # attributes of people/animals, but also the probability with which they 124 | # appear. For example, CHAR_TYPES contains 'human' 4 times and 'animal' 125 | # just 1 time. That means that 'human' is 4x more likely to appear. 126 | 127 | # Choose between a human or animal 128 | CHAR_TYPES = ["human", "human", "human", "animal", "human"] 129 | # If it's an animal, choose between cat or dog 130 | ANIMAL_TYPES = ["cat", "dog"] 131 | # Possible ages of humans 132 | AGE_TYPES = ["baby", "child", "adult", "adult", "adult", "elderly"] 133 | # Possible professions of adults 134 | PROF_TYPES = ["doctor", "CEO", "criminal", "homeless", "unemployed", 135 | "unknown", "unknown", "unknown"] 136 | # Possible genders of humans 137 | GENDER_TYPES = ["male", "female"] 138 | # Select whether a female is pregnant (currently 25% chance) 139 | PREGNANT_CHANCE = [True, False, False, False] 140 | # Select the bodytype of each non-child. 141 | BODYWEIGHT_CHANCE = ["overweight", "athletic", "average", "average"] 142 | 143 | def __init__(self, charType=None, age=None, profession=None, 144 | gender=None, bodyType=None, pregnant=None): 145 | ''' Create a person by randomly selecting their attributes 146 | All of the parameters in this method are OPTIONAL. This means that by 147 | default, a random person is made if no information is given. For 148 | example: 149 | person = Person() 150 | However, you can also create a custom person by filling in any 151 | number of those parameters. For example, the following code would 152 | create an adult woman with an average body type, but still allow 153 | the program to randomly select her profession: 154 | person = Person(charType="human", age="adult", gender="female", 155 | bodyType="average") 156 | ''' 157 | self.charType = charType 158 | self.profession = profession 159 | self.age = age 160 | self.gender = gender 161 | self.bodyType = bodyType 162 | self.pregnant = pregnant 163 | 164 | # set type of character (human or animal?) 165 | if charType is None: 166 | self.charType = random.choice(self.CHAR_TYPES) 167 | 168 | # If it's an animal, choose which type 169 | if self.charType == "animal": 170 | self.charType = random.choice(self.ANIMAL_TYPES) 171 | # If it's a person, set the characteristics 172 | if self.charType == "human": 173 | self.age = random.choice(self.AGE_TYPES) 174 | self.gender = random.choice(self.GENDER_TYPES) 175 | 176 | # Set adult characteristics. 177 | if self.age == "adult": 178 | self.bodyType = random.choice(self.BODYWEIGHT_CHANCE) 179 | if self.gender == "female": 180 | self.pregnant = random.choice(self.PREGNANT_CHANCE) 181 | self.profession = random.choice(self.PROF_TYPES) 182 | 183 | def __repr__(self): 184 | """ Method that helps python understand how to print a Person 185 | For example, you can now create a person in your code somewhere: 186 | person = Person() 187 | and then print that person to see what charecteristics it has: 188 | print(person) 189 | """ 190 | if self.charType == "human": 191 | readable = '[' 192 | if self.bodyType: 193 | readable += self.bodyType + ' ' 194 | if self.age: 195 | readable += self.age 196 | if self.gender: 197 | readable += ' ' + self.gender + ']' 198 | if self.profession: 199 | readable += ' job:' + self.profession 200 | if self.pregnant: 201 | readable += ', pregnant' 202 | else: 203 | readable = self.charType 204 | return readable 205 | -------------------------------------------------------------------------------- /_site/assets/main.css: -------------------------------------------------------------------------------- 1 | /** Reset some basic elements */ 2 | body, h1, h2, h3, h4, h5, h6, p, blockquote, pre, hr, dl, dd, ol, ul, figure { margin: 0; padding: 0; } 3 | 4 | /** Basic styling */ 5 | body { font: 400 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; color: #111; background-color: #fdfdfd; -webkit-text-size-adjust: 100%; -webkit-font-feature-settings: "kern" 1; -moz-font-feature-settings: "kern" 1; -o-font-feature-settings: "kern" 1; font-feature-settings: "kern" 1; font-kerning: normal; display: flex; min-height: 100vh; flex-direction: column; } 6 | 7 | /** Set `margin-bottom` to maintain vertical rhythm */ 8 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, ul, ol, dl, figure, .highlight { margin-bottom: 15px; } 9 | 10 | /** `main` element */ 11 | main { display: block; /* Default value of `display` of `main` element is 'inline' in IE 11. */ } 12 | 13 | /** Images */ 14 | img { max-width: 100%; vertical-align: middle; } 15 | 16 | /** Figures */ 17 | figure > img { display: block; } 18 | 19 | figcaption { font-size: 14px; } 20 | 21 | /** Lists */ 22 | ul, ol { margin-left: 30px; } 23 | 24 | li > ul, li > ol { margin-bottom: 0; } 25 | 26 | /** Headings */ 27 | h1, h2, h3, h4, h5, h6 { font-weight: 400; } 28 | 29 | /** Links */ 30 | a { color: #2a7ae2; text-decoration: none; } 31 | a:visited { color: #1756a9; } 32 | a:hover { color: #111; text-decoration: underline; } 33 | .social-media-list a:hover { text-decoration: none; } 34 | .social-media-list a:hover .username { text-decoration: underline; } 35 | 36 | /** Blockquotes */ 37 | blockquote { color: #828282; border-left: 4px solid #e8e8e8; padding-left: 15px; font-size: 18px; letter-spacing: -1px; font-style: italic; } 38 | blockquote > :last-child { margin-bottom: 0; } 39 | 40 | /** Code formatting */ 41 | pre, code { font-size: 15px; border: 1px solid #e8e8e8; border-radius: 3px; background-color: #eef; } 42 | 43 | code { padding: 1px 5px; } 44 | 45 | pre { padding: 8px 12px; overflow-x: auto; } 46 | pre > code { border: 0; padding-right: 0; padding-left: 0; } 47 | 48 | /** Wrapper */ 49 | .wrapper { max-width: -webkit-calc(800px - (30px * 2)); max-width: calc(800px - (30px * 2)); margin-right: auto; margin-left: auto; padding-right: 30px; padding-left: 30px; } 50 | @media screen and (max-width: 800px) { .wrapper { max-width: -webkit-calc(800px - (30px)); max-width: calc(800px - (30px)); padding-right: 15px; padding-left: 15px; } } 51 | 52 | /** Clearfix */ 53 | .wrapper:after, .footer-col-wrapper:after { content: ""; display: table; clear: both; } 54 | 55 | /** Icons */ 56 | .svg-icon { width: 16px; height: 16px; display: inline-block; fill: #828282; padding-right: 5px; vertical-align: text-top; } 57 | 58 | .social-media-list li + li { padding-top: 5px; } 59 | 60 | /** Tables */ 61 | table { margin-bottom: 30px; width: 100%; text-align: left; color: #3f3f3f; border-collapse: collapse; border: 1px solid #e8e8e8; } 62 | table tr:nth-child(even) { background-color: #f7f7f7; } 63 | table th, table td { padding: 10px 15px; } 64 | table th { background-color: #f0f0f0; border: 1px solid #dedede; border-bottom-color: #c9c9c9; } 65 | table td { border: 1px solid #e8e8e8; } 66 | 67 | /** Site header */ 68 | .site-header { border-top: 5px solid #424242; border-bottom: 1px solid #e8e8e8; min-height: 55.95px; position: relative; } 69 | 70 | .site-title { font-size: 26px; font-weight: 300; line-height: 54px; letter-spacing: -1px; margin-bottom: 0; float: left; } 71 | .site-title, .site-title:visited { color: #424242; } 72 | 73 | .site-nav { float: right; line-height: 54px; } 74 | .site-nav .nav-trigger { display: none; } 75 | .site-nav .menu-icon { display: none; } 76 | .site-nav .page-link { color: #111; line-height: 1.5; } 77 | .site-nav .page-link:not(:last-child) { margin-right: 20px; } 78 | @media screen and (max-width: 600px) { .site-nav { position: absolute; top: 9px; right: 15px; background-color: #fdfdfd; border: 1px solid #e8e8e8; border-radius: 5px; text-align: right; } 79 | .site-nav label[for="nav-trigger"] { display: block; float: right; width: 36px; height: 36px; z-index: 2; cursor: pointer; } 80 | .site-nav .menu-icon { display: block; float: right; width: 36px; height: 26px; line-height: 0; padding-top: 10px; text-align: center; } 81 | .site-nav .menu-icon > svg { fill: #424242; } 82 | .site-nav input ~ .trigger { clear: both; display: none; } 83 | .site-nav input:checked ~ .trigger { display: block; padding-bottom: 5px; } 84 | .site-nav .page-link { display: block; padding: 5px 10px; margin-left: 20px; } 85 | .site-nav .page-link:not(:last-child) { margin-right: 0; } } 86 | 87 | /** Site footer */ 88 | .site-footer { border-top: 1px solid #e8e8e8; padding: 30px 0; } 89 | 90 | .footer-heading { font-size: 18px; margin-bottom: 15px; } 91 | 92 | .contact-list, .social-media-list { list-style: none; margin-left: 0; } 93 | 94 | .footer-col-wrapper { font-size: 15px; color: #828282; margin-left: -15px; } 95 | 96 | .footer-col { float: left; margin-bottom: 15px; padding-left: 15px; } 97 | 98 | .footer-col-1 { width: -webkit-calc(35% - (30px / 2)); width: calc(35% - (30px / 2)); } 99 | 100 | .footer-col-2 { width: -webkit-calc(20% - (30px / 2)); width: calc(20% - (30px / 2)); } 101 | 102 | .footer-col-3 { width: -webkit-calc(45% - (30px / 2)); width: calc(45% - (30px / 2)); } 103 | 104 | @media screen and (max-width: 800px) { .footer-col-1, .footer-col-2 { width: -webkit-calc(50% - (30px / 2)); width: calc(50% - (30px / 2)); } 105 | .footer-col-3 { width: -webkit-calc(100% - (30px / 2)); width: calc(100% - (30px / 2)); } } 106 | @media screen and (max-width: 600px) { .footer-col { float: none; width: -webkit-calc(100% - (30px / 2)); width: calc(100% - (30px / 2)); } } 107 | /** Page content */ 108 | .page-content { padding: 30px 0; flex: 1; } 109 | 110 | .page-heading { font-size: 32px; } 111 | 112 | .post-list-heading { font-size: 28px; } 113 | 114 | .post-list { margin-left: 0; list-style: none; } 115 | .post-list > li { margin-bottom: 30px; } 116 | 117 | .post-meta { font-size: 14px; color: #828282; } 118 | 119 | .post-link { display: block; font-size: 24px; } 120 | 121 | /** Posts */ 122 | .post-header { margin-bottom: 30px; } 123 | 124 | .post-title { font-size: 42px; letter-spacing: -1px; line-height: 1; } 125 | @media screen and (max-width: 800px) { .post-title { font-size: 36px; } } 126 | 127 | .post-content { margin-bottom: 30px; } 128 | .post-content h2 { font-size: 32px; } 129 | @media screen and (max-width: 800px) { .post-content h2 { font-size: 28px; } } 130 | .post-content h3 { font-size: 26px; } 131 | @media screen and (max-width: 800px) { .post-content h3 { font-size: 22px; } } 132 | .post-content h4 { font-size: 20px; } 133 | @media screen and (max-width: 800px) { .post-content h4 { font-size: 18px; } } 134 | 135 | /** Syntax highlighting styles */ 136 | .highlight { background: #fff; } 137 | .highlighter-rouge .highlight { background: #eef; } 138 | .highlight .c { color: #998; font-style: italic; } 139 | .highlight .err { color: #a61717; background-color: #e3d2d2; } 140 | .highlight .k { font-weight: bold; } 141 | .highlight .o { font-weight: bold; } 142 | .highlight .cm { color: #998; font-style: italic; } 143 | .highlight .cp { color: #999; font-weight: bold; } 144 | .highlight .c1 { color: #998; font-style: italic; } 145 | .highlight .cs { color: #999; font-weight: bold; font-style: italic; } 146 | .highlight .gd { color: #000; background-color: #fdd; } 147 | .highlight .gd .x { color: #000; background-color: #faa; } 148 | .highlight .ge { font-style: italic; } 149 | .highlight .gr { color: #a00; } 150 | .highlight .gh { color: #999; } 151 | .highlight .gi { color: #000; background-color: #dfd; } 152 | .highlight .gi .x { color: #000; background-color: #afa; } 153 | .highlight .go { color: #888; } 154 | .highlight .gp { color: #555; } 155 | .highlight .gs { font-weight: bold; } 156 | .highlight .gu { color: #aaa; } 157 | .highlight .gt { color: #a00; } 158 | .highlight .kc { font-weight: bold; } 159 | .highlight .kd { font-weight: bold; } 160 | .highlight .kp { font-weight: bold; } 161 | .highlight .kr { font-weight: bold; } 162 | .highlight .kt { color: #458; font-weight: bold; } 163 | .highlight .m { color: #099; } 164 | .highlight .s { color: #d14; } 165 | .highlight .na { color: #008080; } 166 | .highlight .nb { color: #0086B3; } 167 | .highlight .nc { color: #458; font-weight: bold; } 168 | .highlight .no { color: #008080; } 169 | .highlight .ni { color: #800080; } 170 | .highlight .ne { color: #900; font-weight: bold; } 171 | .highlight .nf { color: #900; font-weight: bold; } 172 | .highlight .nn { color: #555; } 173 | .highlight .nt { color: #000080; } 174 | .highlight .nv { color: #008080; } 175 | .highlight .ow { font-weight: bold; } 176 | .highlight .w { color: #bbb; } 177 | .highlight .mf { color: #099; } 178 | .highlight .mh { color: #099; } 179 | .highlight .mi { color: #099; } 180 | .highlight .mo { color: #099; } 181 | .highlight .sb { color: #d14; } 182 | .highlight .sc { color: #d14; } 183 | .highlight .sd { color: #d14; } 184 | .highlight .s2 { color: #d14; } 185 | .highlight .se { color: #d14; } 186 | .highlight .sh { color: #d14; } 187 | .highlight .si { color: #d14; } 188 | .highlight .sx { color: #d14; } 189 | .highlight .sr { color: #009926; } 190 | .highlight .s1 { color: #d14; } 191 | .highlight .ss { color: #990073; } 192 | .highlight .bp { color: #999; } 193 | .highlight .vc { color: #008080; } 194 | .highlight .vg { color: #008080; } 195 | .highlight .vi { color: #008080; } 196 | .highlight .il { color: #099; } 197 | -------------------------------------------------------------------------------- /_site/assets/minima-social-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /_site/modules/hiring/instructions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Moogle's Hiring Algorithm 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 108 | 109 | 110 |
111 |
112 |
113 | 114 | 115 | 116 | 117 |
118 |

Moogle's Hiring Algorithm

119 |
120 |
121 |

ethical hiring

122 | 123 |

Scenario: Moogle’s Hiring Filter

124 |

Imagine you are working for Moogle, a well-known tech company that receives tens of thousands of job applications from graduating seniors every year.

125 | 126 |

Since the company receives too many job applications for HR to individually assess in a reasonable amount of time, you are asked to create a program that algorithmically analyzes applications and selects the ones most worth passing onto HR.

127 | 128 |

Applicant Data

129 |

It’s difficult to create these first-pass cuts, so Moogle designs their application forms to get some numerical data about their applicants’ education. Job applications must enter the grades they received in 6 core CS courses, as well as their overall GPA. For your convenience, this will be stored in a python list that you can access. For example, a student who received the following scores…

130 | 131 |
    132 |
  • Intro to CS: 100
  • 133 |
  • Data Structures: 95
  • 134 |
  • Software Engineering: 80
  • 135 |
  • Algorithms: 89
  • 136 |
  • Computer Organization: 91
  • 137 |
  • Operative Systems: 75
  • 138 |
  • Overall GPA: 83
  • 139 |
140 | 141 |

… would result in the following list: [100, 95, 80, 89, 91, 75, 83]. You can assume that index 0 is always Intro to CS, 1 is always Data Structures, and so on.

142 | 143 |

Because you are processing many applications, your program will receive a list of lists. For example, this would be the information for 3 applicants:

144 | 145 |

[ [100, 95, 80, 89, 91, 75, 83], [75, 80, 85, 90, 85, 88, 90], [85, 70, 99, 100, 81, 82, 91] ]

146 | 147 |

Your Task

148 |

Your job is to:

149 |
    150 |
  1. Determine how you are going to select the top applicants to pass onto HR.
  2. 151 |
  3. Given a list of applicant data (a list of lists), write a function returns a new list of worthwhile candidates.
  4. 152 |
153 | 154 |

Your Code

155 |

To get you started, we’re provided some template code:

156 | 157 |
    158 |
  • hiring.py a template where you will write your applicant-selection algorithm based on a small set of dummy data.
  • 159 |
  • lottaApps.py a module that contains a list of ten-thousand randomly generated applicants you can try once you have completed your code.
  • 160 |
161 | 162 |

In hiring.py, you will be writing a series of predefined analyze_applicant methods which apply different criteria to applicants. Through this process, you will not only get a sense of the tradeoffs of different criteria, but also get practice writing various for loops. (Note: this is meant to give you practice with for loops, so don’t use python’s built in functions such as sum() or min())

163 | 164 |

Complete the following methods:

165 |
    166 |
  • analyze_applicant1 accepts applicants that have an overall GPA above 80. (Does not need a for loop)
  • 167 |
  • analyze_applicant2 accepts applicants that have no grade below 65.
  • 168 |
  • analyze_applicant3 accepts applicants that have at least 4 grades above 85.
  • 169 |
  • analyze_applicant4 accepts applicants that have an average above 85.
  • 170 |
171 | 172 |

After writing, testing, and considering the tradeoffs of these four methods, write your own criteria in your_analysis.

173 | 174 |

Questions you should answer:

175 | 176 |
    177 |
  1. 178 |

    What criteria did you choose to select finalists? How did you choose that criteria?

    179 |
  2. 180 |
  3. 181 |

    Roughly what percentage of applicants does your algorithm pass on as finalists? Is that enough? If Moogle asked you to take a more aggressive approach with your algorithm, are there any tradeoffs?

    182 |
  4. 183 |
184 | 185 |
186 | 187 |
188 | 189 |
190 |
191 | 192 | 242 | 243 | 244 | 245 | 246 | 247 | --------------------------------------------------------------------------------