1 // Copyright 2020-2021 Ian Jackson and contributors to Otter
2 // SPDX-License-Identifier: AGPL-3.0-or-later
3 // There is NO WARRANTY.
7 #[derive(Clone,Debug,Default,Serialize,Deserialize)]
8 pub struct PerPlayerIdMap {
9 pub(in super) f: SecondarySlotMap<PieceId, VisiblePieceId>,
10 pub(in super) r: DenseSlotMap<VisiblePieceId, PieceId>,
14 pub fn fwd(&self, piece: PieceId) -> Option<VisiblePieceId> {
15 Some(*self.f.get(piece)?)
17 pub fn rev(&self, vis: VisiblePieceId) -> Option<PieceId> {
18 Some(*self.r.get(vis)?)
21 fn fwd_or_insert_internal<R, VF, OF>
22 (&mut self, piece: PieceId, vf: VF, of: OF) -> R
23 where VF: FnOnce(VisiblePieceId) -> R,
24 OF: FnOnce(secondary::OccupiedEntry<PieceId,VisiblePieceId>) -> R,
26 match self.f.entry(piece).expect("stale PieceId !") {
27 secondary::Entry::Vacant(mut vac) => {
28 if let Some((_, stale_vis)) = vac.remove_stale_entry() {
29 self.r.remove(stale_vis);
31 let vis = self.r.insert(piece);
35 secondary::Entry::Occupied(occ) => {
41 pub fn insert(&mut self, piece: PieceId) {
42 self.fwd_or_insert_internal(piece, |_vis|(), |vis|{
43 panic!("duplicate insert of {:?} {:?}", piece, vis)
47 pub fn fwd_or_insert(&mut self, piece: PieceId) -> VisiblePieceId {
48 self.fwd_or_insert_internal(piece, |vis|vis, |occ| *occ.get())
52 pub type NotchNumber = u32;
55 pub struct Notch = NotchNumber;
58 impl From<Notch> for u32 {
59 fn from(n: Notch) -> u32 { n.index().try_into().unwrap() }
62 type NotchPtr = Option<Notch>;
64 #[derive(Clone,Copy,Debug,Serialize,Deserialize)]
65 #[derive(Eq,PartialEq)]
70 type NR = NotchRecord;
73 fn piece(&self) -> Option<PieceId> { match self {
74 &NR::Piece(p) => Some(p),
78 fn unwrap_free(&self) -> NotchPtr { match self {
79 &NR::Free(ptr) => ptr,
83 fn unwrap_free_mut(&mut self) -> &mut NotchPtr { match self {
89 #[derive(Clone,Debug,Serialize,Deserialize,Default)]
92 table: IndexVec<Notch, NotchRecord>,
93 zg: IndexVec<Notch, Generation>, // last time notch was (re)filled
98 pub fn notch_zg(&self, notch: Notch) -> Option<Generation> {
99 self.notches.zg.get(notch).copied()
104 pub fn iter<'i>(&'i self) -> impl Iterator<Item=PieceId> + 'i {
106 .filter_map(|nr| match nr {
108 &NR::Piece(p) => Some(p),
112 /// correctness: piece must not already be in this `Notches`
113 pub fn insert(&mut self, zg: Generation, piece: PieceId) -> Notch {
114 let new = NR::Piece(piece);
115 let notch = match self.freelist.take() {
117 let a = self.table.push(new);
118 let b = self.zg.push(zg);
119 // gs.max_z was updated when we created the occultation
123 Some(old_free_head) => {
124 self.freelist = self.table[old_free_head].unwrap_free();
125 self.table[old_free_head] = new;
126 self.zg[old_free_head] = zg;
135 pub fn remove(&mut self, piece: PieceId, notch: Notch) {
136 match self.table.get(notch) {
137 Some(&NR::Piece(p)) if p == piece => { },
138 _ => throw!(internal_error_bydebug(&(piece, notch, self))),
141 let mut insert_here = &mut self.freelist;
143 let next = *insert_here;
144 let next = if let Some(y) = next { y } else { break };
145 if notch < next { break }
146 if notch == next { panic!() };
147 let next = &mut self.table[next];
148 insert_here = next.unwrap_free_mut();
150 // Now either *insert_here==NULL or notch < insert_here->next
151 let old_next = mem::replace(insert_here, Some(notch));
152 self.table[notch] = NR::Free(old_next);
157 pub fn len(&self) -> NotchNumber { self.used }
158 pub fn is_empty(&self) -> bool { self.used == 0 }
163 let mut count_free = 0;
164 let mut walk = self.freelist;
165 while let Some(here) = walk {
167 let next_walk = self.table[here].unwrap_free();
168 if let Some(more) = next_walk {
169 assert!(more > here);
176 .filter(|nr| matches!(nr, NR::Free(_)))
179 let pieces = self.table.iter()
180 .filter_map(|nr| if let NR::Piece(p) = nr { Some(p) } else { None })
181 .collect::<HashSet<_>>();
187 count_free + pieces.len(),
201 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error> {
202 let (c, p) = match self {
203 Can::Insert(p) => ('+', p),
204 Can::Remove(p) => ('-', p),
206 let (idx, _vsn) = p.data().get_idx_version();
207 write!(f, "{}{}", c, idx)
217 const NPIECES: usize = 4;
218 const DEPTH: usize = 7;
221 fn implement(&self) {
222 eprintln!("implement {:?}", self);
223 let mut notches: Notches = default();
224 let mut pieces = SecondarySlotMap::new();
225 for op in &self.todo { match op {
227 let notch = notches.insert(Generation(0), p);
229 pieces.insert(p, notch);
232 let notch = pieces[p];
233 notches.remove(p, notch).unwrap();
239 fn recurse(&mut self) {
240 if self.todo.len() == DEPTH { self.implement(); return; }
241 eprintln!(" recurse {:?}", &self);
243 for i in 0..self.can.len() {
244 let op = self.can.swap_remove(i);
246 let l = self.can.len();
248 &Can::Insert(p) => { self.can.push(Can::Remove(p)) },
249 &Can::Remove(_) => { },
254 let op = self.todo.pop().unwrap();
256 self.can.truncate(l);
258 let last = if i < self.can.len() {
259 mem::replace(&mut self.can[i], op)
272 let mut slotmap: DenseSlotMap<PieceId,()> = default();
274 .map(|_| slotmap.insert(()))
275 .map(|p| Can::Insert(p))
283 pub fn permute(_occid: OccId,
284 occ: &mut Occultation,
285 gplayers: &mut GPlayers,
286 gpieces: &mut GPieces,
290 let mut ilks: HashMap<OccultIlkId, (
295 for (notch, nr) in occ.notches.table.iter_enumerated() {
296 let piece = if let Some(p) = nr.piece() { p } else { continue };
297 if_let!{ Some(gpc) = gpieces.get(piece); else continue }
298 if gpc.held.is_some() { continue }
299 let occilk = (|| Some(ipieces.get(piece)?.occilk.as_ref()?))();
300 if_let!{ Some(occilk) = occilk; else { continue; }}
301 if_let!{ IOI::Mix(occilk) = occilk; else continue; }
302 let (notches, pieces) = ilks.entry(*occilk.borrow()).or_default();
307 let mut new_notches = occ.notches.table.clone();
308 for (_occilk, (notches, pieces)) in ilks {
309 // We must permute for if we have any views that are scrambled
310 // or displaced obviously. For invisible too, so that when they
311 // reappear the ids have been permuted. And that's all the
312 // non-Visible views which an occultation ought to have at least
315 // We choose a single permutation of each of the subsets (for a
316 // partiular ilk) of the pieces in the Occultation::notches.
319 let mut permu = pieces;
320 config().game_rng.shuffle(&mut permu);
324 for (notch, new_piece) in itertools::zip_eq(notches, permu) {
325 new_notches[notch] = NR::Piece(new_piece);
326 gpieces.get_mut(new_piece).unwrap()
327 .occult.passive.as_mut().unwrap()
336 for (player, gpl) in gplayers.iter_mut() {
337 match occ.views.get_kind(player) {
338 OccK::Visible => continue,
340 OccK::Displaced{..} |
341 OccK::Invisible => (),
344 let mut fwd_updates = vec![];
345 for (old, new) in izip!(&occ.notches.table, &new_notches) {
347 if let Some((old, new)) = zip_eq(old.piece(), new.piece()).next();
348 if let Some(vpid) = gpl.idmap.fwd(old);
350 fwd_updates.push((new, vpid));
351 if let Some(e) = gpl.idmap.r.get_mut(vpid) {
358 for (new, vpid) in fwd_updates {
359 gpl.idmap.f.insert(new, vpid);
363 occ.notches.table = new_notches;
364 trace_dbg!("permuted", &occ);
367 #[cfg(not(debug_assertions))]
369 pub fn consistency_check(
370 _gplayers: &GPlayers,
372 _goccults: &GOccults,
375 #[cfg(debug_assertions)]
376 pub fn consistency_check(
381 for (_player, gpl) in gplayers.iter() {
382 for (piece, &vpid) in gpl.idmap.f.iter() {
383 if let Some(&rpiece) = gpl.idmap.r.get(vpid) {
384 assert_eq!(piece, rpiece);
387 for (vpid, &piece) in gpl.idmap.r.iter() {
388 if let Some(&fvpid) = gpl.idmap.f.get(piece) {
389 assert_eq!(vpid, fvpid);
394 for (piece, gpc) in gpieces.iter() {
395 if let Some(occid) = gpc.occult.active {
396 let occ = goccults.occults.get(occid).unwrap();
397 assert_eq!(occ.occulter, piece);
398 assert_eq!(&gpc.occult.passive, &None);
401 if let Some(Passive { occid, permute_notch }) = gpc.occult.passive {
402 let occ = goccults.occults.get(occid).unwrap();
403 if let Some(notch) = permute_notch {
404 assert_eq!(occ.notches.table[notch], NR::Piece(piece));
406 assert!(occ.unnotched.contains(&piece));
411 for (occid, occ) in goccults.occults.iter() {
412 let ogpc = gpieces.get(occ.occulter).unwrap();
413 assert_eq!(ogpc.occult.active, Some(occid));
414 assert_eq!(occ.notches.table.len(), occ.notches.zg.len());
416 for (notch, nr) in occ.notches.table.iter_enumerated() {
417 if_let!{ Some(ppiece) = nr.piece(); else continue };
418 let pgpc = gpieces.get(ppiece).unwrap();
419 let passive = pgpc.occult.passive.as_ref().unwrap();
420 assert_eq!(passive.occid, occid);
421 assert_eq!(passive.permute_notch.unwrap(), notch);
424 let nfree1 = occ.notches.table.iter()
425 .filter(|nr| nr.piece().is_none()).count();
426 let mut walk = occ.notches.freelist;
428 while let Some(here) = walk {
430 let next = match occ.notches.table[here] {
431 NR::Free(next) => next,
432 NR::Piece(_) => panic!(),
434 if let Some(next) = next {
435 assert!(next > here);
439 assert_eq!(nfree1, nfree2);
441 for &ppiece in &occ.unnotched {
442 assert_eq!(gpieces.get(ppiece).unwrap().occult.passive,
443 Some(Passive { occid, permute_notch: None }));