Compare commits
No commits in common. "6ff23340af5cde19619ba0483549eb98f11baed4" and "84e44930605ded759babd6e1ca9c7ca0e5e2e96e" have entirely different histories.
6ff23340af
...
84e4493060
|
@ -1,9 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "e_212"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Emelie Graven <emelie@graven.dev>"]
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
|
@ -1,130 +0,0 @@
|
||||||
/*! # Description
|
|
||||||
|
|
||||||
When we Swedes are young, we are taught a SUPER-SECRET language that only kids know, so we can hide secrets from our confused parents. This language is known as "Rövarspråket" (which means "Robber's language", more or less), and is surprisingly easy to become fluent in, at least when you're a kid. Recently, the cheeky residents of /r/Sweden decided to play a trick on the rest on reddit, and get a thread entirely in Rövarspråket to /r/all. [The results were hilarious](http://np.reddit.com/r/sweden/comments/301sqr/dodetot_%C3%A4ror_fof%C3%B6ror_lolitote/).
|
|
||||||
|
|
||||||
Rövarspråket is not very complicated: you take an ordinary word and replace the consonants with the consonant doubled and with an "o" in between. So the consonant "b" is replaced by "bob", "r" is replaced with "ror", "s" is replaced with "sos", and so on. Vowels are left intact. It's made for Swedish, but it works just as well in English.
|
|
||||||
|
|
||||||
Your task today is to write a program that can encode a string of text into Rövarspråket.
|
|
||||||
|
|
||||||
(note: this is a higly guarded Swedish state secret, so I trust that none of you will share this very privileged information with anyone! If you do, you will be extradited to Sweden and be forced to eat [surströmming](http://en.wikipedia.org/wiki/Surstr%C3%B6mming) as penance.)
|
|
||||||
|
|
||||||
(note 2: surströmming is actually not that bad, it's much tastier than its reputation would suggest! I'd go so far as to say that it's the tastiest half-rotten fish in the world!)
|
|
||||||
|
|
||||||
# Formal inputs & outputs
|
|
||||||
## Input
|
|
||||||
|
|
||||||
You will recieve one line of input, which is a text string that should be encoded into Rövarspråket.
|
|
||||||
|
|
||||||
## Output
|
|
||||||
|
|
||||||
The output will be the encoded string.
|
|
||||||
|
|
||||||
A few notes: your program should be able to handle case properly, which means that "Hello" should be encoded to "Hohelollolo", and *not* as "HoHelollolo" (note the second capital "H").
|
|
||||||
|
|
||||||
Also, since Rövarspråket is a Swedish invention, your program should follow Swedish rules regarding what is a vowel and what is a consonant. The Swedish alphabet is the same as the English alphabet except that there are three extra characters at the end (Å, Ä and Ö) which are all vowels. In addition, Y is always a vowel in Swedish, so the full list of vowels in Swedish is A, E, I, O, U, Y, Å, Ä and Ö. The rest are consonants.
|
|
||||||
|
|
||||||
Lastly, any character that is not a vowel or a consonant (i.e. things like punctuation) should be left intact in the output.
|
|
||||||
|
|
||||||
# Example inputs
|
|
||||||
## Input 1
|
|
||||||
|
|
||||||
Jag talar Rövarspråket!
|
|
||||||
|
|
||||||
## Output 1
|
|
||||||
|
|
||||||
Jojagog totalolaror Rorövovarorsospoproråkoketot!
|
|
||||||
|
|
||||||
## Input 2
|
|
||||||
|
|
||||||
I'm speaking Robber's language!
|
|
||||||
|
|
||||||
## Output 2
|
|
||||||
|
|
||||||
I'mom sospopeakokinongog Rorobobboberor'sos lolanongoguagoge!
|
|
||||||
|
|
||||||
# Challenge inputs
|
|
||||||
|
|
||||||
## Input 1
|
|
||||||
|
|
||||||
Tre Kronor är världens bästa ishockeylag.
|
|
||||||
|
|
||||||
## Input 2
|
|
||||||
|
|
||||||
Vår kung är coolare än er kung.
|
|
||||||
|
|
||||||
# Bonus
|
|
||||||
|
|
||||||
Make your program able to decode a Rövarspråket-encoded sentence as well as encode it.
|
|
||||||
|
|
||||||
# Notes
|
|
||||||
|
|
||||||
This excellent problem (which filled my crusty old Swedish heart with glee) was suggested by /u/pogotc. Thanks so much for the suggestion!
|
|
||||||
|
|
||||||
If you have an idea for a problem, head on over to /r/dailyprogrammer_ideas and post your suggestion! If it's good idea, we might use it, and you'll be as cool as /u/pogotc.
|
|
||||||
*/
|
|
||||||
#![allow(dead_code)]
|
|
||||||
#![allow(unused)]
|
|
||||||
const CONSONANTS: [char; 40] = [
|
|
||||||
'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'w', 'v', 'x',
|
|
||||||
'z', 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'W', 'V',
|
|
||||||
'X', 'Z',
|
|
||||||
];
|
|
||||||
fn main() {}
|
|
||||||
|
|
||||||
fn encode(input: String) -> String {
|
|
||||||
input.chars().fold(String::new(), |output, ch| {
|
|
||||||
if is_consonant(&ch) {
|
|
||||||
output + &ch.to_string() + "o" + &ch.to_string().to_ascii_lowercase()
|
|
||||||
} else {
|
|
||||||
output + &ch.to_string()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn decode(input: String) -> String {
|
|
||||||
let mut chars = input.chars();
|
|
||||||
let mut output = String::new();
|
|
||||||
while let Some(ch) = &chars.next() {
|
|
||||||
if is_consonant(ch) {
|
|
||||||
// Would use advance_by() here, but it requires nightly
|
|
||||||
chars.next();
|
|
||||||
chars.next();
|
|
||||||
}
|
|
||||||
output += &ch.to_string();
|
|
||||||
}
|
|
||||||
output
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_consonant(ch: &char) -> bool {
|
|
||||||
CONSONANTS.contains(ch)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn challenge_input_1() {
|
|
||||||
assert_eq!(encode(String::from("Tre Kronor är världens bästa ishockeylag.")), String::from("Totrore Kokrorononoror äror vovärorloldodenonsos bobäsostota isoshohocockokeylolagog."));
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn challenge_input_2() {
|
|
||||||
assert_eq!(
|
|
||||||
encode(String::from("Vår kung är coolare än er kung.")),
|
|
||||||
String::from("Vovåror kokunongog äror cocoololarore änon eror kokunongog.")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn bonus_challenge_input_1() {
|
|
||||||
assert_eq!(decode(String::from("Totrore Kokrorononoror äror vovärorloldodenonsos bobäsostota isoshohocockokeylolagog.")), (String::from("Tre Kronor är världens bästa ishockeylag.")));
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn bonus_challenge_input_2() {
|
|
||||||
assert_eq!(
|
|
||||||
decode(String::from(
|
|
||||||
"Vovåror kokunongog äror cocoololarore änon eror kokunongog."
|
|
||||||
)),
|
|
||||||
String::from("Vår kung är coolare än er kung.")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "e_258"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Emelie Graven <emelie@graven.dev>"]
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
|
@ -1,106 +0,0 @@
|
||||||
/*!]]
|
|
||||||
# Description
|
|
||||||
|
|
||||||
A [network socket](https://en.wikipedia.org/wiki/Network_socket) is an endpoint of a connection across a computer network.
|
|
||||||
Today, most communication between computers is based on the Internet Protocol; therefore most network sockets are Internet
|
|
||||||
sockets. [Internet Relay Chat](https://simple.wikipedia.org/wiki/Internet_Relay_Chat) (IRC) is a chat system on the Internet.
|
|
||||||
It allows people from around the world to have conversations together, but it can also be used for two people to chat
|
|
||||||
privately.
|
|
||||||
|
|
||||||
[Freenode](https://en.wikipedia.org/wiki/Freenode) is an IRC network used to discuss peer-directed projects. Their servers
|
|
||||||
are all accessible from the domain names chat.freenode.net and irc.freenode.net. In 2010, it became the largest free and
|
|
||||||
open source software-focused IRC network. In 2013 it became the largest IRC network, encompassing more than 90,000 users
|
|
||||||
and 40,000 channels and gaining almost 5,000 new users per year. We have a channel on freenode ourselves for all things
|
|
||||||
/r/DailyProgrammer on freenode, which is
|
|
||||||
[#reddit-dailyprogrammer](https://www.reddit.com/r/dailyprogrammer/comments/2dtqr7/psa_rdailyprogrammer_irc_channel/).
|
|
||||||
|
|
||||||
Your challenge today will be to communicate with the freenode IRC server. This will consist of opening a TCP socket to
|
|
||||||
freenode and sending two protocol messages to initiate the connection. The original
|
|
||||||
[IRC RFC](https://tools.ietf.org/html/rfc1459#section-4.1) defines a message as a line of text up to 512 bytes starting
|
|
||||||
with a message code, followed by one or more space separated parameters, and ending with a CRLF (`\r\n`). The last
|
|
||||||
paramater can be prefixed by a colon to mark it as a parameter that can contain spaces, which will take up the rest of the
|
|
||||||
line. An example of a colon-prefixed parameter would be the contents of a chat message, as that is something that contains spaces.
|
|
||||||
|
|
||||||
The first of the two initiation messages (`NICK`) defines what name people will see when you send a chat message.
|
|
||||||
It will have to be unique, and you will not be able to connect if you specify a name which is currently in use or reserved.
|
|
||||||
It has a single parameter `<nickname>` and will be sent in the following form:
|
|
||||||
|
|
||||||
NICK <nickname>
|
|
||||||
|
|
||||||
The second of the two initiation messages (`USER`) defines your username, user mode, server name, and real name. The username must also be unique and is usually set to be the same as the nickname. Originally, hostname was sent instead of user mode, but this was changed in a later version of the IRC protocol. For our purposes, standard mode `0` will work fine. As for server name, this will be ignored by the server and is conventionally set as an asterisk (`*`). The real name parameter can be whatever you want, though it is usually set to be the same value as the nickname. It does not have to be unique and may contain spaces. As such, it must be prefixed by a colon. The `USER` message will be sent in the following form:
|
|
||||||
|
|
||||||
USER <username> 0 * :<realname>
|
|
||||||
|
|
||||||
# Input Description
|
|
||||||
|
|
||||||
You will give your program a list of lines specifying server, port, nickname, username, and realname. The first line will contain the server and the port, separated by a colon. The second through fourth lines will contain nick information.
|
|
||||||
|
|
||||||
chat.freenode.net:6667
|
|
||||||
Nickname
|
|
||||||
Username
|
|
||||||
Real Name
|
|
||||||
|
|
||||||
# Output Description
|
|
||||||
|
|
||||||
Your program will open a socket to the specified server and port, and send the two required messages. For example:
|
|
||||||
|
|
||||||
NICK Nickname
|
|
||||||
USER Username 0 * :Real Name
|
|
||||||
|
|
||||||
Afterwards, it will begin to receive messages back from the server. Many messages sent from the server will be prefixed to indicate the origin of the message. This will be in the format `:server` or `:nick[!user][@host]`, followed by a space. The exact contents of these initial messages are usually not important, but you must output them in some manner. The first few messages received on a successful connection will look something like this:
|
|
||||||
|
|
||||||
:wolfe.freenode.net NOTICE * :*** Looking up your hostname...
|
|
||||||
:wolfe.freenode.net NOTICE * :*** Checking Ident
|
|
||||||
:wolfe.freenode.net NOTICE * :*** Found your hostname
|
|
||||||
:wolfe.freenode.net NOTICE * :*** No Ident response
|
|
||||||
:wolfe.freenode.net 001 Nickname :Welcome to the freenode Internet Relay Chat Network Nickname
|
|
||||||
|
|
||||||
# Challenge Input
|
|
||||||
|
|
||||||
The server will occasionally send `PING` messages to you. These have a single parameter beginning with a colon. The exact contents of that parameter will vary between servers, but is usually a unique string used to verify that your client is still connected and responsive. On freenode, it appears to be the name of the specific server you are connected to. For example:
|
|
||||||
|
|
||||||
PING :wolfe.freenode.net
|
|
||||||
|
|
||||||
# Challenge Output
|
|
||||||
|
|
||||||
In response, you must send a `PONG` message with the parameter being the same unique string from the `PING`. You must continue to do this for the entire time your program is running, or it will get automatically disconnected from the server. For example:
|
|
||||||
|
|
||||||
PONG :wolfe.freenode.net
|
|
||||||
|
|
||||||
# Notes
|
|
||||||
|
|
||||||
You can see the full original IRC specification at https://tools.ietf.org/html/rfc1459. Sections 2.3 and 4.1 are of particular note, as they describe the message format and the initial connection. See also, http://ircdocs.horse/specs/.
|
|
||||||
|
|
||||||
[A Regular Expression For IRC Messages](https://mybuddymichael.com/writings/a-regular-expression-for-irc-messages.html)
|
|
||||||
|
|
||||||
Happy Pi Day!
|
|
||||||
*/
|
|
||||||
|
|
||||||
use std::error::Error;
|
|
||||||
use std::io::{BufRead, BufReader, Write};
|
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
const SERVER: &str = "irc.libera.chat:6667";
|
|
||||||
const NICK: &str = "dailyprog_2851";
|
|
||||||
const USER_NAME: &str = "dailyprog_2851";
|
|
||||||
const REAL_NAME: &str = "dailyprog_2851";
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
|
||||||
let mut stream = TcpStream::connect(SERVER)?;
|
|
||||||
stream.write_all((String::from("NICK ") + NICK + "\r\n").as_bytes())?;
|
|
||||||
stream.write_all(
|
|
||||||
(String::from("USER ") + USER_NAME + " 0 * :" + REAL_NAME + "\r\n").as_bytes(),
|
|
||||||
)?;
|
|
||||||
let mut reader = BufReader::new(stream);
|
|
||||||
let mut line = String::new();
|
|
||||||
loop {
|
|
||||||
reader.read_line(&mut line)?;
|
|
||||||
println!("{}", &line);
|
|
||||||
if line.starts_with("PING") {
|
|
||||||
reader
|
|
||||||
.get_mut()
|
|
||||||
.write_all(line.replace("PING", "PONG").as_bytes())?;
|
|
||||||
}
|
|
||||||
line.clear();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -116,7 +116,7 @@ impl FromStr for Dice {
|
||||||
fn from_str(s: &str) -> Result<Dice, Self::Err> {
|
fn from_str(s: &str) -> Result<Dice, Self::Err> {
|
||||||
// Split string at "d" delimeter, parse elements into Dice struct containing u32s
|
// Split string at "d" delimeter, parse elements into Dice struct containing u32s
|
||||||
let dice = s
|
let dice = s
|
||||||
.split('d')
|
.split("d")
|
||||||
.map(|x| x.parse::<u32>())
|
.map(|x| x.parse::<u32>())
|
||||||
.collect::<Result<Vec<u32>, ParseIntError>>();
|
.collect::<Result<Vec<u32>, ParseIntError>>();
|
||||||
let dice = match dice {
|
let dice = match dice {
|
||||||
|
@ -149,7 +149,7 @@ fn main() {
|
||||||
/// Main exercise loop
|
/// Main exercise loop
|
||||||
fn e_364() {
|
fn e_364() {
|
||||||
let input = fs::read_to_string("input.txt").unwrap();
|
let input = fs::read_to_string("input.txt").unwrap();
|
||||||
let dice: Result<Vec<Dice>, DiceError> = input.split('\n').map(|x| x.parse()).collect();
|
let dice: Result<Vec<Dice>, DiceError> = input.split("\n").map(|x| x.parse()).collect();
|
||||||
match dice {
|
match dice {
|
||||||
Ok(d) => d.iter().for_each(|x| println!("{}", x.roll_dice())),
|
Ok(d) => d.iter().for_each(|x| println!("{}", x.roll_dice())),
|
||||||
Err(DiceError::ParseInt(e)) => eprintln!("Could not parse integer: {:?}", e),
|
Err(DiceError::ParseInt(e)) => eprintln!("Could not parse integer: {:?}", e),
|
||||||
|
@ -169,7 +169,7 @@ mod tests {
|
||||||
Dice { count: 16, die: 2 }
|
Dice { count: 16, die: 2 }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
#[test]
|
|
||||||
fn test_error_handling() {
|
fn test_error_handling() {
|
||||||
assert!(matches!("3dx".parse::<Dice>(), Err(DiceError::ParseInt(_))));
|
assert!(matches!("3dx".parse::<Dice>(), Err(DiceError::ParseInt(_))));
|
||||||
assert_eq!("3d3d3".parse::<Dice>(), Err(DiceError::ParseFields));
|
assert_eq!("3d3d3".parse::<Dice>(), Err(DiceError::ParseFields));
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "e_372"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Emelie Graven <emelie@graven.dev>"]
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
|
@ -1,48 +0,0 @@
|
||||||
/*!
|
|
||||||
# Description
|
|
||||||
Given a string containing only the characters `x` and `y`, find whether there are the same number of `x`s and `y`s.
|
|
||||||
|
|
||||||
balanced("xxxyyy") => true
|
|
||||||
balanced("yyyxxx") => true
|
|
||||||
balanced("xxxyyyy") => false
|
|
||||||
balanced("yyxyxxyxxyyyyxxxyxyx") => true
|
|
||||||
balanced("xyxxxxyyyxyxxyxxyy") => false
|
|
||||||
balanced("") => true
|
|
||||||
balanced("x") => false
|
|
||||||
|
|
||||||
## Optional bonus
|
|
||||||
|
|
||||||
Given a string containing only lowercase letters, find whether every letter that appears in the string appears the same number of times. Don't forget to handle the empty string (`""`) correctly!
|
|
||||||
|
|
||||||
balanced_bonus("xxxyyyzzz") => true
|
|
||||||
balanced_bonus("abccbaabccba") => true
|
|
||||||
balanced_bonus("xxxyyyzzzz") => false
|
|
||||||
balanced_bonus("abcdefghijklmnopqrstuvwxyz") => true
|
|
||||||
balanced_bonus("pqq") => false
|
|
||||||
balanced_bonus("fdedfdeffeddefeeeefddf") => false
|
|
||||||
balanced_bonus("www") => true
|
|
||||||
balanced_bonus("x") => true
|
|
||||||
balanced_bonus("") => true
|
|
||||||
|
|
||||||
Note that `balanced_bonus` behaves differently than `balanced` for a few inputs, e.g. `"x"`.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
println!("{}", balanced(String::from("jbsssssh")));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn balanced(input: String) -> bool {
|
|
||||||
let count: HashMap<char, i32> = input.chars().fold(HashMap::new(), |mut map, ch| {
|
|
||||||
map.entry(ch).and_modify(|n| *n += 1).or_insert(1);
|
|
||||||
map
|
|
||||||
});
|
|
||||||
println!("{:?}", count);
|
|
||||||
let mut values = count.values();
|
|
||||||
if let Some(first) = values.next() {
|
|
||||||
values.all(|x| x == first)
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "e_378"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Emelie Graven <emelie@graven.dev>"]
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
|
@ -1,190 +0,0 @@
|
||||||
/*!
|
|
||||||
It was a dark and stormy night. Detective Havel and Detective Hakimi arrived at the scene of the crime.
|
|
||||||
|
|
||||||
Other than the detectives, there were 10 people present. They asked the first person, "out of the 9 other people here, how many had you already met before tonight?" The person answered "5". They asked the same question of the second person, who answered "3". And so on. The 10 answers they got from the 10 people were:
|
|
||||||
|
|
||||||
5 3 0 2 6 2 0 7 2 5
|
|
||||||
|
|
||||||
The detectives looked at the answers carefully and deduced that there was an inconsistency, and that somebody must be lying. (For the purpose of this challenge, assume that nobody makes mistakes or forgets, and if X has met Y, that means Y has also met X.)
|
|
||||||
|
|
||||||
Your challenge for today is, given a sequence of answers to the question "how many of the others had you met before tonight?", apply the Havel-Hakimi algorithm to determine whether or not it's possible that everyone was telling the truth.
|
|
||||||
|
|
||||||
If you're feeling up to it, skip ahead to the Challenge section below. Otherwise, try as many of the optional warmup questions as you want first, before attempting the full challenge.
|
|
||||||
|
|
||||||
# Optional Warmup 1: eliminating 0's.
|
|
||||||
|
|
||||||
Given a sequence of answers, return the same set of answers with all the 0's removed.
|
|
||||||
|
|
||||||
warmup1([5, 3, 0, 2, 6, 2, 0, 7, 2, 5]) => [5, 3, 2, 6, 2, 7, 2, 5]
|
|
||||||
warmup1([4, 0, 0, 1, 3]) => [4, 1, 3]
|
|
||||||
warmup1([1, 2, 3]) => [1, 2, 3]
|
|
||||||
warmup1([0, 0, 0]) => []
|
|
||||||
warmup1([]) => []
|
|
||||||
|
|
||||||
If you want to reorder the sequence as you do this, that's fine. For instance, given `[4, 0, 0, 1, 3]`, then you may return `[4, 1, 3]` or `[1, 3, 4]` or `[4, 3, 1]` or any other ordering of these numbers.
|
|
||||||
|
|
||||||
# Optional Warmup 2: descending sort
|
|
||||||
|
|
||||||
Given a sequence of answers, return the sequence sorted in descending order, so that the first number is the largest and the last number is the smallest.
|
|
||||||
|
|
||||||
warmup2([5, 1, 3, 4, 2]) => [5, 4, 3, 2, 1]
|
|
||||||
warmup2([0, 0, 0, 4, 0]) => [4, 0, 0, 0, 0]
|
|
||||||
warmup2([1]) => [1]
|
|
||||||
warmup2([]) => []
|
|
||||||
|
|
||||||
# Optional Warmup 3: length check
|
|
||||||
|
|
||||||
Given a number `N` and a sequence of answers, return true if `N` is greater than the number of answers (i.e. the length of the sequence), and false if `N` is less than or equal to the number of answers. For instance, given 7 and [6, 5, 5, 3, 2, 2, 2], you would return false, because 7 is less than or equal to 7.
|
|
||||||
|
|
||||||
warmup3(7, [6, 5, 5, 3, 2, 2, 2]) => false
|
|
||||||
warmup3(5, [5, 5, 5, 5, 5]) => false
|
|
||||||
warmup3(5, [5, 5, 5, 5]) => true
|
|
||||||
warmup3(3, [1, 1]) => true
|
|
||||||
warmup3(1, []) => true
|
|
||||||
warmup3(0, []) => false
|
|
||||||
|
|
||||||
# Optional Warmup 4: front elimination
|
|
||||||
|
|
||||||
Given a number `N` and a sequence in descending order, subtract 1 from each of the first `N` answers in the sequence, and return the result. For instance, given `N = 4` and the sequence `[5, 4, 3, 2, 1]`, you would subtract 1 from each of the first 4 answers (5, 4, 3, and 2) to get 4, 3, 2, and 1. The rest of the sequence (1) would not be affected:
|
|
||||||
|
|
||||||
warmup4(4, [5, 4, 3, 2, 1]) => [4, 3, 2, 1, 1]
|
|
||||||
warmup4(11, [14, 13, 13, 13, 12, 10, 8, 8, 7, 7, 6, 6, 4, 4, 2]) => [13, 12, 12, 12, 11, 9, 7, 7, 6, 6, 5, 6, 4, 4, 2]
|
|
||||||
warmup4(1, [10, 10, 10]) => [9, 10, 10]
|
|
||||||
warmup4(3, [10, 10, 10]) => [9, 9, 9]
|
|
||||||
warmup4(1, [1]) => [0]
|
|
||||||
|
|
||||||
You may assume that `N` is greater than 0, and no greater than the length of the sequence. Like in warmup 1, it's okay if you want to reorder the answers in your result.
|
|
||||||
|
|
||||||
# Challenge: the Havel-Hakimi algorithm
|
|
||||||
|
|
||||||
Perform the Havel-Hakimi algorithm on a given sequence of answers. This algorithm will return true if the answers are consistent (i.e. it's possible that everyone is telling the truth) and false if the answers are inconsistent (i.e. someone must be lying):
|
|
||||||
|
|
||||||
1. Remove all 0's from the sequence (i.e. `warmup1`).
|
|
||||||
2. If the sequence is now empty (no elements left), stop and return true.
|
|
||||||
3. Sort the sequence in descending order (i.e. `warmup2`).
|
|
||||||
4. Remove the first answer (which is also the largest answer, or tied for the largest) from the sequence and call it `N`. The sequence is now 1 shorter than it was after the previous step.
|
|
||||||
5. If `N` is greater than the length of this new sequence (i.e. `warmup3`), stop and return false.
|
|
||||||
6. Subtract 1 from each of the first `N` elements of the new sequence (i.e. `warmup4`).
|
|
||||||
7. Continue from step 1 using the sequence from the previous step.
|
|
||||||
|
|
||||||
Eventually you'll either return true in step 2, or false in step 5.
|
|
||||||
|
|
||||||
You don't have to follow these steps exactly: as long as you return the right answer, that's fine. Also, if you answered the warmup questions, you may use your warmup solutions to build your challenge solution, but you don't have to.
|
|
||||||
|
|
||||||
hh([5, 3, 0, 2, 6, 2, 0, 7, 2, 5]) => false
|
|
||||||
hh([4, 2, 0, 1, 5, 0]) => false
|
|
||||||
hh([3, 1, 2, 3, 1, 0]) => true
|
|
||||||
hh([16, 9, 9, 15, 9, 7, 9, 11, 17, 11, 4, 9, 12, 14, 14, 12, 17, 0, 3, 16]) => true
|
|
||||||
hh([14, 10, 17, 13, 4, 8, 6, 7, 13, 13, 17, 18, 8, 17, 2, 14, 6, 4, 7, 12]) => true
|
|
||||||
hh([15, 18, 6, 13, 12, 4, 4, 14, 1, 6, 18, 2, 6, 16, 0, 9, 10, 7, 12, 3]) => false
|
|
||||||
hh([6, 0, 10, 10, 10, 5, 8, 3, 0, 14, 16, 2, 13, 1, 2, 13, 6, 15, 5, 1]) => false
|
|
||||||
hh([2, 2, 0]) => false
|
|
||||||
hh([3, 2, 1]) => false
|
|
||||||
hh([1, 1]) => true
|
|
||||||
hh([1]) => false
|
|
||||||
hh([]) => true
|
|
||||||
|
|
||||||
# Detailed example
|
|
||||||
|
|
||||||
Here's the first pass through the algorithm using the original example:
|
|
||||||
|
|
||||||
* `[5, 3, 0, 2, 6, 2, 0, 7, 2, 5]` - Starting sequence
|
|
||||||
* `[5, 3, 2, 6, 2, 7, 2, 5]` - After step 1, removing 0's.
|
|
||||||
* Step 2: This sequence is not empty, so go on to step 3.
|
|
||||||
* `[7, 6, 5, 5, 3, 2, 2, 2]` - After step 3, sorting in descending order.
|
|
||||||
* `[6, 5, 5, 3, 2, 2, 2]` - After step 4, removing the first answer `N = 7`.
|
|
||||||
* Step 5: N (7) is less than or equal to the number of answers remaining in the sequence (7), so go on to step 6.
|
|
||||||
* `[5, 4, 4, 2, 1, 1, 1]` - After step 6, subtracting 1 from each of the first 7 answers (which is all of them in this case).
|
|
||||||
|
|
||||||
At this point you would start over at step 1 with the sequence `[5, 4, 4, 2, 1, 1, 1]`. After your second pass through the algorithm, your sequence will be `[3, 3, 1, 0, 0, 1]`, so start back at step 1 with this sequence. After your third pass you'll have `[2, 0, 0]`. On your fourth pass, you'll stop at step 5, because you'll have `N = 2` and an empty sequence (`[]`), and 2 > 0, so you will return false.
|
|
||||||
*/
|
|
||||||
#![allow(dead_code)]
|
|
||||||
#![allow(unused)]
|
|
||||||
|
|
||||||
fn main() {}
|
|
||||||
|
|
||||||
fn warmup_1(set: Vec<i32>) -> Vec<i32> {
|
|
||||||
set.into_iter().filter(|x| *x != 0).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn warmup_2(mut set: Vec<i32>) -> Vec<i32> {
|
|
||||||
set.sort_by(|a, b| b.cmp(a));
|
|
||||||
set
|
|
||||||
}
|
|
||||||
|
|
||||||
fn warmup_3(i: i32, set: Vec<i32>) -> bool {
|
|
||||||
(i as usize) > set.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn warmup_4(i: i32, mut set: Vec<i32>) -> Vec<i32> {
|
|
||||||
set.iter_mut().take(i as usize).for_each(|x| *x -= 1);
|
|
||||||
set
|
|
||||||
}
|
|
||||||
|
|
||||||
fn e_378(mut set: Vec<i32>) -> bool {
|
|
||||||
loop {
|
|
||||||
set = warmup_1(set);
|
|
||||||
if set.is_empty() {
|
|
||||||
break true;
|
|
||||||
}
|
|
||||||
set = warmup_2(set);
|
|
||||||
let largest = set.remove(0);
|
|
||||||
if warmup_3(largest, set.clone()) {
|
|
||||||
break false;
|
|
||||||
}
|
|
||||||
set = warmup_4(largest, set);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn does_warmup_1_remove_zero() {
|
|
||||||
assert_eq!(warmup_1(vec![12, 0, 5, 7, 0, 2]), vec![12, 5, 7, 2]);
|
|
||||||
assert_ne!(warmup_1(vec![0, 1, 2, 0, 17]), vec![0, 1, 2, 0, 17]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn does_warmup_2_sort() {
|
|
||||||
assert_eq!(warmup_2(vec![16, 2, 9, 1, 0, -5]), vec![16, 9, 2, 1, 0, -5]);
|
|
||||||
assert_ne!(warmup_2(vec![1, 2, 3, 4, 5]), vec![1, 2, 3, 4, 5]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn is_warmup_3() {
|
|
||||||
assert!(warmup_3(8, vec![5, 3, 1, 7, 8, 4, 2]));
|
|
||||||
assert!(!warmup_3(3, vec![5, 2, 3]));
|
|
||||||
assert!(!warmup_3(3, vec![6, 5, 1, 3, 7]));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn t_warmup_4() {
|
|
||||||
assert_eq!(warmup_4(2, vec![5, 4, 3, 2, 1]), vec![4, 3, 3, 2, 1]);
|
|
||||||
assert_ne!(warmup_4(4, vec![5, 4, 3, 2, 1]), vec![5, 4, 3, 2, 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn does_e_378_havel_hakimi() {
|
|
||||||
assert!(!e_378(vec![5, 3, 0, 2, 6, 2, 0, 7, 2, 5]));
|
|
||||||
assert!(!e_378(vec![4, 2, 0, 1, 5, 0]));
|
|
||||||
assert!(e_378(vec![3, 1, 2, 3, 1, 0]));
|
|
||||||
assert!(e_378(vec![
|
|
||||||
16, 9, 9, 15, 9, 7, 9, 11, 17, 11, 4, 9, 12, 14, 14, 12, 17, 0, 3, 16
|
|
||||||
]));
|
|
||||||
assert!(e_378(vec![
|
|
||||||
14, 10, 17, 13, 4, 8, 6, 7, 13, 13, 17, 18, 8, 17, 2, 14, 6, 4, 7, 12
|
|
||||||
]));
|
|
||||||
assert!(!e_378(vec![
|
|
||||||
15, 18, 6, 13, 12, 4, 4, 14, 1, 6, 18, 2, 6, 16, 0, 9, 10, 7, 12, 3
|
|
||||||
]));
|
|
||||||
assert!(!e_378(vec![
|
|
||||||
6, 0, 10, 10, 10, 5, 8, 3, 0, 14, 16, 2, 13, 1, 2, 13, 6, 15, 5, 1
|
|
||||||
]));
|
|
||||||
assert!(!e_378(vec![2, 2, 0]));
|
|
||||||
assert!(!e_378(vec![3, 2, 1]));
|
|
||||||
assert!(e_378(vec![1, 1]));
|
|
||||||
assert!(!e_378(vec![1]));
|
|
||||||
assert!(e_378(vec![]));
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue