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