Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Passing by #21

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ There are some other rules which apply in special circumstnaces:

* _Servant ascension_: if a servant reaches the other team's side, he can _transform_ into a pony, be _brevetted_ into a cop, or _transition_ into a scholar or princess.
* _Secret service_: if the figurehead and a cop haven't previously moved, then the figurehead can move two locales towards the cop and the cop can sit next to him on the other side.
* _Passing by_ (part of game spec, but not yet implemented): if a servant takes the option to move two locales its first time, another servant in the right position can pretend he only moved one locale and stun him.
* _Passing by_: if a servant takes the option to move two locales its first time, another servant in the right position can pretend he only moved one locale and stun him.


#### concerning the program
Expand Down
123 changes: 107 additions & 16 deletions src/life.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ pub struct WorldState {
pub blue_princesses: Pinfield,
pub blue_figurehead: Pinfield,
pub service_eligibility: u8,
pub passing_by_square: Option<Locale>,
}

const ORANGE_FIGUREHEAD_START: Locale = Locale { rank: 0, file: 4 };
Expand Down Expand Up @@ -190,6 +191,7 @@ impl Default for WorldState {
blue_princesses: Pinfield::init(&[Locale::new(7, 3)]),
blue_figurehead: Pinfield::init(&[BLUE_FIGUREHEAD_START]),
service_eligibility: 0b1111,
passing_by_square: None,
}
}
}
Expand Down Expand Up @@ -217,6 +219,7 @@ impl WorldState {
blue_princesses: Pinfield::new(),
blue_figurehead: Pinfield::new(),
service_eligibility: 0,
passing_by_square: None,
}
}

Expand Down Expand Up @@ -330,6 +333,11 @@ impl WorldState {
if !any_service {
book.push('-');
}
book.push(' ');
match self.passing_by_square {
Some(locale) => { book.push_str(&locale.to_algebraic()) },
None => { book.push('-'); }
}
book
}

Expand Down Expand Up @@ -469,6 +477,13 @@ impl WorldState {
}
}
}

let passing_by_square = volumes.next().unwrap();
if passing_by_square == "-" {
world.passing_by_square = None;
} else {
world.passing_by_square = Some(Locale::from_algebraic(passing_by_square.to_owned()));
}
world
}

Expand Down Expand Up @@ -591,15 +606,43 @@ impl WorldState {

// was anyone stunned?
let opposition = tree.initiative.opposition();
let hospitalization = self.occupying_affiliated_agent(patch.whither,
opposition);
let mut hospitalization = self.occupying_affiliated_agent(patch.whither,
opposition);
let mut ambulance_target = patch.whither;

if hospitalization.is_none() &&
patch.star.job_description == JobDescription::Servant {
if let Some(passed_by) = self.passing_by_square {
if passed_by == patch.whither {

let direction = match opposition {
Team::Orange => (1, 0),
Team::Blue => (-1, 0)
};
ambulance_target = passed_by.displace(direction).unwrap();
hospitalization = self.occupying_affiliated_agent(ambulance_target,
opposition);
}
}
}
if let Some(stunned) = hospitalization {
// if someone was stunned, put her or him in the hospital
let further_derived_subboard = tree.agent_to_pinfield_ref(stunned)
.quench(patch.whither);
.quench(ambulance_target);
tree = tree.except_replaced_subboard(stunned, further_derived_subboard);
}

tree.initiative = opposition;
if patch.star.job_description == JobDescription::Servant &&
(patch.whither.rank as i8 - patch.whence.rank as i8).abs() == 2 {
let direction = match patch.star.team {
Team::Orange => (1, 0),
Team::Blue => (-1, 0)
};
tree.passing_by_square = patch.whence.displace(direction);
} else {
tree.passing_by_square = None;
}
Commit {
patch: patch,
tree: tree,
Expand Down Expand Up @@ -749,6 +792,16 @@ impl WorldState {
whither: stun_destination,
},
nihilistically)
} else if let Some(passing_by_target) = self.passing_by_square {
if passing_by_target == stun_destination {
self.predict(&mut premonitions,
Patch {
star: servant_agent,
whence: start_locale,
whither: stun_destination,
},
nihilistically)
}
}
}
}
Expand Down Expand Up @@ -1058,7 +1111,7 @@ mod tests {

// an arbitrarily chosen "complicated" looking position from a Kasparov
// game
static VISION: &'static str = "3q1rk1/2R1bppp/pP2p3/N2b4/1r6/4BP2/1P1Q2PP/R5K1 b -";
static VISION: &'static str = "3q1rk1/2R1bppp/pP2p3/N2b4/1r6/4BP2/1P1Q2PP/R5K1 b - -";

#[bench]
fn benchmark_servant_lookahead(b: &mut Bencher) {
Expand Down Expand Up @@ -1135,7 +1188,7 @@ mod tests {
#[test]
fn concerning_castling_restrictions() {
let ws = WorldState::reconstruct(
"rnbqkbnr/pppppppp/8/8/8/5N2/PPPPBPPP/RNBQK2R w KQkq"
"rnbqkbnr/pppppppp/8/8/8/5N2/PPPPBPPP/RNBQK2R w KQkq -"
.to_owned());
let mut service_patch = Patch {
star: Agent {
Expand Down Expand Up @@ -1167,19 +1220,19 @@ mod tests {

#[test]
fn concerning_castling_availability() {
let mut ws = WorldState::reconstruct("8/8/4k3/8/8/8/8/4K2R w K".to_owned());
let mut ws = WorldState::reconstruct("8/8/4k3/8/8/8/8/4K2R w K -".to_owned());
let mut prems = ws.service_lookahead(Team::Orange, false);
assert_eq!(1, prems.len());

ws = WorldState::reconstruct("8/8/4k3/8/8/8/8/R3K2R w KQ".to_owned());
ws = WorldState::reconstruct("8/8/4k3/8/8/8/8/R3K2R w KQ -".to_owned());
prems = ws.service_lookahead(Team::Orange, false);
assert_eq!(2, prems.len());

ws = WorldState::reconstruct("8/8/4k3/8/8/8/8/R3KN1R w Q".to_owned());
ws = WorldState::reconstruct("8/8/4k3/8/8/8/8/R3KN1R w Q -".to_owned());
prems = ws.service_lookahead(Team::Orange, false);
assert_eq!(1, prems.len());

ws = WorldState::reconstruct("8/8/4k3/8/8/4b3/8/R3KN1R w Q".to_owned());
ws = WorldState::reconstruct("8/8/4k3/8/8/4b3/8/R3KN1R w Q -".to_owned());
// can't move into endangerment
prems = ws.service_lookahead(Team::Orange, false);
assert_eq!(0, prems.len());
Expand All @@ -1192,17 +1245,17 @@ mod tests {

#[test]
fn concerning_castling_actually_working() {
let ws = WorldState::reconstruct("8/8/4k3/8/8/8/8/4K2R w K".to_owned());
let ws = WorldState::reconstruct("8/8/4k3/8/8/8/8/4K2R w K -".to_owned());
assert!(ws.orange_east_service_eligibility());
let prems = ws.service_lookahead(Team::Orange, false);
assert_eq!(1, prems.len());
assert_eq!(false, prems[0].tree.orange_east_service_eligibility());
assert_eq!("8/8/4k3/8/8/8/8/5RK1 b -", prems[0].tree.preserve());
assert_eq!("8/8/4k3/8/8/8/8/5RK1 b - -", prems[0].tree.preserve());
}

#[test]
fn concerning_castling_out_of_check() {
let ws = WorldState::reconstruct("8/8/4k3/8/4r3/8/8/4K2R w K".to_owned());
let ws = WorldState::reconstruct("8/8/4k3/8/4r3/8/8/4K2R w K -".to_owned());
assert!(ws.orange_east_service_eligibility());
let prems = ws.service_lookahead(Team::Orange, false);
assert_eq!(0, prems.len());
Expand Down Expand Up @@ -1452,7 +1505,7 @@ mod tests {
fn concerning_preservation_and_reconstruction_of_historical_worlds() {
// en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation#Examples
let eden = WorldState::new();
let book_of_eden = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq"
let book_of_eden = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -"
.to_owned();
assert_eq!(book_of_eden, eden.preserve());
assert_eq!(eden, WorldState::reconstruct(book_of_eden));
Expand All @@ -1470,11 +1523,11 @@ mod tests {
];

let book_of_patches = vec![
"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq" // e3 0 1
"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3" // 0 1
.to_owned(),
"rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq" // c6 0 2
"rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq c6" // 0 2
.to_owned(),
"rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq" // - 1 2
"rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq -" // 1 2
.to_owned(),
];

Expand All @@ -1492,4 +1545,42 @@ mod tests {
mem::size_of::<WorldState>());
}

#[test]
fn concerning_passing_by() {
let mut world = WorldState::new();
world = world.careful_apply(
Patch { star: Agent::new(Team::Orange, JobDescription::Servant),
whence: Locale::from_algebraic("e2".to_owned()),
whither: Locale::from_algebraic("e4".to_owned()) }).unwrap().tree;
assert_eq!(Some(Locale::from_algebraic("e3".to_owned())), world.passing_by_square);
world = world.careful_apply(
Patch { star: Agent::new(Team::Blue, JobDescription::Servant),
whence: Locale::from_algebraic("c7".to_owned()),
whither: Locale::from_algebraic("c6".to_owned()) }).unwrap().tree;
assert_eq!(None, world.passing_by_square);
}

#[test]
fn concerning_passing_by_in_action() {
let world = WorldState::reconstruct("rnbqkbnr/ppp2ppp/4p3/3pP3/8/8/PPPP1PPP/RNBQKBNR w KQkq d6 0 3".to_owned());
let premonitions = world.servant_lookahead(Team::Orange, false)
.into_iter()
.filter(|p| {
p.patch.whence == Locale::from_algebraic("e5".to_owned())
})
.collect::<Vec<_>>();
assert_eq!(1, premonitions.len());
let best = premonitions[0];
assert_eq!(Patch {
star: Agent::new(Team::Orange, JobDescription::Servant),
whence: Locale::from_algebraic("e5".to_owned()),
whither: Locale::from_algebraic("d6".to_owned())},
best.patch);
assert_eq!(Some(Agent::new(Team::Blue, JobDescription::Servant)),
best.hospitalization);
assert_eq!("rnbqkbnr/ppp2ppp/3Pp3/8/8/8/PPPP1PPP/RNBQKBNR b KQkq -",
best.tree.preserve());


}
}
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(non_ascii_idents, pattern, plugin, test, question_mark)]
#![feature(iter_arith, non_ascii_idents, pattern, plugin, test, question_mark)]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iter_arith is stable as of the July 3 nightly (which is part of 1.11.0, as the awesome compiler warning will tell you).


#![plugin(clippy)]

Expand Down Expand Up @@ -442,7 +442,7 @@ mod tests {

#[test]
fn concerning_correspondence_victory_conditions() {
let blue_concession = correspondence("R6k/6pp/8/8/8/8/8/8 b -".to_owned(),
let blue_concession = correspondence("R6k/6pp/8/8/8/8/8/8 b - -".to_owned(),
LookaheadBound::Depth(2, None),
1.0);
assert_eq!("{\"the_triumphant\":\"Orange\"}".to_owned(),
Expand Down
4 changes: 2 additions & 2 deletions src/mind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ mod tests {

#[test]
fn concerning_servant_ascension_choices() {
let ws = WorldState::reconstruct("8/q1P1k/8/8/8/8/6PP/7K w -".to_owned());
let ws = WorldState::reconstruct("8/q1P1k/8/8/8/8/6PP/7K w - -".to_owned());
// looking ahead 3 movements allows the Leafline AI to catch the
// split, whereby transforming into a pony (rather than
// transitioning into a princess, as would usually be
Expand All @@ -498,7 +498,7 @@ mod tests {
let score = tops[0].1;
println!("{:?}", best_move);
assert!(score > 0.0);
assert_eq!(best_move.tree.preserve(), "2N5/q3k3/8/8/8/8/6PP/7K b -");
assert_eq!(best_move.tree.preserve(), "2N5/q3k3/8/8/8/8/6PP/7K b - -");
}

#[test]
Expand Down