initial commit
This commit is contained in:
commit
94c5952a0c
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name="pvn"
|
||||
version="0.0.1"
|
||||
authors=["Adrian Malacoda <adrian.malacoda@monarch-pass.net>"]
|
||||
|
||||
[dependencies]
|
||||
log = "0.3.6"
|
||||
env_logger = "0.4.0"
|
||||
lru-cache = "0.1.0"
|
||||
select = "0.3.0"
|
||||
hyper = "0.10.4"
|
20
README.md
Normal file
20
README.md
Normal file
@ -0,0 +1,20 @@
|
||||
# Pirate vs Ninja Client Library
|
||||
This is a client for [Pirate vs Ninja](http://www.majcher.com/pvn/) written in Rust. It can be used standalone or as a library.
|
||||
|
||||
## Usage
|
||||
### Command Line
|
||||
`cargo run <pirate_name> <ninja_name>`
|
||||
|
||||
#### Example
|
||||
malacoda@kraken:~/Projects/pvn$ cargo run Pie "Windows 98"
|
||||
Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
|
||||
Running `target/debug/pvn Pie Windows\ 98`
|
||||
Pirate { name: "Captain Pie", swashbuckling: 19, drunkenness: 9, booty: 15, weapons: ["Cannon", "Broken Bottle", "Belaying Pin"] } => 46
|
||||
Ninja { name: "Ninja Master Windows 98", sneakiness: 9, pajamas: 15, pointy_things: 19, weapons: ["Poison Dart", "Thousand Blossom Finger", "Death Touch"] } => 46
|
||||
It's a tie!
|
||||
|
||||
### Library
|
||||
The library provides the `Pirates` and `Ninjas` types, which each keep a cache of `Pirate` and `Ninja` objects. Given a `Pirates` object, you can call `pirates.get(&str)` to obtain a reference to the `Pirate` with the given name. Or, you can create a `Pirate` or `Ninja` by passing in HTML to `Pirate::from_html(&str)`.
|
||||
|
||||
#### Example
|
||||
See `src/main.rs`
|
36
src/lib.rs
Normal file
36
src/lib.rs
Normal file
@ -0,0 +1,36 @@
|
||||
extern crate lru_cache;
|
||||
extern crate hyper;
|
||||
extern crate select;
|
||||
|
||||
pub mod pirates;
|
||||
pub mod ninjas;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Http(hyper::error::Error),
|
||||
Io(std::io::Error)
|
||||
}
|
||||
|
||||
impl From<hyper::error::Error> for Error {
|
||||
fn from (err: hyper::error::Error) -> Error {
|
||||
Error::Http(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for Error {
|
||||
fn from (err: std::io::Error) -> Error {
|
||||
Error::Io(err)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Fighter {
|
||||
fn power (&self) -> u8;
|
||||
}
|
||||
|
||||
pub fn parse_weapons (weapons: &str) -> Vec<String> {
|
||||
if weapons == "None" {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
weapons.split(", ").into_iter().map(String::from).collect()
|
||||
}
|
27
src/main.rs
Normal file
27
src/main.rs
Normal file
@ -0,0 +1,27 @@
|
||||
extern crate pvn;
|
||||
|
||||
use pvn::Fighter;
|
||||
use pvn::pirates::Pirates;
|
||||
use pvn::ninjas::Ninjas;
|
||||
use std::env;
|
||||
|
||||
fn main () {
|
||||
let mut pirates = Pirates::new();
|
||||
let mut ninjas = Ninjas::new();
|
||||
|
||||
let pirate_name = &env::args().nth(1).expect("Expected pirate name as first argument")[..];
|
||||
let pirate = pirates.get(pirate_name).unwrap();
|
||||
println!("{:?} => {}", pirate, pirate.power());
|
||||
|
||||
let ninja_name = &env::args().nth(2).expect("Expected ninja name as second argument")[..];
|
||||
let ninja = ninjas.get(ninja_name).unwrap();
|
||||
println!("{:?} => {}", ninja, ninja.power());
|
||||
|
||||
if ninja.power() == pirate.power() {
|
||||
println!("It's a tie!", )
|
||||
} else if ninja.power() > pirate.power() {
|
||||
println!("Winner: {}!", ninja.name);
|
||||
} else {
|
||||
println!("Winner: {}!", pirate.name);
|
||||
}
|
||||
}
|
84
src/ninjas/mod.rs
Normal file
84
src/ninjas/mod.rs
Normal file
@ -0,0 +1,84 @@
|
||||
use lru_cache::LruCache;
|
||||
use hyper::client::Client;
|
||||
use select::document::Document;
|
||||
use select::predicate::Class;
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
use {Error, Fighter, parse_weapons};
|
||||
|
||||
pub struct Ninjas {
|
||||
cache: LruCache<String, Ninja>,
|
||||
client: Client
|
||||
}
|
||||
|
||||
impl Ninjas {
|
||||
pub fn new () -> Ninjas {
|
||||
Ninjas::with_cache_size(30)
|
||||
}
|
||||
|
||||
pub fn with_cache_size (cache_size: usize) -> Ninjas {
|
||||
Ninjas {
|
||||
cache: LruCache::new(cache_size),
|
||||
client: Client::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get (&mut self, name: &str) -> Result<&Ninja, Error> {
|
||||
if self.cache.contains_key(name) {
|
||||
return Result::Ok(self.cache.get_mut(name).unwrap())
|
||||
}
|
||||
|
||||
let ninja = self.get_by_name(name)?;
|
||||
self.cache.insert(String::from(name), ninja);
|
||||
Result::Ok(self.cache.get_mut(name).unwrap())
|
||||
}
|
||||
|
||||
fn get_by_name (&self, name: &str) -> Result<Ninja, Error> {
|
||||
let mut contents = String::new();
|
||||
self.client.get(&format!("http://www.majcher.com/pvn/pvn.cgi?a=n&n1={}", name)).send()?.read_to_string(&mut contents)?;
|
||||
Ninja::from_html(&contents[..])
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Ninja {
|
||||
pub name: String,
|
||||
pub sneakiness: u8,
|
||||
pub pajamas: u8,
|
||||
pub pointy_things: u8,
|
||||
pub weapons: Vec<String>
|
||||
}
|
||||
|
||||
impl Ninja {
|
||||
pub fn from_html (contents: &str) -> Result<Ninja, Error> {
|
||||
let document = Document::from(contents);
|
||||
let mut ninja = Ninja {
|
||||
name: String::from(document.find(Class("ninja-name")).first().unwrap().text()),
|
||||
sneakiness: 0,
|
||||
pajamas: 0,
|
||||
pointy_things: 0,
|
||||
weapons: vec![]
|
||||
};
|
||||
|
||||
for node in document.find(Class("ninja-skill")).iter() {
|
||||
let skill = node.text();
|
||||
let score = node.parent().unwrap().find(Class("ninja-score")).first().unwrap().text();
|
||||
match &skill[..] {
|
||||
"Sneakiness:" => { ninja.sneakiness = score.parse::<u8>().unwrap() }
|
||||
"Pajamas:" => { ninja.pajamas = score.parse::<u8>().unwrap() },
|
||||
"Pointy Things:" => { ninja.pointy_things = score.parse::<u8>().unwrap() },
|
||||
"Weapons:" => { ninja.weapons = parse_weapons(&score[..]) }
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
|
||||
Result::Ok(ninja)
|
||||
}
|
||||
}
|
||||
|
||||
impl Fighter for Ninja {
|
||||
fn power (&self) -> u8 {
|
||||
self.sneakiness + self.pajamas + self.pointy_things + self.weapons.len() as u8
|
||||
}
|
||||
}
|
84
src/pirates/mod.rs
Normal file
84
src/pirates/mod.rs
Normal file
@ -0,0 +1,84 @@
|
||||
use lru_cache::LruCache;
|
||||
use hyper::client::Client;
|
||||
use select::document::Document;
|
||||
use select::predicate::Class;
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
use {Error, Fighter, parse_weapons};
|
||||
|
||||
pub struct Pirates {
|
||||
cache: LruCache<String, Pirate>,
|
||||
client: Client
|
||||
}
|
||||
|
||||
impl Pirates {
|
||||
pub fn new () -> Pirates {
|
||||
Pirates::with_cache_size(30)
|
||||
}
|
||||
|
||||
pub fn with_cache_size (cache_size: usize) -> Pirates {
|
||||
Pirates {
|
||||
cache: LruCache::new(cache_size),
|
||||
client: Client::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get (&mut self, name: &str) -> Result<&Pirate, Error> {
|
||||
if self.cache.contains_key(name) {
|
||||
return Result::Ok(self.cache.get_mut(name).unwrap())
|
||||
}
|
||||
|
||||
let pirate = self.get_by_name(name)?;
|
||||
self.cache.insert(String::from(name), pirate);
|
||||
Result::Ok(self.cache.get_mut(name).unwrap())
|
||||
}
|
||||
|
||||
fn get_by_name (&self, name: &str) -> Result<Pirate, Error> {
|
||||
let mut contents = String::new();
|
||||
self.client.get(&format!("http://www.majcher.com/pvn/pvn.cgi?a=p&n1={}", name)).send()?.read_to_string(&mut contents)?;
|
||||
Pirate::from_html(&contents[..])
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Pirate {
|
||||
pub name: String,
|
||||
pub swashbuckling: u8,
|
||||
pub drunkenness: u8,
|
||||
pub booty: u8,
|
||||
pub weapons: Vec<String>
|
||||
}
|
||||
|
||||
impl Pirate {
|
||||
pub fn from_html (contents: &str) -> Result<Pirate, Error> {
|
||||
let document = Document::from(contents);
|
||||
let mut pirate = Pirate {
|
||||
name: String::from(document.find(Class("pirate-name")).first().unwrap().text()),
|
||||
swashbuckling: 0,
|
||||
drunkenness: 0,
|
||||
booty: 0,
|
||||
weapons: vec![]
|
||||
};
|
||||
|
||||
for node in document.find(Class("pirate-skill")).iter() {
|
||||
let skill = node.text();
|
||||
let score = node.parent().unwrap().find(Class("pirate-score")).first().unwrap().text();
|
||||
match &skill[..] {
|
||||
"Swashbuckling:" => { pirate.swashbuckling = score.parse::<u8>().unwrap() }
|
||||
"Drunkenness:" => { pirate.drunkenness = score.parse::<u8>().unwrap() },
|
||||
"Booty:" => { pirate.booty = score.parse::<u8>().unwrap() },
|
||||
"Weapons:" => { pirate.weapons = parse_weapons(&score[..]) }
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
|
||||
Result::Ok(pirate)
|
||||
}
|
||||
}
|
||||
|
||||
impl Fighter for Pirate {
|
||||
fn power (&self) -> u8 {
|
||||
self.swashbuckling + self.drunkenness + self.booty + self.weapons.len() as u8
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user