├── CODE_OF_CONDUCT.md ├── README.md ├── emails ├── 1.md ├── 2.md ├── 3.md ├── 4.md ├── 5.md ├── 6.md └── 7.md └── tracks ├── java └── exercises │ └── binary-search │ └── README.md ├── python └── exercises │ ├── allergies │ └── README.md │ └── bob │ └── README.md ├── ruby └── exercises │ ├── clock │ └── README.md │ └── matrix │ └── README.md └── rust ├── .gitignore └── exercises └── leap ├── Cargo.toml ├── README.md └── src └── lib.rs /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | This policy was adopted from the Front-end London Slack community. 2 | 3 | _This policy is a "living" document, and subject to refinement and expansion in the future. This policy applies to every Exercism entity or event, including but not limited to the Slack community, Twitter chats and GitHub posts._ 4 | 5 | The simple version: 6 | 7 | - be welcoming 8 | - be kind 9 | - be honest 10 | - be supportive 11 | 12 | The details: 13 | 14 | Exercism should be a safe place for everybody regardless of 15 | - gender, gender identity or gender expression 16 | - sexual orientation 17 | - disability 18 | - physical appearance (including but not limited to body size) 19 | - race 20 | - age 21 | - religion 22 | 23 | anything else you can think of. 24 | 25 | As someone who is part of this community, you agree that: 26 | 27 | - We are collectively and individually committed to safety and inclusivity. 28 | - We have zero tolerance for abuse, harassment, or discrimination. 29 | - We respect people’s boundaries and identities. 30 | - We refrain from using language that can be considered oppressive (systemically or otherwise), eg. sexist, racist, homophobic, transphobic, ableist, classist, etc. - this includes (but is not limited to) various slurs. 31 | - We avoid using offensive topics as a form of humour. 32 | 33 | We actively work towards: 34 | 35 | - Being a safe community 36 | - Cultivating a network of support & encouragement for each other 37 | - Encouraging responsible and varied forms of expression 38 | 39 | We condemn: 40 | 41 | - Stalking, doxxing, or publishing private information 42 | - Violence, threats of violence or violent language 43 | - Anything that compromises people’s safety 44 | - Conduct or speech which might be considered sexist, racist, homophobic, transphobic, ableist or otherwise discriminatory or offensive in nature. 45 | - Do not use unwelcome, suggestive, derogatory or inappropriate nicknames or terms. 46 | - Do not show disrespect towards others. (Jokes, innuendo, dismissive attitudes.) 47 | - Intimidation or harassment (online or in-person). Please read the Citizen Code of Conduct for how we interpret harassment. 48 | - Disrespect towards differences of opinion. 49 | - Inappropriate attention or contact. 50 | - Not understanding the differences between constructive criticism and disparagement. 51 | 52 | These things are NOT OK. 53 | 54 | Be aware of how your actions affect others. If it makes someone uncomfortable, stop. 55 | 56 | If you say something that is found offensive, and you are called out on it, let’s: 57 | 58 | - Listen without interruption. 59 | - Believe what the person is saying & do not attempt to disqualify what they have to say. 60 | - Ask for tips / help with avoiding making the offence in the future. 61 | - Apologise and ask forgiveness. 62 | - Failing to follow the Code of Conduct as described in this document carries consequences. For minor infractions, you may be temporarily suspended from using Exercism. Upon repeat offenses, or if the community believes you are not acting in good faith, you may be asked to leave permanently. 63 | 64 | If you experience abuse, harassment, discrimination, or feel unsafe, email abuse@exercism.io. 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Exercism Mentors 2 | 3 | **NOTE: This repository is deprecated. Mentor notes now live in the [exercism/website-copy](https://github.com/exercism/website-copy) repository.** 4 | 5 | ## Not a mentor? 6 | 7 | We are always looking for more mentors to help new people ramp up in the programming languages that Exercism supports. Read more about mentorship at Exercism on [mentoring.exercism.io](https://mentoring.exercism.io/). 8 | 9 | ## Crowd-sourced mentor notes 10 | The structure within the repository is: `/tracks/ruby/exercises/isogram/README.md`. 11 | 12 | - You can easily edit the files within GitHub to create Pull Requests for changes. 13 | - We'll be offering some mentors write permissions to the repo so that they can merge PRs without waiting for us to check everything. 14 | - In the near-future we'll auto-pull things into the website to display it for mentors at the relevant time. 15 | 16 | Please use `###` for headings and try to keep to a structure of: 17 | 18 | - **Reasonable solutions:** 1+ solutions that solve this problem well. 19 | - **Common suggestions:** Good suggestions specific to this exercise. Good lessons that emerge from it. 20 | - **Talking points:** Questions to challenge more advance learners with. 21 | 22 | Here's an example for [Ruby's Isogram](https://github.com/exercism/mentors/blob/master/tracks/ruby/exercises/isogram/README.md). 23 | 24 |
25 | This is how you create a new file: 26 | 27 | ![Create a new file](http://g.recordit.co/96zCDgEkfG.gif) 28 | 29 |
30 | 31 | ## General Mentoring Questions 32 | 33 | ### How many mentors do we need? 34 | 35 | Well, that depends. For any given track, the minimum number of active mentors is *five*. This ensures that the burden is never too great for a single mentor, even when life gets busy for a bit, or you go on vacation. Beyond this, we need an extra mentor for every ten-twelve additional submissions per week. 36 | 37 | For reference, the most active track at the moment is the Python track, with about 150 submissions per day. This equates roughly to a need for about 90 active mentors, each giving about 1 hour per week. 38 | -------------------------------------------------------------------------------- /emails/1.md: -------------------------------------------------------------------------------- 1 | Hi, 2 | 3 | Firstly I want to say a **big** thank you from the Exercism team for signing up to be a mentor. Two years ago we decided to apply the learnings and lessons from 4 years of seeing Exercism grow organically and design the product "properly" from the ground up. One of the key decisions that came out of this redesign process was that we felt Exercism should move from a community-based mentoring model to a more formally-structured one, where we could develop a team of mentors that could give high-quality, empathetic and thoughtful feedback. You are one of the first guinea pigs in this massive change and we are incredibly grateful for you taking that journey with us. 4 | 5 | After two years of thinking, writing and coding, we are now closing in on launching the new Exercism site. We have a [beta version](https://v2.exercism.io/) which we update periodically and a (manageable) number of blocking issues that we are working through. We are targeting launch on or close to 9th July. We currently have 1,000 submissions per day on the [original Exercism site](http://exercism.io), of which fewer than 20% receive feedback. Our key launch-targets are to not decrease the number of submissions per day (ie, not have made it harder for people to use Exercism) and to achieve >95% feedback-rate. Presuming mentors can offer 1hr/week on average, we have calculated how many mentors we need to achieve this on [this spreadsheet](https://docs.google.com/spreadsheets/d/1M3K03UIkgfPV3-WWFprX-eBFoZ6mMdoLTtqhRNG3N3k/edit#gid=0). 6 | 7 | We care deeply about having a mentor team that is diverse in their skills, knowledge, styles and representation, and are working hard to achieve this by reaching out to different communities and circles in tech. When we find mentors we also hope that they can deepen the team. Based on the premise that friendly mentors hang-out with other friendly potential-mentors, if everyone was able to recruit two friends, that would greatly help us have enough mentors for launch. The spreadsheet above shows the key areas where we are weak. Python, Rust, Java, Haskell, Kotlin, Swift, Closure and C are the areas where we especially weak right now. Your help would be massively appreciated! 8 | 9 | In preparation for the big launch, there are a few things you can do to make sure we have a smooth start: 10 | - Sign up to our Slack room. You should have received an invitation. If you haven't, please let me know. 11 | - Join the track-specific channels (e.g. track-ruby) for the language tracks you want to mentor. 12 | - Read the [Code Review](https://github.com/exercism/docs/blob/master/about/conception/code-review.md) document that explains why we decided to move to a formal mentoring model. 13 | - Push any friends who you think would make good mentors to http://mentoring.exercism.io/ 14 | - Try out the first 5-10 exercises from each track you have chosen to mentor on the [original Exercism site](http://exercism.io/). 15 | 16 | In the next two weeks we will be launching a mentors-specific-version of the new site where you can try out the mentorship tools by mentoring other mentors. We will also create a mechanism for you to send us your photos/bios to appear around the Exercism site. We will be in touch again then. In the meantime, see you on Slack, and thank you again! 17 | 18 | Jeremy and the Exercism team. 19 | -------------------------------------------------------------------------------- /emails/2.md: -------------------------------------------------------------------------------- 1 | Hi, 2 | 3 | It's been an exciting week in Exercism-land as we've now recruited 50% of the mentors we need to launch. Thank you if you've been inviting your friends and colleagues! 4 | 5 | I have one update, one request, and one offer: 6 | 7 | 1) We will be launching a version of the new website just for mentors this week where you can practice mentoring in the new interface. This will give you an opportunity to try things out, get familiar with the tooling and exercises, and report any bugs! I will let you know when that is launched. 8 | 9 | 2) In preparation for that please can you ensure that you're registered on Slack and in the correct channels for your chosen languages. This will correspond to which tracks you mentor on the test (and eventually live) site. I explained this more here: https://exercism-mentors.slack.com/archives/CANG20CKE/p1528843725000303 10 | 11 | 3) As part of the new website we want to feature our mentors on the relevant track pages and the "Our Mentors" page. If you would like to appear on the website, please follow the instructions here: https://github.com/exercism/website-copy/blob/master/mentors/README.md#mentors 12 | 13 | We're only 3 weeks away from launch now and both very excited and a bit nervous. Thanks for being on this journey with us! 14 | 15 | Jeremy and the Exercism team 16 | -------------------------------------------------------------------------------- /emails/3.md: -------------------------------------------------------------------------------- 1 | Hey, 2 | 3 | The mentors testing site is now live for you to use! 4 | 5 | This site is a version of the new Exercism, exclusive for mentors, where you can learn the exercises, explore the mentoring interface and practice your mentoring skills. It's also an opportunity to highlight any bugs or issues that that you find. 6 | 7 | - The website is here: https://mentors-beta.exercism.io/ 8 | - Learn how to download and use the CLI here: https://exercism-mentors.slack.com/archives/CAQP7JL3T/p1529683167000115?thread_ts=1529683065.000711&cid=CAQP7JL3T 9 | 10 | **Please read these things carefully:** 11 | 12 | - Forget about v2.exercism.io and the nextercism CLI for this phase. This is a different sandbox. 13 | 14 | - Please only sign up using GitHub Oauth for now as emails are turned off so you won't be able to confirm and get in that way. If you don't have a GitHub account you can message me on Slack and I'll sort something out for you. 15 | 16 | - To make this testing-phase work, we need you to submit solutions so you and other mentors have something to give feedback on! Feel free to submit solutions in your mentor-languages or on different language that you want to learn. 17 | 18 | - You will become a mentor of any track you join (this is because I've not had time to do the Slack integration yet). 19 | 20 | - This is an empty db. Old solutions won't be there. You can of course submit an old solution through the CLI if you want to. Instructions are here: https://exercism-mentors.slack.com/archives/CAQP7JL3T/p1529612222000221?thread_ts=1529612208.000076&cid=CAQP7JL3T 21 | 22 | - If you find anything that's broken, please report it at https://github.com/exercism/v2-feedback/issues 23 | 24 | - While building better tools for mentors is high on our roadmap, we're actively not asking for feature requests at this time, unless they're something you consider critical. Once we've launched and got everything working well, then we'll start exploring next steps with you :) 25 | 26 | - Feel free to bounce any questions on Slack in either the #questions channel (for more formal questions) or #chat if you want to discuss things. 27 | 28 | We're really excited to see you all on there soon! 29 | 30 | Thanks, 31 | 32 | Jeremy and the Exercism team 33 | -------------------------------------------------------------------------------- /emails/4.md: -------------------------------------------------------------------------------- 1 | Hi, 2 | 3 | I have two pieces of exciting news. Firstly, we've hit the amazing milestone of having 500 mentors! We're incredibly humbled and excited that you've all joined up to help others improve their coding skills. Thank you! 4 | 5 | Secondly, we have two developers working full time on Exercism for the summer sponsored by RailsGirls Summer of Code. Amalia (amaliacardenas) and Lori (loriking) will be working on helping develop the mentoring-side of Exercism, working on resources and tooling to help make your time on Exercism as fun and easy as possible. Please say hello to them on Slack over the next few days :) 6 | 7 | I have created at #start-here channel on Slack with a checklist of what you need to do before launch. Please have a look to ensure you've done everything there. You can find it here: https://exercism-mentors.slack.com/archives/CBDA9LMDF/p1529968977000336 8 | 9 | Only 50% of people have joined the correct language channels. **Please double-check that you have** as we need to understand where to spend money advertising for mentors, and we don't want it to go to waste. 10 | 11 | We're about two weeks from launch now and getting more excited by the day. Thanks for being part of this journey! 12 | 13 | Jeremy and the Exercism team 14 | -------------------------------------------------------------------------------- /emails/5.md: -------------------------------------------------------------------------------- 1 | Hi, 2 | 3 | We're live!! There are still lots of rough edges and things we want to improve and add, but we're happy with where we've got to and have put it live. Thank you to everyone who has tried things out and given us feedback over the last few weeks - it's been invaluable. The fun starts here! 4 | 5 | To get started, please follow these instructions in Slack: https://exercism-mentors.slack.com/archives/CBDA9LMDF/p1529968977000336 6 | 7 | We've started writing a mentoring guide here (https://exercism.io/mentoring-guide) and put some FAQs together here (https://exercism.io/mentoring-faqs) 8 | 9 | Please note that the mentors-beta site and mentorcism are now dead. Everything is live on the real site (https://exercism.io). If you've been submitting solutions to the site, you should be able to (easily) to submit them to the new site instead. The new CLI is here: https://github.com/exercism/cli/releases/tag/v3.0.1 10 | 11 | We had ~1,000 solutions submitted per day to the old site and we expect this to grow over the next few days as things like email notifications bring people back more than before, so we're going to need a continuing flow of new mentors to help out. If you know anyone that you think would make a great mentor, please do encourage them to check out http://mentoring.exercism.io/ 12 | 13 | Thanks so much for being part of this journey. We're super excited and somewhat terrified right now :) 14 | 15 | Jeremy and The Exercism Team 16 | -------------------------------------------------------------------------------- /emails/6.md: -------------------------------------------------------------------------------- 1 | Hi , 2 | 3 | Wow - what a first week! If you've been active in mentoring, please accept our huge gratitude. The mentors have done a brilliant job in keeping up with the level of submissions we've been having, especially ensuring that the "core" solutions which block users are promptly mentored :) 4 | 5 | If you've only just joined as a mentor or haven't managed to get set up yet, you can find the starting instructions here: https://exercism-mentors.slack.com/archives/CBDA9LMDF/p1529968977000336 6 | 7 | In the background we've been working hard to fix bugs, add some new features, and triage the 250(!) issues that have been opened. There are still some pretty urgent issues we're working through, but once everything has settled, our next phase of development will be focused on improvements to the mentoring experience. If you have thoughts or opinions on things we should add, please comment on the existing issues or open a new one at https://github.com/exercism/exercism.io. 8 | 9 | Slack has also been brilliant since launch. Some great conversations - especially in the track-specific channel. If you've not been using it, please do check it out. We created a channel today where we're posting some of the lovely feedback we're receiving. It's worth checking out Slack just for that :) https://exercism-mentors.slack.com/archives/CBWDVPECE/p1532342509000228 10 | 11 | Some stats for you: 12 | - The community have submitted 11,369 solutions with a total of 277,786 lines of code. 13 | - You and our other mentors have helped 5,177 learners, posting a total of 6,609 comments. 14 | - Over 3,026 new members have joined Exercism and over 3,000 of our existing members have checked out the new site. All without any publicity other than word-of-mouth. 15 | - We've helped people from 134 different countries. 16 | 17 | I hope you're enjoying mentoring and finding that you're learning lots from it too. Thanks again for all your hard work! 18 | 19 | Jeremy and the Exercism Team 20 | -------------------------------------------------------------------------------- /emails/7.md: -------------------------------------------------------------------------------- 1 | Hi, 2 | 3 | Since we launched the new version of Exercism three weeks ago nearly 3,000 learners have received mentoring on over 8,500 solutions, receiving 15,982 pieces of feedback. We think that's pretty incredible. Thank you to everyone that's made that possible! 4 | 5 | All of this is even more amazing considering that **only 1/3 of the people who have signed up to mentor have actually started mentoring**. We currently have 500 mentors sitting in the wings waiting to give feedback on their first solution. So far we've generally kept up well with the backlog of exercises, but we've been relying on quite a few star mentors who have been giving feedback on over 100 solutions per week. This isn't sustainable and so we really need those who have signed up to mentor to get started to even our the load for everyone. If everyone that's signed up gives **one hour per week**, we'll be entirely on top of all submissions across all tracks - which would be amazing for everyone using Exercism. 6 | 7 | **If you haven't started mentoring, can I please encourage you to do so.** It's quick and easy to get started, and once you get going you'll find it strangely addictive! The instructions are here on our Slack Room here: https://exercism-team.slack.com/archives/CBDA9LMDF/p1529968977000336 - if you have any questions or problems please post a message on #chat on Slack and someone will reply. If you can't get onto Slack, just reply to this and I'll help you out. Also, if you've decided you don't want to be involved, please can you reply and let me know that too, so that we can try and recruit someone to take your place. 8 | 9 | Mentoring on Exercism is proving to be interesting, fun, and intellectually rewarding. There are numerous conversations on Slack about how even the most senior developers are learning new tips and tricks and seeing different approaches to solving problems. Why not give it a try today? :) 10 | 11 | Thanks, 12 | Jeremy and the Exercism team 13 | -------------------------------------------------------------------------------- /tracks/java/exercises/binary-search/README.md: -------------------------------------------------------------------------------- 1 | :warning: The following notes are for a version of the exercise that does not involve the use of generics (see this [issue](https://github.com/exercism/java/issues/1507) for more information). To validate a solution involving generics, use [this test](https://github.com/exercism/java/blob/65e2f240123b3357e310881bc5f2c29e92009343/exercises/binary-search/src/test/java/BinarySearchTest.java). 2 | 3 | ### Reasonable solutions 4 | 5 | #### Using a while-loop 6 | ```java 7 | 8 | import java.util.List; 9 | 10 | class BinarySearch { 11 | 12 | private List array; 13 | private int arraySize; 14 | 15 | BinarySearch(List array) { 16 | this.array = array; 17 | this.arraySize = array.size(); 18 | } 19 | 20 | int indexOf(int value) { 21 | return search(value); 22 | } 23 | 24 | private int search(int value) { 25 | int left = 0; 26 | int right = arraySize - 1; 27 | 28 | while (left <= right) { 29 | int middle = (left + right) / 2; 30 | int element = array.get(middle); 31 | 32 | if (value > element) { 33 | left = middle + 1; 34 | } else if (value < element) { 35 | right = middle - 1; 36 | } else { 37 | return middle; 38 | } 39 | } 40 | 41 | return -1; 42 | } 43 | } 44 | ``` 45 | 46 | #### Using recursion 47 | ```java 48 | 49 | import java.util.List; 50 | 51 | class BinarySearch { 52 | 53 | private List array; 54 | private int arraySize; 55 | 56 | BinarySearch(List array) { 57 | this.array = array; 58 | this.arraySize = array.size(); 59 | } 60 | 61 | int indexOf(int value) { 62 | return search(value, 0, arraySize - 1); 63 | } 64 | 65 | private int search(int value, int left, int right) { 66 | if (left > right) { 67 | return -1; 68 | } 69 | 70 | int middle = (left + right) / 2; 71 | int element = array.get(middle); 72 | 73 | if (value > element) { 74 | return search(value, middle + 1, right); 75 | } else if (value < element) { 76 | return search(value, left, middle - 1); 77 | } else { 78 | return middle; 79 | } 80 | } 81 | } 82 | ``` 83 | 84 | ### Common suggestions 85 | 86 | - Use `left + (right - left) / 2` instead of `(left + right) / 2` to avoid overflow. _See [Nearly All Binary Searches and Mergesorts are Broken](https://ai.googleblog.com/2006/06/extra-extra-read-all-about-it-nearly.html) by Joshua Bloch._ 87 | 88 | ### Talking points 89 | 90 | - Precomputing `arraySize` is correct only if we assume that the size of `array` will never change. However, without a defensive copy (which could be inefficient) this is not true. 91 | - Recursion is safe for binary search because it require at most _log2(n)_ stack frames, where _n_ is the size of the array. Nevertheless, a while-loop uses less memory. 92 | -------------------------------------------------------------------------------- /tracks/python/exercises/allergies/README.md: -------------------------------------------------------------------------------- 1 | ### Reasonable Solutions 2 | 3 | A `list`-based solution optimizes for `Allergies.lst` access, but sacrifices the speed of `Allergies.is_allergic_to` lookups. 4 | 5 | ```python 6 | class Allergies: 7 | allergens = [ 8 | "eggs", 9 | "peanuts", 10 | "shellfish", 11 | "strawberries", 12 | "tomatoes", 13 | "chocolate", 14 | "pollen", 15 | "cats", 16 | ] 17 | 18 | def __init__(self, score): 19 | self.score = score 20 | self._items = [item 21 | for ind, item in enumerate(self.allergens) 22 | if score & (1 << ind)] 23 | 24 | def is_allergic_to(self, item): 25 | return item in self._items 26 | 27 | @property 28 | def lst(self): 29 | return self._items 30 | ``` 31 | 32 | A `dict`-based solution optimizes for `Allergies.is_allergic_to` lookups, but sacrifices the speed of `Allergies.lst` access. 33 | The `Allergies.lst` cost is greater if maintaining sort order in Python versions < 3.7 is important. 34 | 35 | ```python 36 | class Allergies: 37 | allergens = { 38 | "eggs": 1, 39 | "peanuts": 2, 40 | "shellfish": 4, 41 | "strawberries": 8, 42 | "tomatoes": 16, 43 | "chocolate": 32, 44 | "pollen": 64, 45 | "cats": 128, 46 | } 47 | 48 | def __init__(self, score): 49 | self.score = score 50 | self._items = {k: v for k, v in self.allergens.items() if score & v} 51 | 52 | def is_allergic_to(self, item): 53 | return item in self._items 54 | 55 | @property 56 | def lst(self): 57 | return sorted(self._items, key=self.allergens.get) 58 | ``` 59 | 60 | A hybrid solution seeks decent performance from both access methods. 61 | 62 | ```python 63 | class Allergies: 64 | allergens = { 65 | "eggs": 1, 66 | "peanuts": 2, 67 | "shellfish": 4, 68 | "strawberries": 8, 69 | "tomatoes": 16, 70 | "chocolate": 32, 71 | "pollen": 64, 72 | "cats": 128, 73 | } 74 | 75 | def __init__(self, score): 76 | self.score = score 77 | self._items = [item for item in self.allergens if self.is_allergic_to(item)] 78 | self._items.sort(key=self.allergens.get) 79 | 80 | def is_allergic_to(self, item): 81 | return self.allergens.get(item, 0) & self.score != 0 82 | 83 | @property 84 | def lst(self): 85 | return self._items 86 | ``` 87 | 88 | Lastly, an `enum.Flag`-based solution sacrifices some overall performance in exchange for readability. 89 | 90 | ```python 91 | from enum import Flag, auto 92 | 93 | class Allergens(Flag): 94 | EGGS = auto() 95 | PEANUTS = auto() 96 | SHELLFISH = auto() 97 | STRAWBERRIES = auto() 98 | TOMATOES = auto() 99 | CHOCOLATE = auto() 100 | POLLEN = auto() 101 | CATS = auto() 102 | 103 | class Allergies: 104 | def __init__(self, score): 105 | self.score = Allergens(score & sum(a.value for a in Allergens)) 106 | self._items = [a.name.lower() for a in Allergens if a in self.score] 107 | 108 | def is_allergic_to(self, item): 109 | try: 110 | return Allergens[item.upper()] in self.score 111 | except KeyError: 112 | return False 113 | 114 | @property 115 | def lst(self): 116 | return self._items 117 | ``` 118 | 119 | ### Common Suggestions 120 | 121 | #### The Binary Representation of Integers and Bitwise Operators Can Help 122 | 123 | *Note: This suggestion was written up for a student that was struggling with this exercise, so it's probably quite a bit more wordy than it needs to be for an average submission.* 124 | 125 | --- 126 | 127 | An approach that makes the logic more intuitive is to leverage the _binary representation_ of integers and the _bitwise operators_ that Python provides to work with them. 128 | 129 | Recall that, from the computer's perspective, _all_ integers are stored as binary data; when you work with the decimal (aka base 10) integers (ie 0 - 10), you're really just interacting with the _decimal representation_ of the underlying binary data. The computer simply defaults to decimal because it is the most familiar and easily understood representations for humans. There are other _useful_ representations, including _octal_ (base 8) and _hexidecimal_ (base 16), but from Python's perspective an integer value in any one representation is _exactly_ the same as the same value in any other representation. 130 | 131 | ``` 132 | 0b01100100 == 0o144 == 100 == 0x64 # notice they're all the same value... 133 | # => True 134 | 135 | 0b01100100 is 0o144 is 100 is 0x64 # but also all the same actual object in memory 136 | # => True 137 | ``` 138 | 139 | For most purposes there's no reason not work in the familiar decimal world, but some problems benefit from working with the binary representation directly. Any time you see powers of 2, it's a good idea to at least consider whether or not the binary representation and bitwise operators can help you out. When you see exclusively unique powers of 2 being summed, especially, it's an indicator you might be working with, or may want to implement, a _bit flag_. 140 | 141 | First, let's look at how the smaller powers of 2 look in their 8-bit binary representation: 142 | 143 | ``` 144 | 2**0 1 0b00000001 145 | 2**1 2 0b00000010 146 | 2**2 4 0b00000100 147 | 2**3 8 0b00001000 148 | 2**4 16 0b00010000 149 | 2**5 32 0b00100000 150 | 2**6 64 0b01000000 151 | 2**7 128 0b10000000 152 | ``` 153 | 154 | Notice how each power of 2 is really just a single 1 in a unique column? And that moving the 1 a column to the left doubles the value? That's what allows you to multiply by 2 using the _bitwise left shift_ (`<<`) operator, and divide by 2 using the _bitwise right shift_ (`>>`) operator: 155 | 156 | ```python 157 | 24 << 1 158 | # => 48 159 | 160 | 100 >> 2 161 | # => 25 162 | 163 | 1 << 7 # ie 1 x 2^7 164 | # => 128 165 | ``` 166 | 167 | Incidentally, the `bin` function is a helpful way to quickly check the binary representation of a given value, but notice that it does strip off any leading 0s. 168 | 169 | ``` 170 | bin(1) 171 | # => '0b1' 172 | 173 | bin(128) 174 | # => '0b10000000' 175 | ``` 176 | 177 | Ok, but how is all of this useful to the problem at hand? Well, notice what happens to the binary representation of the result when you exclusively sum unique powers of 2 (ie, no individual power of 2 ever contributes to the sum more than once). 178 | 179 | ``` 180 | 0b00000001 # 1 181 | 0b01000000 # 64 182 | 0b10000000 # 128 183 | + __________ 184 | 0b11000001 # 193 185 | ``` 186 | 187 | See how the sum has a 1 in every column for which each of the components had a 1? That is the property that allows us to construct a bit flag: all we need to do to check if a given power of 2 contributed to a given sum is to see if they share a 1 in the same column. 188 | 189 | But how do we do that? 190 | 191 | Well, let's talk about the _bitwise AND_ operator (`&`); this operator takes two numbers and performs an AND of their binary representations, returning the number that has a 1 wherever _both_ inputs had a 1 and 0 anywhere else; so, for instance, `38 & 34` will return `34` because of the columns in which both values share a 1, while `3 & 32` will return `0` because no shared 1 columns exist. 192 | 193 | ``` 194 | 0b00100110 # 38 195 | 0b00100010 # 34 196 | & __________ 197 | 0b00100010 # 34 198 | 199 | 0b00000011 # 3 200 | 0b00100000 # 32 201 | & __________ 202 | 0b00000000 # 0 203 | ``` 204 | 205 | So, let's look at 65; the binary representation of 65 is `0b01000001`, so there is a 1 in the 0th power position (furthest right, which is 1) and a 1 in the 6th power position (second from the left, which is 64), which makes it the sum of 1 and 64. You'll note that, even though 65 is larger than 2, 4, 8, 16, and 32, those numbers did not contribute to 65 because there's no 1 in their respective columns. So let's take a look at what happens when we bitwise AND 65 with each power of 2. 206 | 207 | ```python 208 | 65 & 1 209 | # => 1 210 | 65 & 2 211 | # => 0 212 | 65 & 4 213 | # => 0 214 | 65 & 8 215 | # => 0 216 | 65 & 16 217 | # => 0 218 | 65 & 32 219 | # => 0 220 | 65 & 64 221 | # => 64 222 | 65 & 128 223 | # => 0 224 | ``` 225 | 226 | See how everything returned zero _except_ for 1 and 64? The nice thing about doing things this way is that it provides a slick way of filtering out the higher powers of 2 (in this case 256, 512, 1024, etc) that we don't care about. 227 | 228 | ```python 229 | 257 & 1 230 | # => 1 231 | 257 & 2 232 | # => 0 233 | # ... All of the rest will be zero. 234 | ``` 235 | 236 | Granted, for 257, there will be a 1 in the **eighth** power of 2 place, but for the purposes of this exercise we only care about columns 0-7, so we can ignore that column. 237 | 238 | To make that extra clear, let's do 509. Binary for 509 is: 239 | 240 | ``` 241 | 0b111111101 242 | # We'll only be checking the rightmost 8 digits: 243 | 0b1 | 11111101 244 | ``` 245 | 246 | Let's check each of our allergens: 247 | 248 | ```python 249 | 509 & 1 250 | # => 1 251 | 509 & 2 252 | # => 0 253 | 509 & 4 254 | # => 4 255 | 509 & 8 256 | # => 8 257 | 509 & 16 258 | # => 16 259 | 509 & 32 260 | # => 32 261 | 509 & 64 262 | # => 64 263 | 509 & 128 264 | # => 128 265 | ``` 266 | 267 | The only one that came out zero is 2, which, on our list, is peanuts. So anyone with score of 509 would be allergic to everything but peanuts. 268 | 269 | ### Talking Points 270 | 271 | - Be careful with making overly complex list comprehensions. Anytime you add an extra loop or a conditional `if`, try to see if there is any way you can make it extra readable. 272 | - Integers are integers; `0b10000000 == 128 and 0b10000000 is 128`; there's no such thing as a "binary number" or "non-binary number", there are only different representations. 273 | - Python binary operators work on numbers given in any representation. `35 & 6` works just as well as `0b100011 & 0b110` or for that matter `0x23 & 0o6` 274 | -------------------------------------------------------------------------------- /tracks/python/exercises/bob/README.md: -------------------------------------------------------------------------------- 1 | ### Reasonable solutions 2 | 3 | A conditional structure with a single nested **if** can avoid duplicated effort: 4 | 5 | ```python 6 | def hey(phrase): 7 | """ 8 | Answer for Bob. 9 | """ 10 | phrase = phrase.strip() 11 | if not phrase: 12 | return "Fine. Be that way!" 13 | if phrase.isupper(): 14 | if phrase.endswith("?"): 15 | return "Calm down, I know what I'm doing!" 16 | return "Whoa, chill out!" 17 | if phrase.endswith("?"): 18 | return "Sure." 19 | return "Whatever." 20 | ``` 21 | 22 | Alternatively, reserving the outcome of the two main tests can result in a flatter structure: 23 | 24 | ```python 25 | def hey(phrase): 26 | """ 27 | Answer for Bob. 28 | """ 29 | phrase = phrase.strip() 30 | if not phrase: 31 | return "Fine. Be that way!" 32 | 33 | is_yelling = phrase.isupper() 34 | is_question = phrase.endswith("?") 35 | 36 | if is_yelling and is_question: 37 | return "Calm down, I know what I'm doing!" 38 | if is_yelling: 39 | return "Whoa, chill out!" 40 | if is_question: 41 | return "Sure." 42 | return "Whatever." 43 | ``` 44 | 45 | It's also possible to maintain Single Entry Single Exit (SESE), though see Talking Points below. 46 | 47 | ```python 48 | def hey(phrase): 49 | """ 50 | Answer for Bob. 51 | """ 52 | answer = "Whatever." 53 | phrase = phrase.strip() 54 | if not phrase: 55 | answer = "Fine. Be that way!" 56 | else: 57 | if phrase.isupper(): 58 | if phrase.endswith("?"): 59 | answer = "Calm down, I know what I'm doing!" 60 | answer = "Whoa, chill out!" 61 | elif phrase.endswith("?"): 62 | answer = "Sure." 63 | return answer 64 | ``` 65 | 66 | ### Common suggestions 67 | - use the standard methods of the **str** class to your advantage 68 | - the **str.isupper** method ignores the presence of characters that are non case-aware 69 | - the **str.endswith** method is more flexible than indexing / slicing and comparison 70 | - both **str.strip** and **str.rstrip** will convert an all-whitespace **phrase** to the empty string 71 | - in this case it's acceptable to _shadow_ the the original, un-stripped **phrase** with one stripped of padding, since no part of the rest of the function is concerned with the un-stripped form 72 | - try to eliminate unnecessary work; for instance, avoid checking if an empty **phrase** is a question or yelled 73 | - try to eliminate duplicate work; neither of the other two checks need ever be run more than once 74 | - helper functions _may_ help overall readability 75 | 76 | ### Talking points 77 | - rather than have multiple **return** statements, you _may_ find it helpful to track the return value through the conditional tree as a variable, so that you have a single **return** statement; this is known as Single Entry Single Exit or SESE, however: 78 | - doing so without duplicating effort often results in structures that are more complicated and even less readable than the alternative 79 | - you eliminate the logical help that earlier **return** statements higher up in the code give you; the careful use of **if** and **elif** can return some of this, but multiple **if** statements can easily result multiple changes to the result 80 | - SESE is mainly a virtue in languages that have a _goto_ statement; as Python lacks any such functionality its benefits are far less clear; consider trying it both ways and see which is more readable to you 81 | - in Python [truth-value testing](https://docs.python.org/3/library/stdtypes.html#truth-value-testing) is the idiomatic way to check for the presence of an empty (`if not phrase:`) or non-empty (`if phrase:`) string; indeed it's the idiomatic way to check for the "empty" or "full" versions of all the builtin types and collections, and should generally be used in favor of direct comparison or length testing 82 | -------------------------------------------------------------------------------- /tracks/ruby/exercises/clock/README.md: -------------------------------------------------------------------------------- 1 | # Clock 2 | 3 | Clock introduces students to the concept of **value objects** and **[modular 4 | arithmetic](https://www.khanacademy.org/computing/computer-science/cryptography/modarithmetic/a/what-is-modular-arithmetic)**. 5 | 6 | **Note:** This exercise changes a lot depending on which version the person has solved. 7 | 8 | ## Reasonable solutions 9 | 10 | ```ruby 11 | class Clock 12 | MINUTES_PER_HOUR = 60 13 | MINUTES_PER_DAY = 1440 14 | 15 | def initialize(hour: 0, minute: 0) 16 | @time = ((hour * MINUTES_PER_HOUR) + minute) % MINUTES_PER_DAY 17 | end 18 | 19 | def to_s 20 | "%02d:%02d" % time.divmod(MINUTES_PER_HOUR) 21 | end 22 | 23 | def +(other) 24 | self.class.new(minute: time + other.time) 25 | end 26 | 27 | def -(other) 28 | self.class.new(minute: time - other.time) 29 | end 30 | 31 | def ==(other) 32 | time == other.time 33 | end 34 | alias eql? == 35 | 36 | def hash 37 | [self.class, self.time].hash 38 | end 39 | 40 | protected 41 | 42 | attr_reader :time 43 | end 44 | ``` 45 | 46 | A good solution should have the following: 47 | 48 | * Store a single quantity 49 | * Implement [value-object semantics](https://www.sitepoint.com/value-objects-explained-with-ruby/) (immutability, `==`/`hash`/`eql?` by value) 50 | * Not store more than a day's worth of time 51 | * Use `protected` to allow access to another instance’s `time` in `==` without making the attributes public. 52 | - Use constants instead of [magic numbers](https://refactoring.guru/replace-magic-number-with-symbolic-constant). 53 | 54 | ## Mentoring flow 55 | 56 | 1. Discuss single vs double quantity in more depth modeling 57 | 2. Discuss immutability 58 | 3. Discuss guaranteeing that you store less than a days worth of time (this is 59 | easier if you've got immutable objects because validation can be done once in 60 | the constructor) 61 | 4. Discuss hash/eql? 62 | 5. Teach `divmod()` 63 | 5. Final round discussing style 64 | 65 | ## Common suggestions 66 | 67 | ### Modeling objects with a single quantity versus separate minutes and hours 68 | 69 | This makes the math easier. Storing hours and minutes separately is effectively 70 | caching a calculation. It's usually done because the student is modeling human 71 | groupings directly. Help student realize that "time elapsed since midnight" is a 72 | single quantity, even though humans represent it as two quantities for ease of 73 | reading. 74 | 75 | ### Return new instances from `+` and `-` 76 | 77 | In general, value objects should never change and instead return new instances. 78 | This prevents tricky bugs in client code. More on this in the talking points 79 | below. 80 | 81 | ### Implement `#hash` and `#eql?` 82 | 83 | Objects that re-implement `#==` usually also want to re-implement `#hash` and 84 | `#eql?` so that objects that are considered the "same" are still considered 85 | "same" when used as hash keys. It's normal to define these methods when creating 86 | value objects. 87 | 88 | ### Don't store more than a day's worth of time 89 | 90 | A `Clock` represents the time elapsed since midnight _this morning_. This number 91 | cannot be greater than than 1439 minutes (23:59). Anything over is greater than 92 | a day violates the expectation of what a `Clock` represents. The student should 93 | use modulo to roll over to the next day in the constructor. 94 | 95 | Doing this allows students to remove any code that does division by 24 or 96 | conditionally checks for time greater than one day sprinkled in other parts of 97 | their code. 98 | 99 | ### Don't manually check for negative numbers 100 | 101 | The output of a modulo operation will _always_ be positive: 102 | 103 | Modulo operations on negative numbers just move backwards on the clock. This 104 | means you don't need extra logic to check for negative numbers. 105 | 106 | See the discussion on modulo vs remainder in the talking points below. 107 | 108 | ### Use named constants instead of using numbers directly 109 | 110 | Using constants instead of numbers like 60, 24, 1440 directly helps with 111 | readability. A good guideline is that all numbers other than 1 and 0 should used 112 | via a constant rather than directly inline. 113 | 114 | ## Talking points 115 | 116 | ### Storing 1 vs 2 quantities 117 | 118 | **What is a Clock?** 119 | 120 | Think about what a `Clock` represents. It's a time-of-day, a value between 00:00 121 | and 23:59. A time-of-day is effectively a big counter that starts at 0 and 122 | resets after one day. 123 | 124 | **Human vs Computer** 125 | 126 | Humans break up large numbers into different size units to make them easier to 127 | understand. _"10 hours and 40 minutes"_ makes more sense (to an English speaker) 128 | than _"640 minutes"_. We do the same with other quantities too (e.g. _"5 feet 129 | and 6 inches"_ instead of _"66 inches"_). 130 | 131 | Computers on the other hand don't care. In software, these sorts of counters are 132 | usually implemented as a single number in whatever the smaller unit is (e.g. 133 | milliseconds for time or cents for US currency). This makes the math easier and 134 | you can easily convert to human readable formats when it's time to render. 135 | 136 | **Prior Art** 137 | 138 | Times and dates in particular are usually defined this way. You define some zero 139 | point (sometimes called the _epoch_) and store a single counter since then. Some 140 | examples of this approach include: 141 | 142 | * [UNIX timestamps](http://unixtimestamp.50x.eu/about.php) measure date-times as 143 | the number of milliseconds since midnight on January 1st 1970. 144 | * [Postgres time-of-day](https://www.postgresql.org/docs/current/static/datatype-datetime.html) 145 | stores the number of microseconds since midnight (very similar problem to 146 | `Clock` but with higher precision) 147 | 148 | **Math** 149 | 150 | Adding is now easy because it's just ... adding. No need to re-balance 151 | hours/minutes every time you add minutes. 152 | 153 | Getting the human-readable values is easy too. To get hours and minutes you 154 | either divide or modulo by the number of minutes per hour (60) 155 | 156 | ```ruby 157 | def hours 158 | @total / 60 159 | end 160 | 161 | def minutes 162 | @total % 60 163 | end 164 | ``` 165 | 166 | However, it's easier to use the `divmod` method which does both things at once. 167 | 168 | **Storing Two Values** 169 | 170 | Storing two values is a form of eagerly caching that calculation of minutes to 171 | hours and minutes. Every time you do a math operation on the two clocks, you 172 | have to go through and re-adjust the hours and minutes even if you never need to 173 | convert to a human-readable format. 174 | 175 | The advantage you get with this approach though is that if you're rendering the 176 | human readable version very frequently you aren't calculating every time but can 177 | rely on the cached value. 178 | 179 | ### Immutability 180 | 181 | Students will often mutate in `+` and `-` instead of returning a new instance of 182 | `Clock`. While this passes the tests, it can easily lead to bugs in client code 183 | like: 184 | 185 | ```ruby 186 | start_time = Clock.new(hour: 10, minute: 30) 187 | duration = Clock.new(hour: 1, minute: 30) 188 | 189 | # one hour and thirty minutes later... 190 | end_time = start_time + duration 191 | 192 | puts "Event duration: #{start_time.to_s} - #{end_time.to_s}" 193 | ``` 194 | 195 | mutable clock returns 196 | 197 | > Event duration: 12:00 - 12:00 198 | 199 | immutable clock returns 200 | 201 | > Event duration: 10:30 - 12:00 202 | 203 | [Value objects](https://www.sitepoint.com/value-objects-explained-with-ruby/) 204 | like `Clock` should almost always be immutable to prevent this sort of bug. 205 | Bonus points if you `#freeze` in the constructor. 206 | 207 | ### modulo vs remainder 208 | 209 | **modulo (%)** is a sort of circular math. Doing modulo with a negative number can 210 | be thought of as moving backwards on a clock with `n` ticks on it. The value 211 | returned will _always_ be positive. 212 | 213 | **remainder** is the classic "do integer division and give me what's left that 214 | didn't divide cleanly". This number _can_ be negative if one of the inputs is 215 | negative. 216 | 217 | ```ruby 218 | # modulo 219 | 57 % 60 # => 57 220 | 117 % 60 # => 57 221 | -57 % 60 # => 3 222 | -117 % 60 # => 3 223 | 224 | # remainder 225 | 57.remainder 60 # => 57 226 | 117.remainder 60 # => 57 227 | -57.remainder 60 # => -57 228 | -117.remainder 60 # => -57 229 | ``` 230 | 231 | ### Invalid states 232 | 233 | Clocks represent a "time of day" value which should always be less than a day's 234 | worth of time. Discuss why storing more time should be invalid. Discuss what it 235 | means to allow invalid states. What are the consequences? Why is it bad? How can 236 | we avoid it? 237 | 238 | ### Method visibility 239 | 240 | Discuss `public` vs `protected` vs `private`. Value objects often expose their 241 | internal values as protected attributes. 242 | 243 | ### Human vs computer representations 244 | 245 | Often it's easier to do operations on data in one form but easier for humans to 246 | read it in a different form. The following pattern: 247 | 248 | 1. Take input in human form, convert it to internal representation 249 | 2. Do operations on internal representation 250 | 3. Convert to human-friendly form when displaying result 251 | 252 | is very common in software. Discuss the difference between human representation 253 | of data and data that is easy to work with. 254 | 255 | -------------------------------------------------------------------------------- /tracks/ruby/exercises/matrix/README.md: -------------------------------------------------------------------------------- 1 | # Matrix 2 | 3 | ## Reasonable Solutions 4 | 5 | ```ruby 6 | class Matrix 7 | attr_reader :rows, :columns 8 | def initialize(matrix_as_string) 9 | @rows = extract_rows(matrix_as_string) 10 | @columns = rows.transpose 11 | end 12 | 13 | private 14 | def extract_rows(string) 15 | string.each_line.map { |line| line.split.map(&:to_i) } 16 | end 17 | end 18 | ``` 19 | 20 | Many solutions will not split out the input parsing into methods like this. We don't yet have consensus among mentors if this is important or not. If the methods are split out, then they should be private. 21 | 22 | ## Common Suggestions 23 | 24 | There's no need to overload a student with all of these suggestions, so here is a list ordered roughly by most important suggestions first: 25 | 26 | - For students who wrote code that interleaves string manipulation with data persistance, encourage them to do those steps sequentially 27 | - Suggest the student look at other methods on `String` that could simplify their code if they don't use `String#lines` or `String#each_line` 28 | - If they have written their own transpose method, `point out Array#transpose` 29 | - More generally, for any solutions that has matching based on a regular expression or explicitly decleared string or substring, encourage them to find a solution that does not require either 30 | - If the solution is reasonable, then approve it, but suggest that they might want to attempt to write their own version of `Array#transpose`. 31 | -------------------------------------------------------------------------------- /tracks/rust/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /tracks/rust/exercises/leap/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "leap" 3 | version = "0.1.0" 4 | authors = ["Peter Tillemans "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /tracks/rust/exercises/leap/README.md: -------------------------------------------------------------------------------- 1 | ### Reasonable solutions 2 | 3 | ```rust 4 | pub fn is_leap_year(year): 5 | year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) 6 | ``` 7 | 8 | ### Common suggestions 9 | - there are just two cases that return True: 10 | - a year is a multiple of 4 *and not** 100 11 | - a year is a multiple of 4, 100, and 400 12 | - order of operations matter: 13 | - 75% of all years *cannot* be leap years because they are not mulitples of 4; 14 | test `year % 4 == 0` first 15 | - 98.97% of all years that are multiples of 4 are not multiples of 100; test 16 | `year % 100 != 0` second 17 | - 1.03% of all years that are multiples of 4 are also multiples of 100 and 18 | 400; test `year % 400 == 0` third 19 | - order of evaluation matters: 20 | 21 | ```rust 22 | year $ 4 == 0 && year % 100 != 0 || year % 400 == 0 23 | ``` 24 | 25 | _looks_ right, but will force a year like 999 to be checked for being a 26 | multiple of 400 unnecessarily 27 | - eliminate duplicate work; no year should ever have to be checked multiple 28 | times for the same condition 29 | 30 | ### Talking points 31 | - it's very helpful to internalize the rules Rust uses for [expression 32 | order](https://doc.rust-lang.org/reference/expressions.html#expression-precedence) 33 | - there is no compile time penalty of binding parts of the boolean expression to 34 | a meaningful name and combine the afterwards 35 | 36 | ### Benchmark code 37 | 38 | Included is a simple project which benchmarks some variants. 39 | 40 | - leap1 uses bindings to name subexpressions and combines them afterwards 41 | - leap2 uses the recommended expression above 42 | - leap3 uses an alternative expression 43 | - leap4 uses the counter example which shows that evaluation order matters 44 | 45 | results: 46 | 47 | ```shell 48 | exercises/leap - [master●●] » cargo bench 49 | Finished release [optimized] target(s) in 0.04s 50 | Running target/release/deps/leap-ac2b7d8794582ded 51 | 52 | running 4 tests 53 | test tests::leap1_bench ... bench: 1,644 ns/iter (+/- 103) 54 | test tests::leap2_bench ... bench: 1,641 ns/iter (+/- 182) 55 | test tests::leap3_bench ... bench: 1,628 ns/iter (+/- 105) 56 | test tests::leap4_bench ... bench: 2,637 ns/iter (+/- 312) 57 | 58 | test result: ok. 0 passed; 0 failed; 0 ignored; 4 measured; 0 filtered out 59 | ``` 60 | 61 | This clearly shows that: 62 | - binding sub expressions is zero-cost as long as they have no side effects. 63 | - order of evaluation *does* matter 64 | -------------------------------------------------------------------------------- /tracks/rust/exercises/leap/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | extern crate test; 3 | 4 | pub fn is_leap_year1(year: i32) -> bool { 5 | let div_4 = year % 4 == 0; 6 | let div_100 = year % 100 == 0; 7 | let div_400 = year % 400 == 0; 8 | div_4 && !(div_100 && !div_400) 9 | } 10 | 11 | pub fn is_leap_year2(year: i32) -> bool { 12 | year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) 13 | } 14 | 15 | pub fn is_leap_year3(year: i32) -> bool { 16 | year % 4 == 0 && !(year % 100 == 0 && year % 400 != 0) 17 | } 18 | 19 | pub fn is_leap_year4(year: i32) -> bool { 20 | year % 4 == 0 && year % 100 != 0 || year % 400 == 0 21 | } 22 | 23 | #[cfg(test)] 24 | mod tests { 25 | use super::*; 26 | use test::Bencher; 27 | 28 | #[bench] 29 | fn leap1_bench(b: &mut Bencher) { 30 | b.iter( || { 31 | (0..1200).fold(0, |cnt, year| if is_leap_year1(year) {cnt + 1} else {cnt}) 32 | }) 33 | } 34 | 35 | #[bench] 36 | fn leap2_bench(b: &mut Bencher) { 37 | b.iter( || { 38 | (0..1200).fold(0, |cnt, year| if is_leap_year2(year) {cnt + 1} else {cnt}) 39 | }) 40 | } 41 | 42 | #[bench] 43 | fn leap3_bench(b: &mut Bencher) { 44 | b.iter( || { 45 | (0..1200).fold(0, |cnt, year| if is_leap_year3(year) {cnt + 1} else {cnt}) 46 | }) 47 | } 48 | 49 | #[bench] 50 | fn leap4_bench(b: &mut Bencher) { 51 | b.iter( || { 52 | (0..1200).fold(0, |cnt, year| if is_leap_year4(year) {cnt + 1} else {cnt}) 53 | }) 54 | } 55 | 56 | } 57 | --------------------------------------------------------------------------------