Compare commits
2 Commits
9f1eac75a0
...
906aaa1e59
| Author | SHA1 | Date | |
|---|---|---|---|
| 906aaa1e59 | |||
| 6b4105ecd9 |
@@ -1,16 +1,16 @@
|
||||
use thiserror::Error;
|
||||
use rand::rng;
|
||||
use rand::seq::SliceRandom;
|
||||
use std::fmt;
|
||||
use strum::IntoEnumIterator;
|
||||
use strum_macros::EnumIter;
|
||||
use std::fmt;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::rng;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(PartialEq, Debug, EnumIter, Copy, Clone)]
|
||||
pub enum Suit {
|
||||
Heart,
|
||||
Diamond,
|
||||
Club,
|
||||
Spade
|
||||
Spade,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
@@ -53,7 +53,7 @@ pub enum Value {
|
||||
Ten,
|
||||
Jack,
|
||||
Queen,
|
||||
King
|
||||
King,
|
||||
}
|
||||
|
||||
impl Value {
|
||||
@@ -97,7 +97,6 @@ impl fmt::Display for Value {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||
pub struct Card {
|
||||
pub suit: Suit,
|
||||
@@ -105,7 +104,6 @@ pub struct Card {
|
||||
pub visible: bool,
|
||||
}
|
||||
|
||||
|
||||
impl fmt::Display for Card {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}{}", self.value, self.suit)
|
||||
@@ -140,8 +138,13 @@ impl Card {
|
||||
}
|
||||
|
||||
// Needs to be adjacent
|
||||
if self.value == Value::King || self.value.indexed_values() + 1 != top.value.indexed_values() {
|
||||
return Err(StackingError::NotAdjacent(self.to_string(), top.to_string()));
|
||||
if self.value == Value::King
|
||||
|| self.value.indexed_values() + 1 != top.value.indexed_values()
|
||||
{
|
||||
return Err(StackingError::NotAdjacent(
|
||||
self.to_string(),
|
||||
top.to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -153,9 +156,12 @@ impl Card {
|
||||
if self.value == Value::Ace {
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err(StackingError::NotAdjacent(self.to_string(), "an empty foundation".to_string()));
|
||||
return Err(StackingError::NotAdjacent(
|
||||
self.to_string(),
|
||||
"an empty foundation".to_string(),
|
||||
));
|
||||
}
|
||||
},
|
||||
}
|
||||
Some(c) => {
|
||||
if self.suit != c.suit {
|
||||
return Err(StackingError::WrongSuit);
|
||||
@@ -172,7 +178,7 @@ impl Card {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Deck {
|
||||
pub cards: Vec<Card>
|
||||
pub cards: Vec<Card>,
|
||||
}
|
||||
|
||||
impl Default for Deck {
|
||||
@@ -180,18 +186,14 @@ impl Default for Deck {
|
||||
let mut array = Vec::new();
|
||||
for suit in Suit::iter() {
|
||||
for value in Value::iter() {
|
||||
array.push(
|
||||
Card {
|
||||
suit,
|
||||
value,
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
array.push(Card {
|
||||
suit,
|
||||
value,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
}
|
||||
Deck {
|
||||
cards: array,
|
||||
}
|
||||
Deck { cards: array }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,7 +224,7 @@ pub struct CardAndPosition {
|
||||
pub enum CardPosition {
|
||||
TopWaste, // I don't think we'd ever interact with anything other than the top of the Waste
|
||||
Pile(usize, usize), // (PileNumber, Index)
|
||||
Foundation(usize)
|
||||
Foundation(usize),
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
@@ -245,7 +247,7 @@ pub struct Klondike {
|
||||
}
|
||||
|
||||
impl Klondike {
|
||||
pub fn deck_to_waste(self: &mut Self) {
|
||||
pub fn deck_to_waste(&mut self) {
|
||||
for _ in 0..self.num_cards_turned {
|
||||
let card = self.deck.pop();
|
||||
match card {
|
||||
@@ -255,13 +257,15 @@ impl Klondike {
|
||||
}
|
||||
}
|
||||
// TODO return some sort of error
|
||||
pub fn waste_to_deck(self: &mut Self) {
|
||||
pub fn waste_to_deck(&mut self) {
|
||||
match self.max_num_passes_through_deck {
|
||||
NumPassesThroughDeck::Unlimited => (),
|
||||
NumPassesThroughDeck::Limited(n) => if n >= self.current_num_passes_through_deck {
|
||||
// no!
|
||||
return
|
||||
},
|
||||
NumPassesThroughDeck::Limited(n) => {
|
||||
if n >= self.current_num_passes_through_deck {
|
||||
// no!
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.deck.len() != 0 {
|
||||
// no!
|
||||
@@ -275,7 +279,7 @@ impl Klondike {
|
||||
pub fn move_card(self, source_card: &CardAndPosition, dest_card: &CardAndPosition) -> bool {
|
||||
// TODO raise errors properly
|
||||
assert!(source_card.card.is_some());
|
||||
assert_eq!(source_card.card.unwrap().visible, true);
|
||||
assert!(source_card.card.unwrap().visible);
|
||||
dest_card.pos.is_valid_dest();
|
||||
|
||||
// Maybe TODO - check the .cards is the actual card in that position
|
||||
@@ -283,19 +287,30 @@ impl Klondike {
|
||||
match dest_card.pos {
|
||||
CardPosition::Pile(_, _) => self.move_card_to_pile(&source_card, &dest_card),
|
||||
CardPosition::Foundation(_f) => self.move_card_to_foundation(source_card, dest_card),
|
||||
CardPosition::TopWaste => unreachable!()
|
||||
CardPosition::TopWaste => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn move_card_to_foundation(mut self, source_card: &CardAndPosition, dest_card: &CardAndPosition) -> bool {
|
||||
pub fn move_card_to_foundation(
|
||||
mut self,
|
||||
source_card: &CardAndPosition,
|
||||
dest_card: &CardAndPosition,
|
||||
) -> bool {
|
||||
// TODO check the cards referenced in source and dest are the ones that are actually there
|
||||
// TODO - ditto this for the "move to pile" function
|
||||
// TODO actually learn Rust properly so I can figure out why I need to clone the whole struct to check a value
|
||||
if source_card.pos != CardPosition::TopWaste && !self.clone().is_card_top_of_pile(&source_card.pos) {
|
||||
if source_card.pos != CardPosition::TopWaste
|
||||
&& !self.clone().is_card_top_of_pile(&source_card.pos)
|
||||
{
|
||||
// TODO as above - make all these proper errors
|
||||
return false;
|
||||
}
|
||||
if source_card.card.unwrap().can_be_placed_on_foundation(&dest_card.card).is_err() {
|
||||
if source_card
|
||||
.card
|
||||
.unwrap()
|
||||
.can_be_placed_on_foundation(&dest_card.card)
|
||||
.is_err()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -305,27 +320,36 @@ impl Klondike {
|
||||
let card = self.waste.pop().unwrap();
|
||||
self.foundation[foundation_index].push(card);
|
||||
return true;
|
||||
},
|
||||
}
|
||||
CardPosition::Pile(pile_index, _) => {
|
||||
let card = self.piles[pile_index].pop().unwrap();
|
||||
self.foundation[foundation_index].push(card);
|
||||
return true;
|
||||
},
|
||||
}
|
||||
CardPosition::Foundation(_) => {
|
||||
unreachable!()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
pub fn move_card_to_pile(mut self, source_card: &CardAndPosition, dest_card: &CardAndPosition) -> bool {
|
||||
if source_card.card.unwrap().can_be_placed_on_pile(&dest_card.card.unwrap()).is_err() {
|
||||
pub fn move_card_to_pile(
|
||||
mut self,
|
||||
source_card: &CardAndPosition,
|
||||
dest_card: &CardAndPosition,
|
||||
) -> bool {
|
||||
if source_card
|
||||
.card
|
||||
.unwrap()
|
||||
.can_be_placed_on_pile(&dest_card.card.unwrap())
|
||||
.is_err()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
let (dpile_index, dcard_index) = match dest_card.pos {
|
||||
CardPosition::Pile(p, i) => (p, i),
|
||||
CardPosition::TopWaste | CardPosition::Foundation(_) => return false
|
||||
CardPosition::TopWaste | CardPosition::Foundation(_) => return false,
|
||||
};
|
||||
if dcard_index != self.piles[dpile_index].len() - 1 {
|
||||
// Can't move to anything other than top of pile
|
||||
@@ -337,7 +361,7 @@ impl Klondike {
|
||||
CardPosition::TopWaste => {
|
||||
let card = self.waste.pop().unwrap();
|
||||
self.piles[dpile_index].push(card);
|
||||
},
|
||||
}
|
||||
CardPosition::Pile(spile_index, scard_index) => {
|
||||
let num_cards_to_take = self.piles[spile_index].len() - scard_index; // -1 maybe?
|
||||
let mut cards: Vec<Card> = Vec::new();
|
||||
@@ -349,11 +373,11 @@ impl Klondike {
|
||||
}
|
||||
// TODO Properly learn rust and why I can't use drain & extend methods
|
||||
// https://doc.rust-lang.org/std/vec/struct.Vec.html#method.drain
|
||||
},
|
||||
}
|
||||
CardPosition::Foundation(s_index) => {
|
||||
let card = self.foundation[s_index].pop().unwrap();
|
||||
self.piles[dpile_index].push(card);
|
||||
},
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
@@ -361,19 +385,17 @@ impl Klondike {
|
||||
fn is_card_top_of_pile(self, pos: &CardPosition) -> bool {
|
||||
// TODO consider, at which point the Pos::Pile() ranges etc are correct
|
||||
match pos {
|
||||
CardPosition::Pile(pile_index, card_index) => {
|
||||
match self.piles.get(*pile_index) {
|
||||
Some(pile_index) => {
|
||||
if *card_index == (pile_index.len() - 1) {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
CardPosition::Pile(pile_index, card_index) => match self.piles.get(*pile_index) {
|
||||
Some(pile_index) => {
|
||||
if *card_index == (pile_index.len() - 1) {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
None => false
|
||||
}
|
||||
None => false,
|
||||
},
|
||||
CardPosition::TopWaste | CardPosition::Foundation(_) => false
|
||||
CardPosition::TopWaste | CardPosition::Foundation(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,9 +426,17 @@ impl Default for Klondike {
|
||||
fn default() -> Self {
|
||||
let mut deck = Deck::default();
|
||||
deck.shuffle(Seed::Unseeded);
|
||||
let mut piles: [Vec<Card>; NUM_PILES_KLONDIKE] = [Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new()];
|
||||
let mut piles: [Vec<Card>; NUM_PILES_KLONDIKE] = [
|
||||
Vec::new(),
|
||||
Vec::new(),
|
||||
Vec::new(),
|
||||
Vec::new(),
|
||||
Vec::new(),
|
||||
Vec::new(),
|
||||
Vec::new(),
|
||||
];
|
||||
for pile in 0..NUM_PILES_KLONDIKE {
|
||||
for num in 0..pile+1 {
|
||||
for num in 0..pile + 1 {
|
||||
let mut c = deck.cards.pop().unwrap();
|
||||
if num == pile {
|
||||
c.visible = true;
|
||||
@@ -445,19 +475,28 @@ mod tests {
|
||||
value: Value::Six,
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(testing_card.can_be_placed_on_pile(&bad_same_suit), Err(StackingError::SameColour));
|
||||
assert_eq!(
|
||||
testing_card.can_be_placed_on_pile(&bad_same_suit),
|
||||
Err(StackingError::SameColour)
|
||||
);
|
||||
let bad_same_colour = Card {
|
||||
suit: Suit::Diamond,
|
||||
value: Value::Six,
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(testing_card.can_be_placed_on_pile(&bad_same_colour), Err(StackingError::SameColour));
|
||||
assert_eq!(
|
||||
testing_card.can_be_placed_on_pile(&bad_same_colour),
|
||||
Err(StackingError::SameColour)
|
||||
);
|
||||
let should_stack_card = Card {
|
||||
suit: Suit::Club,
|
||||
value: Value::Six,
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(testing_card.can_be_placed_on_pile(&should_stack_card), Ok(()));
|
||||
assert_eq!(
|
||||
testing_card.can_be_placed_on_pile(&should_stack_card),
|
||||
Ok(())
|
||||
);
|
||||
let value_too_high = Card {
|
||||
suit: Suit::Club,
|
||||
value: Value::Seven,
|
||||
@@ -467,7 +506,9 @@ mod tests {
|
||||
if let Err(e) = not_adj_error {
|
||||
match e {
|
||||
StackingError::NotAdjacent(_, _) => assert!(true),
|
||||
StackingError::SameColour => assert!(false, "Colour is different - incorrect error"),
|
||||
StackingError::SameColour => {
|
||||
assert!(false, "Colour is different - incorrect error")
|
||||
}
|
||||
StackingError::WrongSuit => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
@@ -498,12 +539,12 @@ mod tests {
|
||||
let ace = Card {
|
||||
suit: Suit::Spade,
|
||||
value: Value::Ace,
|
||||
.. Default::default()
|
||||
..Default::default()
|
||||
};
|
||||
klon.piles[0].push(ace.clone());
|
||||
let source_card = CardAndPosition {
|
||||
card: Some(ace.clone()),
|
||||
pos: CardPosition::Pile(0, 1)
|
||||
pos: CardPosition::Pile(0, 1),
|
||||
};
|
||||
let dest_card = CardAndPosition {
|
||||
card: None,
|
||||
@@ -516,12 +557,12 @@ mod tests {
|
||||
let two = Card {
|
||||
suit: Suit::Spade,
|
||||
value: Value::Two,
|
||||
.. Default::default()
|
||||
..Default::default()
|
||||
};
|
||||
klon.piles[0].push(two.clone());
|
||||
let source_card = CardAndPosition {
|
||||
card: Some(two.clone()),
|
||||
pos: CardPosition::Pile(0, 1)
|
||||
pos: CardPosition::Pile(0, 1),
|
||||
};
|
||||
let dest_card = CardAndPosition {
|
||||
card: None,
|
||||
@@ -534,7 +575,7 @@ mod tests {
|
||||
let ace = Card {
|
||||
suit: Suit::Spade,
|
||||
value: Value::Ace,
|
||||
.. Default::default()
|
||||
..Default::default()
|
||||
};
|
||||
klon.waste.push(ace.clone());
|
||||
let source_card = CardAndPosition {
|
||||
@@ -552,7 +593,7 @@ mod tests {
|
||||
let two = Card {
|
||||
suit: Suit::Spade,
|
||||
value: Value::Two,
|
||||
.. Default::default()
|
||||
..Default::default()
|
||||
};
|
||||
klon.waste.push(two.clone());
|
||||
let source_card = CardAndPosition {
|
||||
@@ -570,12 +611,12 @@ mod tests {
|
||||
let ace = Card {
|
||||
suit: Suit::Spade,
|
||||
value: Value::Ace,
|
||||
.. Default::default()
|
||||
..Default::default()
|
||||
};
|
||||
let two = Card {
|
||||
suit: Suit::Spade,
|
||||
value: Value::Two,
|
||||
.. Default::default()
|
||||
..Default::default()
|
||||
};
|
||||
klon.waste.push(two.clone());
|
||||
klon.piles[0].push(ace.clone());
|
||||
@@ -589,8 +630,6 @@ mod tests {
|
||||
};
|
||||
assert!(klon.move_card_to_foundation(&source_card, &dest_card));
|
||||
|
||||
|
||||
|
||||
// TODO the following cases:
|
||||
// - moving a card from pile to foundation when something is already there
|
||||
// - moving Ace from waste to top of pile
|
||||
@@ -604,12 +643,12 @@ mod tests {
|
||||
let ace = Card {
|
||||
suit: Suit::Heart,
|
||||
value: Value::Ace,
|
||||
.. Default::default()
|
||||
..Default::default()
|
||||
};
|
||||
let two = Card {
|
||||
suit: Suit::Spade,
|
||||
value: Value::Two,
|
||||
.. Default::default()
|
||||
..Default::default()
|
||||
};
|
||||
klon.waste.push(two.clone());
|
||||
klon.piles[0].push(ace.clone());
|
||||
@@ -631,12 +670,12 @@ mod tests {
|
||||
let ace_heart = Card {
|
||||
suit: Suit::Heart,
|
||||
value: Value::Ace,
|
||||
.. Default::default()
|
||||
..Default::default()
|
||||
};
|
||||
let ace_spade = Card {
|
||||
suit: Suit::Spade,
|
||||
value: Value::Ace,
|
||||
.. Default::default()
|
||||
..Default::default()
|
||||
};
|
||||
klon.waste.push(ace_heart.clone());
|
||||
klon.piles[0].push(ace_spade.clone());
|
||||
@@ -655,7 +694,7 @@ mod tests {
|
||||
fn get_a_whole_deck() {
|
||||
let d = Deck::default();
|
||||
assert_eq!(d.cards.len(), 52); // Probably should test whether all cards are in... eh
|
||||
//println!("{:#?}", d); // A "manual" review looks alright
|
||||
//println!("{:#?}", d); // A "manual" review looks alright
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -664,12 +703,12 @@ mod tests {
|
||||
let ace = Card {
|
||||
suit: Suit::Heart,
|
||||
value: Value::Ace,
|
||||
.. Default::default()
|
||||
..Default::default()
|
||||
};
|
||||
let two = Card {
|
||||
suit: Suit::Spade,
|
||||
value: Value::Two,
|
||||
.. Default::default()
|
||||
..Default::default()
|
||||
};
|
||||
klon.piles[0].push(two.clone());
|
||||
klon.piles[1].push(ace.clone());
|
||||
@@ -683,18 +722,18 @@ mod tests {
|
||||
};
|
||||
assert!(klon.move_card_to_pile(&source_card, &dest_card));
|
||||
}
|
||||
#[test]
|
||||
#[test]
|
||||
fn move_pile_card_to_bad_pile() {
|
||||
let mut klon = Klondike::default();
|
||||
let ace = Card {
|
||||
suit: Suit::Heart,
|
||||
value: Value::Ace,
|
||||
.. Default::default()
|
||||
..Default::default()
|
||||
};
|
||||
let two = Card {
|
||||
suit: Suit::Diamond,
|
||||
value: Value::Two,
|
||||
.. Default::default()
|
||||
..Default::default()
|
||||
};
|
||||
klon.piles[0].push(two.clone());
|
||||
klon.piles[1].push(ace.clone());
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,10 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
chrono = { version = "0.4.39", features = ["serde"] }
|
||||
clap = { version = "4.5.42", features = ["derive"] }
|
||||
closestmatch = "0.1.2"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0.138"
|
||||
tempfile = "3.20.0"
|
||||
ureq = { version = "3.0.12", features = ["json"] }
|
||||
uuid = { version = "1.12.1", features = ["v4", "serde"] }
|
||||
|
||||
@@ -1,8 +1,83 @@
|
||||
use chrono::NaiveDate;
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
use std::fs;
|
||||
use std::io::{Read, Seek, SeekFrom, Write};
|
||||
use tempfile::NamedTempFile;
|
||||
use ureq;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct ScryfallBulkData {
|
||||
pub id: Uuid,
|
||||
pub uri: String,
|
||||
#[serde(rename = "type")]
|
||||
pub stype: String,
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub download_uri: String,
|
||||
pub updated_at: String,
|
||||
pub content_type: String,
|
||||
pub content_encoding: String,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct ScryfallBulk {
|
||||
pub object: String,
|
||||
pub has_more: bool,
|
||||
pub data: Vec<ScryfallBulkData>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
pub enum ScryfallBulkType {
|
||||
#[serde(rename = "oracle_cards")]
|
||||
OracleCards,
|
||||
#[serde(rename = "unique_artwork")]
|
||||
UniqueArtwork,
|
||||
#[serde(rename = "default_cards")]
|
||||
DefaultCards,
|
||||
#[serde(rename = "all_cards")]
|
||||
AllCards,
|
||||
#[serde(rename = "rulings")]
|
||||
Rulings,
|
||||
}
|
||||
|
||||
const SCRYFALL_BULK_API: &str = "https://api.scryfall.com/bulk-data";
|
||||
|
||||
pub fn download_latest(
|
||||
_stype: ScryfallBulkType,
|
||||
mut dest_file: &NamedTempFile,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let bulk_body: ScryfallBulk = ureq::get(SCRYFALL_BULK_API)
|
||||
.header("User-Agent", "Arthur's Card Finger Testing v0.1")
|
||||
.header("Accept", "application/json")
|
||||
.call()?
|
||||
.body_mut()
|
||||
.read_json::<ScryfallBulk>()?;
|
||||
|
||||
let mut download_uri = String::new();
|
||||
for scryfall_bulk in bulk_body.data {
|
||||
// TODO: Actually implement getting different types
|
||||
if scryfall_bulk.stype == "oracle_cards" {
|
||||
download_uri = scryfall_bulk.download_uri;
|
||||
}
|
||||
}
|
||||
assert!(!download_uri.is_empty());
|
||||
|
||||
let cards_response = ureq::get(download_uri)
|
||||
.header("User-Agent", "Arthur's Card Finger Testing v0.1")
|
||||
.header("Accept", "application/json")
|
||||
.call()?
|
||||
.body_mut()
|
||||
.with_config()
|
||||
.limit(700 * 1024 * 1024)
|
||||
.read_to_string()?;
|
||||
write!(dest_file, "{}", cards_response)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Info from here:
|
||||
// https://scryfall.com/docs/api/cards
|
||||
#[allow(dead_code)]
|
||||
@@ -110,7 +185,6 @@ struct ScryfallCard {
|
||||
pub watermark: Option<String>,
|
||||
pub preview: Option<Preview>,
|
||||
|
||||
|
||||
// These aren't in the Scryfall docs, but some cards do have 'em
|
||||
pub foil: Option<bool>,
|
||||
pub nonfoil: Option<bool>,
|
||||
@@ -785,4 +859,14 @@ mod tests {
|
||||
let ac = fs::read_to_string(f).unwrap();
|
||||
let _ac: Vec<ScryfallCard> = serde_json::from_str(&ac).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn get_scryfall_bulk_page() {
|
||||
let mut file = NamedTempFile::new().unwrap();
|
||||
let _ = download_latest(ScryfallBulkType::OracleCards, &file);
|
||||
let file_size = file.seek(SeekFrom::End(0)).unwrap();
|
||||
assert!(file_size > 4092);
|
||||
println!("File size: {}", file_size);
|
||||
}
|
||||
}
|
||||
|
||||
22
scryfall_deser/src/main.rs
Normal file
22
scryfall_deser/src/main.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
use clap::Parser;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Args {
|
||||
#[arg(short, long)]
|
||||
update: bool,
|
||||
remainder: Vec<String>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut args = Args::parse();
|
||||
if args.update {
|
||||
unimplemented!("Haven't implemented update yet");
|
||||
}
|
||||
let card_name = args.remainder;
|
||||
if card_name.is_empty() {
|
||||
panic!("You need to put some card text to search");
|
||||
}
|
||||
let search_string = card_name.join(" ");
|
||||
dbg!(search_string);
|
||||
}
|
||||
Reference in New Issue
Block a user