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_impl.h - "delta states" are an encoding of states, where the
9 // states are encoded and decoded based on a compact delta from the initial
10 // state.
11 #include "delta_states_iface.h"
12 #include "delta_states.h"
13 
14 #ifndef FCS_DEBONDT_DELTA_STATES
fc_solve_get_column_orig_num_cards(fcs_delta_stater * const self GCC_UNUSED,const fcs_const_cards_column col)15 static stack_i fc_solve_get_column_orig_num_cards(
16     fcs_delta_stater *const self GCC_UNUSED, const fcs_const_cards_column col)
17 {
18     FCS_ON_NOT_FC_ONLY(const_SLOT(sequences_are_built_by, self));
19     for (stack_i num_cards = fcs_col_len(col); num_cards >= 2; --num_cards)
20     {
21         if (!fcs_is_parent_card(fcs_col_get_card(col, num_cards - 1),
22                 fcs_col_get_card(col, num_cards - 2)))
23         {
24             return num_cards;
25         }
26     }
27     return 0;
28 }
29 
fc_solve_delta_stater_init(fcs_delta_stater * const self,const fcs_dbm_variant_type local_variant GCC_UNUSED,fcs_state * const init_state,const size_t num_columns,const size_t num_freecells PASS_ON_NOT_FC_ONLY (const int sequences_are_built_by))30 static void fc_solve_delta_stater_init(fcs_delta_stater *const self,
31     const fcs_dbm_variant_type local_variant GCC_UNUSED,
32     fcs_state *const init_state, const size_t num_columns,
33     const size_t num_freecells PASS_ON_NOT_FC_ONLY(
34         const int sequences_are_built_by))
35 {
36     FCS_ON_NOT_FC_ONLY(self->sequences_are_built_by = sequences_are_built_by);
37     self->num_columns = num_columns;
38     self->num_freecells = num_freecells;
39     self->init_state = init_state;
40 
41     stack_i max_num_cards = 0;
42     for (size_t col_idx = 0; col_idx < num_columns; ++col_idx)
43     {
44         const_AUTO(num_cards, fc_solve_get_column_orig_num_cards(self,
45                                   fcs_state_get_col(*init_state, col_idx)));
46 
47         if (num_cards > max_num_cards)
48         {
49             max_num_cards = num_cards;
50         }
51     }
52 
53     {
54         stack_i bitmask = 1;
55         stack_i num_bits = 0;
56 
57         while (bitmask <= max_num_cards)
58         {
59             ++num_bits;
60             bitmask <<= 1;
61         }
62 
63         self->bits_per_orig_cards_in_column = num_bits;
64     }
65 }
66 
fc_solve_delta_stater_release(fcs_delta_stater * const self GCC_UNUSED)67 static inline void fc_solve_delta_stater_release(
68     fcs_delta_stater *const self GCC_UNUSED)
69 {
70 }
71 
72 typedef struct
73 {
74     enum
75     {
76         COL_TYPE_EMPTY,
77         COL_TYPE_ENTIRELY_NON_ORIG,
78         COL_TYPE_HAS_ORIG
79     } type;
80     rin_uchar enc[4];
81     rin_uchar *end;
82     size_t bit_in_char_idx;
83 } fcs_column_encoding_composite;
84 
fc_solve_get_column_encoding_composite(fcs_delta_stater * const self,const stack_i col_idx,fcs_column_encoding_composite * const ret)85 static inline void fc_solve_get_column_encoding_composite(
86     fcs_delta_stater *const self, const stack_i col_idx,
87     fcs_column_encoding_composite *const ret)
88 {
89     const fcs_state *const derived = self->derived_state;
90     const_AUTO(col, fcs_state_get_col(*derived, col_idx));
91 
92     const_AUTO(num_orig_cards, fc_solve_get_column_orig_num_cards(self, col));
93     const stack_i col_len = fcs_col_len(col);
94     const stack_i num_derived_cards = col_len - num_orig_cards;
95 
96     stack_i num_cards_in_seq = num_derived_cards;
97     fcs_card init_card = fc_solve_empty_card;
98 
99     if ((num_orig_cards == 0) && num_derived_cards)
100     {
101         init_card = fcs_col_get_card(col, 0);
102         --num_cards_in_seq;
103     }
104 
105     // Prepare the encoding.
106     rin_bit_writer bit_w;
107     rin_bit_writer_init_and_clear(&bit_w, ret->enc);
108 
109     rin_bit_writer_write(
110         &bit_w, self->bits_per_orig_cards_in_column, num_orig_cards);
111 
112     rin_bit_writer_write(&bit_w, 4, num_derived_cards);
113 
114     if (fcs_card_is_valid(init_card))
115     {
116         rin_bit_writer_write(&bit_w, 6, fcs_card2char(init_card));
117     }
118 
119     for (stack_i i = col_len - num_cards_in_seq; i < col_len; ++i)
120     {
121 #define GET_SUIT_BIT(card) (((fcs_card_suit(card)) & 0x2) >> 1)
122         rin_bit_writer_write(&bit_w, 1, GET_SUIT_BIT(fcs_col_get_card(col, i)));
123 #undef GET_SUIT_BIT
124     }
125 
126     ret->end = bit_w.current;
127     ret->bit_in_char_idx = bit_w.bit_in_char_idx;
128 
129     // Calculate the type.
130     ret->type = ((col_len == 0) ? COL_TYPE_EMPTY
131                                 : num_orig_cards ? COL_TYPE_HAS_ORIG
132                                                  : COL_TYPE_ENTIRELY_NON_ORIG);
133 }
134 
135 #if MAX_NUM_FREECELLS > 0
fc_solve_get_freecells_encoding(fcs_delta_stater * const self,rin_bit_writer * const bit_w)136 static inline void fc_solve_get_freecells_encoding(
137     fcs_delta_stater *const self, rin_bit_writer *const bit_w)
138 {
139     const fcs_state *const derived = self->derived_state;
140     const_SLOT(num_freecells, self);
141 
142     fcs_card freecells[MAX_NUM_FREECELLS];
143     for (size_t i = 0; i < num_freecells; ++i)
144     {
145         freecells[i] = fcs_freecell_card(*derived, i);
146     }
147 
148     // Sort the freecells using selection-sort.
149     for (size_t i = 0; i < num_freecells; ++i)
150     {
151         size_t min_idx = i;
152         for (size_t j = i + 1; j < num_freecells; ++j)
153         {
154             if (fcs_card2char(freecells[j]) < fcs_card2char(freecells[min_idx]))
155             {
156                 min_idx = j;
157             }
158         }
159         const_AUTO(i_card, freecells[i]);
160         rin_bit_writer_write(bit_w, 6,
161             fcs_card2char((min_idx != i) ? ({
162                 const_AUTO(min_card, freecells[min_idx]);
163                 freecells[min_idx] = i_card;
164                 min_card;
165             })
166                                          : i_card));
167     }
168 }
169 #endif
170 
fc_solve_delta__promote_empty_cols(const size_t num_columns,int * const cols_indexes,fcs_column_encoding_composite * const cols)171 static inline void fc_solve_delta__promote_empty_cols(const size_t num_columns,
172     int *const cols_indexes, fcs_column_encoding_composite *const cols)
173 {
174     size_t non_orig_idx = 0;
175     ssize_t empty_col_idx = (ssize_t)num_columns - 1;
176 
177     while (1)
178     {
179         for (; non_orig_idx < num_columns; ++non_orig_idx)
180         {
181             if (cols[non_orig_idx].type == COL_TYPE_ENTIRELY_NON_ORIG)
182             {
183                 break;
184             }
185         }
186 
187         if (non_orig_idx == num_columns)
188         {
189             break;
190         }
191 
192         for (; empty_col_idx >= 0; --empty_col_idx)
193         {
194             if (cols[empty_col_idx].type == COL_TYPE_EMPTY)
195             {
196                 break;
197             }
198         }
199 
200         if ((empty_col_idx < 0) || (empty_col_idx < (ssize_t)non_orig_idx))
201         {
202             break;
203         }
204 
205         const_AUTO(swap_int, cols_indexes[non_orig_idx]);
206         cols_indexes[non_orig_idx] = cols_indexes[empty_col_idx];
207         cols_indexes[empty_col_idx] = swap_int;
208 
209         ++non_orig_idx;
210         --empty_col_idx;
211     }
212 }
213 
fc_solve_delta_stater_encode_composite(fcs_delta_stater * const self,rin_bit_writer * const bit_w)214 static void fc_solve_delta_stater_encode_composite(
215     fcs_delta_stater *const self, rin_bit_writer *const bit_w)
216 {
217     int cols_indexes[MAX_NUM_STACKS];
218     fcs_column_encoding_composite cols[MAX_NUM_STACKS];
219     fcs_state *const derived = self->derived_state;
220 
221     const_SLOT(num_columns, self);
222     for (size_t i = 0; i < num_columns; ++i)
223     {
224         cols_indexes[i] = (int)i;
225         fc_solve_get_column_encoding_composite(self, i, &(cols[i]));
226     }
227 
228     // Move the empty columns to the front, but only within the
229     // entirely_non_orig
230     // That's because the orig columns should be preserved in their own
231     // place.
232     fc_solve_delta__promote_empty_cols(num_columns, cols_indexes, cols);
233 
234     int new_non_orig_cols_indexes[MAX_NUM_STACKS];
235     int new_non_orig_cols_indexes_count = 0;
236 
237     // Filter the new_non_orig_cols_indexes
238     for (size_t i = 0; i < num_columns; ++i)
239     {
240         if (cols[cols_indexes[i]].type == COL_TYPE_ENTIRELY_NON_ORIG)
241         {
242             new_non_orig_cols_indexes[new_non_orig_cols_indexes_count++] =
243                 cols_indexes[i];
244         }
245     }
246 
247 // Sort the new_non_orig_cols_indexes_count using insertion-sort.
248 #define COMP_BY(idx)                                                           \
249     (fcs_card2char(fcs_col_get_card(fcs_state_get_col((*derived), (idx)), 0)))
250 #define ITEM_IDX(idx) (new_non_orig_cols_indexes[idx])
251 #define COMP_BY_IDX(idx) (COMP_BY(ITEM_IDX(idx)))
252     for (int b = 1; b < new_non_orig_cols_indexes_count; ++b)
253     {
254         for (int c = b; (c > 0) && (COMP_BY_IDX(c - 1) > COMP_BY_IDX(c)); --c)
255         {
256             const_AUTO(swap_int, ITEM_IDX(c));
257             ITEM_IDX(c) = ITEM_IDX(c - 1);
258             ITEM_IDX(c - 1) = swap_int;
259         }
260     }
261 #undef COMP_BY_IDX
262 #undef ITEM_IDX
263 #undef COMP_BY
264 #undef b
265     for (size_t i = 0, sorted_idx = 0; i < num_columns; ++i)
266     {
267         if (cols[cols_indexes[i]].type == COL_TYPE_ENTIRELY_NON_ORIG)
268         {
269             cols_indexes[i] = new_non_orig_cols_indexes[sorted_idx++];
270         }
271     }
272 
273 #if MAX_NUM_FREECELLS > 0
274     fc_solve_get_freecells_encoding(self, bit_w);
275 #endif
276     for (size_t i = 0; i < num_columns; ++i)
277     {
278         const fcs_column_encoding_composite *const col_enc =
279             (cols + cols_indexes[i]);
280         const rin_uchar *enc;
281         const rin_uchar *const end = col_enc->end;
282         for (enc = col_enc->enc; enc < end; ++enc)
283         {
284             rin_bit_writer_write(bit_w, NUM_BITS_IN_BYTES, (*enc));
285         }
286         rin_bit_writer_write(bit_w, col_enc->bit_in_char_idx, (*enc));
287     }
288 }
289 
290 // ret must be an empty state.
fc_solve_delta_stater_decode(fcs_delta_stater * const self,rin_bit_reader * const bit_r,fcs_state * const ret)291 static void fc_solve_delta_stater_decode(fcs_delta_stater *const self,
292     rin_bit_reader *const bit_r, fcs_state *const ret)
293 {
294 #define PROCESS_CARD(card)                                                     \
295     if (fcs_card_rank(card) < foundations[fcs_card_suit(card)])                \
296     {                                                                          \
297         foundations[fcs_card_suit(card)] = fcs_card_rank(card);                \
298     }
299 
300     const_SLOT(bits_per_orig_cards_in_column, self);
301 
302     int foundations[4] = {14, 14, 14, 14};
303     // Read the Freecells.
304 
305 #if MAX_NUM_FREECELLS > 0
306     const_SLOT(num_freecells, self);
307     for (size_t i = 0; i < num_freecells; ++i)
308     {
309         const fcs_card card =
310             fcs_char2card((fcs_card)rin_bit_reader_read(bit_r, 6));
311         if (fcs_card_is_valid(card))
312         {
313             PROCESS_CARD(card);
314         }
315         fcs_put_card_in_freecell(*ret, i, card);
316     }
317 #endif
318 
319     const_SLOT(num_columns, self);
320     const fcs_state *const init_state = self->init_state;
321 
322     for (size_t col_idx = 0; col_idx < num_columns; ++col_idx)
323     {
324         const_AUTO(col, fcs_state_get_col(*ret, col_idx));
325         const stack_i num_orig_cards =
326             rin_bit_reader_read(bit_r, bits_per_orig_cards_in_column);
327         const_AUTO(orig_col, fcs_state_get_col(*init_state, col_idx));
328 
329         for (stack_i i = 0; i < num_orig_cards; ++i)
330         {
331             const fcs_card card = fcs_col_get_card(orig_col, i);
332             PROCESS_CARD(card);
333             fcs_col_push_card(col, card);
334         }
335 
336         const stack_i num_derived_cards = rin_bit_reader_read(bit_r, 4);
337         uint_fast16_t num_cards_in_seq = num_derived_cards;
338 
339         if ((num_orig_cards == 0) && num_derived_cards)
340         {
341             const fcs_card card =
342                 fcs_char2card((fcs_card)rin_bit_reader_read(bit_r, 6));
343             PROCESS_CARD(card);
344             fcs_col_push_card(col, card);
345 
346             --num_cards_in_seq;
347         }
348 
349         if (num_cards_in_seq)
350         {
351             fcs_card last_card = fcs_col_get_card(col, fcs_col_len(col) - 1);
352 
353             for (uint_fast16_t i = 0; i < num_cards_in_seq; ++i)
354             {
355                 const stack_i suit_bit = rin_bit_reader_read(bit_r, 1);
356                 const fcs_card new_card =
357                     fcs_make_card(fcs_card_rank(last_card) - 1,
358                         (fcs_card)((((size_t)suit_bit) << 1U) |
359                                    ((fcs_card_suit(last_card) & 0x1U) ^ 0x1U)));
360 
361                 PROCESS_CARD(new_card);
362                 fcs_col_push_card(col, new_card);
363 
364                 last_card = new_card;
365             }
366         }
367     }
368 
369     for (int i = 0; i < 4; ++i)
370     {
371         fcs_set_foundation(*ret, i, foundations[i] - 1);
372     }
373 
374 #undef PROCESS_CARD
375 }
376 
fc_solve_delta_stater_decode_into_state_proto(const fcs_dbm_variant_type local_variant GCC_UNUSED,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))377 static inline void fc_solve_delta_stater_decode_into_state_proto(
378     const fcs_dbm_variant_type local_variant GCC_UNUSED,
379     fcs_delta_stater *const delta_stater, const rin_uchar *const enc_state,
380     fcs_state_keyval_pair *const ret IND_BUF_T_PARAM(indirect_stacks_buffer))
381 {
382     rin_bit_reader bit_r;
383     rin_bit_reader_init(&bit_r, enc_state + 1);
384     fc_solve_state_init(ret, STACKS_NUM, indirect_stacks_buffer);
385     fc_solve_delta_stater_decode(delta_stater, &bit_r, &(ret->s));
386 }
387 
fc_solve_delta_stater_encode_into_buffer(fcs_delta_stater * const delta_stater,const fcs_dbm_variant_type local_variant GCC_UNUSED,fcs_state_keyval_pair * const state,unsigned char * const out_enc_state)388 static inline void fc_solve_delta_stater_encode_into_buffer(
389     fcs_delta_stater *const delta_stater,
390     const fcs_dbm_variant_type local_variant GCC_UNUSED,
391     fcs_state_keyval_pair *const state, unsigned char *const out_enc_state)
392 {
393     rin_bit_writer bit_w;
394     rin_bit_writer_init_and_clear(&bit_w, out_enc_state + 1);
395     fc_solve_delta_stater_set_derived(delta_stater, &(state->s));
396     fc_solve_delta_stater_encode_composite(delta_stater, &bit_w);
397     out_enc_state[0] = (unsigned char)(bit_w.current - bit_w.start +
398                                        (bit_w.bit_in_char_idx > 0));
399 }
400 #endif
401