1 // This file is part of Freecell Solver. It is subject to the license terms in
2 // the COPYING.txt file found in the top-level directory of this distribution
3 // and at http://fc-solve.shlomifish.org/docs/distro/COPYING.html . No part of
4 // Freecell Solver, including this file, may be copied, modified, propagated,
5 // or distributed except according to the terms contained in the COPYING file.
6 //
7 // Copyright (c) 2011 Shlomi Fish
8 // delta_states_debondt_impl.h - "delta states" are an encoding of states,
9 // where the states are encoded and decoded based on a compact delta from the
10 // initial state.
11 //
12 // This encoding improves upon the original delta_states.c .
13 #include "indirect_buffer.h"
14 #include "delta_states_iface.h"
15 #include "delta_states.h"
16
17 #ifdef FCS_DEBONDT_DELTA_STATES
18 #define FOUNDATION_BASE (RANK_KING + 1)
19
20 enum
21 {
22 OPT_TOPMOST = 0,
23 OPT_DONT_CARE = OPT_TOPMOST,
24 OPT_FREECELL = 1,
25 OPT_ORIG_POS = 2,
26 NUM_KING_OPTS = 3,
27 OPT_PARENT_SUIT_MOD_IS_0 = 3,
28 OPT_PARENT_SUIT_MOD_IS_1 = 4,
29 NUM_OPTS = 5,
30 OPT_IN_FOUNDATION = 5,
31 OPT__BAKERS_DOZEN__ORIG_POS = 0,
32 OPT__BAKERS_DOZEN__FIRST_PARENT = 1,
33 NUM__BAKERS_DOZEN__OPTS = OPT__BAKERS_DOZEN__FIRST_PARENT + 4,
34 OPT__BAKERS_DOZEN__IN_FOUNDATION = NUM__BAKERS_DOZEN__OPTS,
35 };
36
37 #define IS_BAKERS_DOZEN() (local_variant == FCS_DBM_VARIANT_BAKERS_DOZEN)
38
fc_solve_delta_stater_init(fcs_delta_stater * const self,const fcs_dbm_variant_type local_variant,fcs_state * const init_state,const size_t num_columns,const int num_freecells PASS_ON_NOT_FC_ONLY (const int sequences_are_built_by))39 static inline void fc_solve_delta_stater_init(fcs_delta_stater *const self,
40 const fcs_dbm_variant_type local_variant, fcs_state *const init_state,
41 const size_t num_columns,
42 const int num_freecells PASS_ON_NOT_FC_ONLY(
43 const int sequences_are_built_by))
44 {
45 FCS_ON_NOT_FC_ONLY(self->sequences_are_built_by = sequences_are_built_by);
46 self->num_columns = num_columns;
47 self->num_freecells = num_freecells;
48 self->init_state = init_state;
49
50 memset(self->bakers_dozen_topmost_cards_lookup, '\0',
51 sizeof(self->bakers_dozen_topmost_cards_lookup));
52
53 fc_solve_var_base_writer_init(&self->w);
54 fc_solve_var_base_reader_init(&self->r);
55
56 if (IS_BAKERS_DOZEN())
57 {
58 #pragma GCC diagnostic push
59 #ifndef __clang__
60 #pragma GCC diagnostic ignored "-Waggressive-loop-optimizations"
61 #endif
62 for (size_t col_idx = 0; col_idx < self->num_columns; ++col_idx)
63 {
64 const_AUTO(col, fcs_state_get_col(*init_state, col_idx));
65 const int col_len = fcs_col_len(col);
66
67 if (col_len > 0)
68 {
69 const_AUTO(top_card, fcs_col_get_card(col, 0));
70 self->bakers_dozen_topmost_cards_lookup[top_card >> 3] |=
71 (1 << (top_card & (8 - 1)));
72 }
73 }
74 #pragma GCC diagnostic pop
75 }
76 }
77
fc_solve_delta_stater__init_card_states(fcs_delta_stater * const self)78 static inline void fc_solve_delta_stater__init_card_states(
79 fcs_delta_stater *const self)
80 {
81 int *const card_states = self->card_states;
82 for (size_t i = 0; i < COUNT(self->card_states); ++i)
83 {
84 card_states[i] = -1;
85 }
86 }
87
88 #ifdef FCS_USE_INT128_FOR_VAR_BASE
89 #define fc_solve_delta_stater_release(s)
90 #else
fc_solve_delta_stater_release(fcs_delta_stater * const self)91 static inline void fc_solve_delta_stater_release(fcs_delta_stater *const self)
92 {
93 fc_solve_var_base_reader_release(&(self->r));
94 fc_solve_var_base_writer_release(&(self->w));
95 }
96 #endif
97
wanted_suit_bit_opt(const fcs_card parent_card)98 static inline int wanted_suit_bit_opt(const fcs_card parent_card)
99 {
100 return ((fcs_card_suit(parent_card) & 0x2) ? OPT_PARENT_SUIT_MOD_IS_1
101 : OPT_PARENT_SUIT_MOD_IS_0);
102 }
103
wanted_suit_idx_opt(const fcs_card parent_card)104 static inline int wanted_suit_idx_opt(const fcs_card parent_card)
105 {
106 return OPT__BAKERS_DOZEN__FIRST_PARENT + fcs_card_suit(parent_card);
107 }
108
calc_child_card_option(const fcs_dbm_variant_type local_variant,const fcs_card parent_card,const fcs_card child_card PASS_ON_NOT_FC_ONLY (const int sequences_are_built_by))109 static inline int calc_child_card_option(
110 const fcs_dbm_variant_type local_variant, const fcs_card parent_card,
111 const fcs_card child_card PASS_ON_NOT_FC_ONLY(
112 const int sequences_are_built_by))
113 {
114 if (IS_BAKERS_DOZEN())
115 {
116 if ((fcs_card_rank(child_card) != 1) &&
117 (fcs_card_rank(child_card) + 1 == fcs_card_rank(parent_card)))
118 {
119 return wanted_suit_idx_opt(parent_card);
120 }
121 else
122 {
123 return OPT__BAKERS_DOZEN__ORIG_POS;
124 }
125 }
126 else
127 {
128 if ((fcs_card_rank(child_card) != 1) &&
129 (fcs_is_parent_card(child_card, parent_card)))
130 {
131 return wanted_suit_bit_opt(parent_card);
132 }
133 else
134 {
135 return OPT_ORIG_POS;
136 }
137 }
138 }
139
get_top_rank_for_iter(const fcs_dbm_variant_type local_variant)140 static inline int get_top_rank_for_iter(
141 const fcs_dbm_variant_type local_variant)
142 {
143 return (IS_BAKERS_DOZEN() ? (RANK_KING - 1) : RANK_KING);
144 }
145
fc_solve_delta_stater_encode_composite(fcs_delta_stater * const self,const fcs_dbm_variant_type local_variant,fcs_var_base_writer * const writer)146 static void fc_solve_delta_stater_encode_composite(fcs_delta_stater *const self,
147 const fcs_dbm_variant_type local_variant, fcs_var_base_writer *const writer)
148 {
149 fcs_state *const derived = self->derived_state;
150
151 fc_solve_delta_stater__init_card_states(self);
152
153 for (size_t suit_idx = 0; suit_idx < FCS_NUM_SUITS; ++suit_idx)
154 {
155 const unsigned long rank = fcs_foundation_value(*derived, suit_idx);
156
157 fc_solve_var_base_writer_write(writer, FOUNDATION_BASE, rank);
158
159 const unsigned long max_rank = ((rank < 1) ? 1 : rank);
160
161 for (unsigned long r = 1; r <= max_rank; ++r)
162 {
163 #define CARD_POS(card) ((size_t)(card))
164 #define CARD_STATE(card) self->card_states[CARD_POS(card)]
165 #define SET_CARD_STATE(card, opt) CARD_STATE(card) = (opt)
166 #define RS_STATE(rank, suit_idx) CARD_STATE(fcs_make_card(rank, suit_idx))
167 RS_STATE(((fcs_card)r), ((fcs_card)suit_idx)) = OPT_DONT_CARE;
168 }
169 }
170
171 #if MAX_NUM_FREECELLS > 0
172 for (int fc_idx = 0; fc_idx < self->num_freecells; ++fc_idx)
173 {
174 const fcs_card card = fcs_freecell_card(*derived, fc_idx);
175
176 if (fcs_card_is_valid(card))
177 {
178 SET_CARD_STATE(card, OPT_FREECELL);
179 }
180 }
181 #endif
182
183 if (IS_BAKERS_DOZEN())
184 {
185 for (size_t col_idx = 0; col_idx < self->num_columns; ++col_idx)
186 {
187 const_AUTO(col, fcs_state_get_col(*derived, col_idx));
188 const int col_len = fcs_col_len(col);
189
190 if (!col_len)
191 {
192 continue;
193 }
194 const_AUTO(top_card, fcs_col_get_card(col, 0));
195
196 // Skip Aces which were already set.
197 if (fcs_card_rank(top_card) != 1)
198 {
199 SET_CARD_STATE(top_card, OPT__BAKERS_DOZEN__ORIG_POS);
200 }
201
202 for (int pos = 1; pos < col_len; ++pos)
203 {
204 const fcs_card parent_card = fcs_col_get_card(col, pos - 1);
205 const fcs_card this_card = fcs_col_get_card(col, pos);
206
207 // Skip Aces which were already set.
208 if (fcs_card_rank(this_card) != 1)
209 {
210 SET_CARD_STATE(
211 this_card, ((fcs_card_rank(this_card) + 1 ==
212 fcs_card_rank(parent_card))
213 ? wanted_suit_idx_opt(parent_card)
214 : OPT__BAKERS_DOZEN__ORIG_POS));
215 }
216 }
217 }
218 }
219 else
220 {
221 for (size_t col_idx = 0; col_idx < self->num_columns; ++col_idx)
222 {
223 const_AUTO(col, fcs_state_get_col(*derived, col_idx));
224 const int col_len = fcs_col_len(col);
225
226 if (!col_len)
227 {
228 continue;
229 }
230 const_AUTO(top_card, fcs_col_get_card(col, 0));
231 if (fcs_card_rank(top_card) != 1)
232 {
233 SET_CARD_STATE(top_card, OPT_TOPMOST);
234 }
235
236 fcs_card parent_card = top_card;
237 for (int child_idx = 1; child_idx < col_len; ++child_idx)
238 {
239 const fcs_card child_card = fcs_col_get_card(col, child_idx);
240
241 if (fcs_card_rank(child_card) != 1)
242 {
243 const int opt =
244 calc_child_card_option(local_variant, parent_card,
245 child_card PASS_ON_NOT_FC_ONLY(
246 self->sequences_are_built_by));
247 SET_CARD_STATE(child_card, opt);
248 }
249
250 parent_card = child_card;
251 }
252 }
253 }
254
255 // All cards should be determined now - let's encode.
256 //
257 // The foundations have already been encoded.
258 //
259 // Skip encoding the aces, and the kings are encoded with less bits.
260 const int top_rank_for_iter = get_top_rank_for_iter(local_variant);
261 for (int rank = 2; rank <= top_rank_for_iter; ++rank)
262 {
263 for (int suit_idx = 0; suit_idx < FCS_NUM_SUITS; ++suit_idx)
264 {
265 const unsigned long opt =
266 (unsigned long)RS_STATE((fcs_card)rank, (fcs_card)suit_idx);
267 unsigned long base;
268
269 if (IS_BAKERS_DOZEN())
270 {
271 const_AUTO(card, fcs_card2char(fcs_make_card(
272 (fcs_card)rank, (fcs_card)suit_idx)));
273
274 if (self->bakers_dozen_topmost_cards_lookup[card >> 3] &
275 (1 << (card & (8 - 1))))
276 {
277 continue;
278 }
279 base = NUM__BAKERS_DOZEN__OPTS;
280 }
281 else
282 {
283 base = ((rank == RANK_KING) ? NUM_KING_OPTS : NUM_OPTS);
284 }
285
286 assert(opt < base);
287
288 fc_solve_var_base_writer_write(writer, base, opt);
289 }
290 }
291 }
292
delta_stater__fill_column_with_descendent_cards(fcs_delta_stater * const self,const fcs_dbm_variant_type local_variant,fcs_cards_column * const col)293 static inline void delta_stater__fill_column_with_descendent_cards(
294 fcs_delta_stater *const self, const fcs_dbm_variant_type local_variant,
295 fcs_cards_column *const col)
296 {
297 fcs_card parent_card = fcs_col_get_card(*col, fcs_col_len(*col) - 1);
298
299 while (fcs_card_is_valid(parent_card))
300 {
301 const int wanted_opt =
302 (IS_BAKERS_DOZEN() ? wanted_suit_idx_opt(parent_card)
303 : wanted_suit_bit_opt(parent_card));
304
305 fcs_card child_card = fc_solve_empty_card;
306 const int candidate_rank = fcs_card_rank(parent_card) - 1;
307 for (int suit = (IS_BAKERS_DOZEN()
308 ? 0
309 : ((fcs_card_suit(parent_card) & (0x1)) ^ 0x1));
310 suit < FCS_NUM_SUITS; suit += (IS_BAKERS_DOZEN() ? 1 : 2))
311 {
312 const fcs_card candidate_card =
313 fcs_make_card((fcs_card)candidate_rank, (fcs_card)suit);
314
315 if (CARD_STATE(candidate_card) == wanted_opt)
316 {
317 child_card = candidate_card;
318 break;
319 }
320 }
321
322 if (fcs_card_is_valid(child_card))
323 {
324 fcs_col_push_card(*col, child_card);
325 }
326 parent_card = child_card;
327 }
328 }
329
fc_solve_delta_stater_decode(fcs_delta_stater * const self,const fcs_dbm_variant_type local_variant,fcs_var_base_reader * const reader,fcs_state * const ret)330 static void fc_solve_delta_stater_decode(fcs_delta_stater *const self,
331 const fcs_dbm_variant_type local_variant, fcs_var_base_reader *const reader,
332 fcs_state *const ret)
333 {
334 fcs_card new_top_most_cards[MAX_NUM_STACKS];
335
336 fc_solve_delta_stater__init_card_states(self);
337
338 for (int suit_idx = 0; suit_idx < FCS_NUM_SUITS; ++suit_idx)
339 {
340 const unsigned long foundation_rank =
341 fc_solve_var_base_reader_read(reader, FOUNDATION_BASE);
342
343 for (unsigned long rank = 1; rank <= foundation_rank; ++rank)
344 {
345 RS_STATE((fcs_card)rank, (fcs_card)suit_idx) = OPT_IN_FOUNDATION;
346 }
347
348 fcs_set_foundation(*ret, suit_idx, foundation_rank);
349 }
350
351 #define IS_IN_FOUNDATIONS(card) \
352 (fcs_card_rank(card) <= fcs_foundation_value(*ret, fcs_card_suit(card)))
353
354 fcs_state *const init_state = self->init_state;
355
356 const int orig_pos_opt =
357 (IS_BAKERS_DOZEN() ? OPT__BAKERS_DOZEN__ORIG_POS : OPT_ORIG_POS);
358
359 #if MAX_NUM_FREECELLS > 0
360 const_SLOT(num_freecells, self);
361 #endif
362
363 bool orig_top_most_cards[CARD_ARRAY_LEN] = {false};
364 for (size_t col_idx = 0; col_idx < self->num_columns; ++col_idx)
365 {
366 const_AUTO(col, fcs_state_get_col(*init_state, col_idx));
367
368 if (fcs_col_len(col))
369 {
370 orig_top_most_cards[CARD_POS(fcs_col_get_card(col, 0))] = true;
371 }
372 }
373
374 // Process the kings:
375 if (IS_BAKERS_DOZEN())
376 {
377 for (int suit_idx = 0; suit_idx < FCS_NUM_SUITS; ++suit_idx)
378 {
379 const fcs_card card = fcs_make_card(RANK_KING, (fcs_card)suit_idx);
380
381 if (!IS_IN_FOUNDATIONS(card))
382 {
383 SET_CARD_STATE(card, OPT__BAKERS_DOZEN__ORIG_POS);
384 }
385 }
386 }
387
388 #if MAX_NUM_FREECELLS > 0
389 int next_freecell_idx = 0;
390 #endif
391 int next_new_top_most_cards = 0;
392 const int top_rank_for_iter = get_top_rank_for_iter(local_variant);
393 for (int rank = 1; rank <= top_rank_for_iter; ++rank)
394 {
395 for (int suit_idx = 0; suit_idx < FCS_NUM_SUITS; ++suit_idx)
396 {
397 const fcs_card card =
398 fcs_make_card((fcs_card)rank, (fcs_card)suit_idx);
399 const_AUTO(card_char, fcs_card2char(card));
400
401 if (IS_BAKERS_DOZEN())
402 {
403 if ((self->bakers_dozen_topmost_cards_lookup[card_char >> 3] &
404 (1 << (card_char & (8 - 1)))))
405 {
406 if (!IS_IN_FOUNDATIONS(card))
407 {
408 SET_CARD_STATE(card, OPT__BAKERS_DOZEN__ORIG_POS);
409 }
410 continue;
411 }
412 }
413
414 const int existing_opt =
415 RS_STATE((fcs_card)rank, (fcs_card)suit_idx);
416
417 if (rank == 1)
418 {
419 if (existing_opt < 0)
420 {
421 RS_STATE((fcs_card)rank, (fcs_card)suit_idx) = orig_pos_opt;
422 }
423 }
424 else
425 {
426 const unsigned long base =
427 (IS_BAKERS_DOZEN()
428 ? NUM__BAKERS_DOZEN__OPTS
429 : ((rank == RANK_KING) ? NUM_KING_OPTS : NUM_OPTS));
430 const unsigned long item_opt =
431 fc_solve_var_base_reader_read(reader, base);
432
433 if (existing_opt < 0)
434 {
435 RS_STATE((fcs_card)rank, (fcs_card)suit_idx) =
436 (int)item_opt;
437
438 if (!IS_BAKERS_DOZEN())
439 {
440 if (item_opt == OPT_FREECELL)
441 {
442 #if MAX_NUM_FREECELLS > 0
443 fcs_put_card_in_freecell(
444 *ret, next_freecell_idx, card);
445 ++next_freecell_idx;
446 #endif
447 }
448 else if (item_opt == OPT_TOPMOST)
449 {
450 if (!orig_top_most_cards[CARD_POS(card)])
451 {
452 new_top_most_cards[next_new_top_most_cards++] =
453 card;
454 }
455 }
456 }
457 }
458 }
459 }
460 }
461
462 #if MAX_NUM_FREECELLS > 0
463 for (; next_freecell_idx < num_freecells; ++next_freecell_idx)
464 {
465 fcs_empty_freecell(*ret, next_freecell_idx);
466 }
467 #endif
468
469 for (size_t col_idx = 0; col_idx < self->num_columns; ++col_idx)
470 {
471 fcs_card top_card;
472 int top_opt;
473
474 fcs_cards_column col = fcs_state_get_col(*ret, col_idx);
475 const_AUTO(orig_col, fcs_state_get_col(*init_state, col_idx));
476 const_AUTO(orig_col_len, fcs_col_len(orig_col));
477
478 if (orig_col_len)
479 {
480 top_card = fcs_col_get_card(orig_col, 0);
481 top_opt = CARD_STATE(top_card);
482 }
483 else
484 {
485 top_card = fc_solve_empty_card;
486 top_opt = -1;
487 }
488
489 if (fcs_card_is_empty(top_card) ||
490 (!((top_opt == OPT_TOPMOST) || (top_opt == orig_pos_opt))))
491 {
492 if (next_new_top_most_cards > 0)
493 {
494 fcs_col_push_card(
495 col, new_top_most_cards[--next_new_top_most_cards]);
496
497 delta_stater__fill_column_with_descendent_cards(
498 self, local_variant, &col);
499 }
500 }
501 else
502 {
503 fcs_col_push_card(col, top_card);
504 var_AUTO(parent_card, top_card);
505 for (int pos = 1; pos < orig_col_len; ++pos)
506 {
507 const fcs_card child_card = fcs_col_get_card(orig_col, pos);
508
509 if ((!IS_IN_FOUNDATIONS(child_card)) &&
510 (CARD_STATE(child_card) ==
511 calc_child_card_option(local_variant, parent_card,
512 child_card PASS_ON_NOT_FC_ONLY(
513 self->sequences_are_built_by))))
514 {
515 fcs_col_push_card(col, child_card);
516 parent_card = child_card;
517 }
518 else
519 {
520 break;
521 }
522 }
523
524 delta_stater__fill_column_with_descendent_cards(
525 self, local_variant, &col);
526 }
527 }
528 #undef IS_IN_FOUNDATIONS
529 }
530 #undef IS_BAKERS_DOZEN
531
fc_solve_delta_stater_decode_into_state_proto(const fcs_dbm_variant_type local_variant,fcs_delta_stater * const delta_stater,const rin_uchar * const enc_state,fcs_state_keyval_pair * const ret IND_BUF_T_PARAM (indirect_stacks_buffer))532 static inline void fc_solve_delta_stater_decode_into_state_proto(
533 const fcs_dbm_variant_type local_variant,
534 fcs_delta_stater *const delta_stater, const rin_uchar *const enc_state,
535 fcs_state_keyval_pair *const ret IND_BUF_T_PARAM(indirect_stacks_buffer))
536 {
537 fc_solve_var_base_reader_start(
538 &(delta_stater->r), enc_state, sizeof(fcs_encoded_state_buffer));
539
540 fc_solve_state_init(ret, STACKS_NUM, indirect_stacks_buffer);
541
542 fc_solve_delta_stater_decode(
543 delta_stater, local_variant, &(delta_stater->r), &(ret->s));
544 }
545
fc_solve_delta_stater_encode_into_buffer(fcs_delta_stater * const delta_stater,const fcs_dbm_variant_type local_variant,fcs_state_keyval_pair * const state,unsigned char * const out_enc_state)546 static inline void fc_solve_delta_stater_encode_into_buffer(
547 fcs_delta_stater *const delta_stater,
548 const fcs_dbm_variant_type local_variant,
549 fcs_state_keyval_pair *const state, unsigned char *const out_enc_state)
550 {
551 fc_solve_var_base_writer_start(&(delta_stater->w));
552 fc_solve_delta_stater_set_derived(delta_stater, &(state->s));
553 fc_solve_delta_stater_encode_composite(
554 delta_stater, local_variant, &(delta_stater->w));
555 fc_solve_var_base_writer_get_data(&(delta_stater->w), out_enc_state);
556 }
557 #endif
558