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) 2000 Shlomi Fish
8 // meta_move_funcs_helpers.h - header file of the move functions of Freecell
9 // Solver.
10 //
11 // The move functions code itself is found in freecell.c and simpsim.c.
12 #pragma once
13
14 #ifdef __cplusplus
15 extern "C" {
16 #endif
17
max0(const int e)18 static inline int max0(const int e) { return max(e, 0); }
19 #ifdef FCS_FREECELL_ONLY
20 #define calc_max_sequence_move(num_freecells, num_empty_cols) \
21 (((num_freecells) + 1) << (num_empty_cols))
22 #else
23 // The number of cards that can be moved is
24 // (freecells_number + 1) * 2 ^ (free_stacks_number)
25 //
26 // See the Freecell FAQ and the source code of PySol
27 #define calc_max_sequence_move(num_freecells, num_empty_cols) \
28 (INSTANCE_UNLIMITED_SEQUENCE_MOVE \
29 ? INT_MAX \
30 : ((empty_stacks_fill == FCS_ES_FILLED_BY_ANY_CARD) \
31 ? (((num_freecells) + 1) << (num_empty_cols)) \
32 : ((num_freecells) + 1)))
33
calc_max_simple_simon_seq_move(const int num_empty_cols)34 static inline size_t calc_max_simple_simon_seq_move(const int num_empty_cols)
35 {
36 return ((num_empty_cols < 0) ? 0 : (1 << num_empty_cols));
37 }
38 #endif
39
40 // These are some macros to make it easier for the programmer.
41 #define ptr_state_key (raw_state_raw.key)
42 #define ptr_new_state &(pass_new_state)
43 #define state_key (*ptr_state_key)
44 #define new_state_key (*(pass_new_state.key))
45
46 #define sfs_check_state_begin() \
47 fc_solve_sfs_check_state_begin(hard_thread, &pass_new_state, \
48 raw_state_raw SFS__PASS_MOVE_STACK(moves))
49
50 #ifdef FCS_HARD_CODE_REPARENT_STATES_AS_FALSE
51 #define sfs_check_state_end__arg
52 #else
53 #define sfs_check_state_end__arg raw_state_raw,
54 #endif
55
56 #define sfs_check_state_end() \
57 fc_solve_derived_states_list_add_state(derived_states_list, \
58 fc_solve_sfs_check_state_end(soft_thread, \
59 sfs_check_state_end__arg &pass_new_state FCS__pass_moves(moves)), \
60 state_context_value)
61
fc_solve_move_sequence_function(fcs_state * const s FCS__pass_moves (fcs_move_stack * const moves),const size_t dest_col_i,const size_t src_col_i,const size_t cards_num)62 static inline void fc_solve_move_sequence_function(
63 fcs_state *const s FCS__pass_moves(fcs_move_stack *const moves),
64 const size_t dest_col_i, const size_t src_col_i, const size_t cards_num)
65 {
66 fcs_col_transfer_cards(fcs_state_get_col(*s, dest_col_i),
67 fcs_state_get_col(*s, src_col_i), cards_num);
68 fcs_move_stack_params_push(
69 moves, FCS_MOVE_TYPE_STACK_TO_STACK, src_col_i, dest_col_i, cards_num);
70 }
71
72 #define fcs_move_sequence(to, from, cards_num) \
73 fc_solve_move_sequence_function( \
74 &(new_state_key)FCS__pass_moves(moves), to, from, cards_num)
75
76 #ifdef FCS_RCS_STATES
77
78 #define tests_define_accessors_rcs_states() \
79 fcs_state my_new_out_state_key; \
80 pass_new_state.key = &my_new_out_state_key
81
82 #else
83 #define tests_define_accessors_rcs_states()
84 #endif
85
86 #ifdef FCS_FREECELL_ONLY
87
88 #define tests_define_accessors_freecell_only() \
89 { \
90 }
91
92 #define tests__is_filled_by_any_card() true
93 #define IS_FILLED_BY_KINGS_ONLY() false
94 #define IS_FILLED_BY_NONE() false
95
96 #else
97
98 #ifdef FCS_SINGLE_HARD_THREAD
99 #define tests_define_accessors_freecell_only() \
100 fcs_instance *const instance = hard_thread;
101 #else
102 #define tests_define_accessors_freecell_only() \
103 fcs_instance *const instance = hard_thread->instance;
104 #endif
105
106 #define tests__is_filled_by_any_card() \
107 (empty_stacks_fill == FCS_ES_FILLED_BY_ANY_CARD)
108
109 #define IS_FILLED_BY_KINGS_ONLY() \
110 (empty_stacks_fill == FCS_ES_FILLED_BY_KINGS_ONLY)
111
112 #define IS_FILLED_BY_NONE() (empty_stacks_fill == FCS_ES_FILLED_BY_NONE)
113
114 #endif
115
116 #ifdef FCS_WITH_MOVES
117 #define tests_define_accessors_move_stack() \
118 fcs_move_stack *const moves = &(HT_FIELD(hard_thread, reusable_move_stack))
119 #else
120 #define tests_define_accessors_move_stack()
121 #endif
122
123 #define tests_state_context_val int state_context_value = 0;
124 // This macro defines these accessors to have some value.
125 #define tests_define_accessors_no_stacks(MORE) \
126 fcs_hard_thread *const hard_thread = soft_thread->hard_thread; \
127 tests_define_accessors_move_stack(); \
128 MORE fcs_kv_state pass_new_state; \
129 tests_define_accessors_freecell_only(); \
130 tests_define_accessors_rcs_states()
131
132 #ifdef INDIRECT_STACK_STATES
133 #define tests_define_indirect_stack_states_accessors() \
134 fcs_card *indirect_stacks_buffer = \
135 HT_FIELD(hard_thread, indirect_stacks_buffer);
136 #else
137 #define tests_define_indirect_stack_states_accessors()
138 #endif
139
140 #define tests_define_accessors__generic(MORE) \
141 tests_define_accessors_no_stacks(MORE); \
142 tests_define_indirect_stack_states_accessors()
143
144 #define tests_define_accessors() \
145 tests_define_accessors__generic(tests_state_context_val)
146 #define my_copy_stack(idx) \
147 fcs_copy_stack( \
148 new_state_key, *(pass_new_state.val), idx, indirect_stacks_buffer)
149 #define copy_two_stacks(idx1, idx2) \
150 my_copy_stack(idx1); \
151 my_copy_stack(idx2)
152
153 // This macro assists in implementing this prune:
154 //
155 // https://groups.yahoo.com/neo/groups/fc-solve-discuss/conversations/topics/1121
156 //
157 // There is no point in moving the last card in a
158 // column to a parent on a different column, because then the column won't
159 // be able to be filled, and will be left to disuse. Furthermore, after
160 // moved to a parent, the card might block other cards that can be placed
161 // on the parent.
162 //
163 // TODO : implement it for FCS_ES_FILLED_BY_KINGS_ONLY
164 #define MOVE_FUNCS__should_not_empty_columns() IS_FILLED_BY_NONE()
165
166 #define MOVE_FUNCS__define_common() \
167 tests_define_accessors(); \
168 MOVE_FUNCS__define_seqs_built_by(); \
169 MOVE_FUNCS__define_empty_stacks_fill()
170
171 #ifdef FCS_FREECELL_ONLY
172
173 #define MOVE_FUNCS__define_seqs_built_by()
174 #define MOVE_FUNCS__define_empty_stacks_fill()
175 #define PASS_sequences_are_built_by(param)
176 #include "pos_by_rank__freecell.h"
177 #define POS_BY_RANK_STEP (2)
178 #define FCS_POS_IDX_TO_CHECK_START_LOOP(src_card) \
179 const_AUTO(pos_pos, pos_by_rank__freecell[(int)src_card]); \
180 const int8_t *pos_idx_to_check = &positions_by_rank[pos_pos.start]; \
181 const int8_t *const last_pos_idx = &positions_by_rank[pos_pos.end]; \
182 \
183 for (; pos_idx_to_check < last_pos_idx; \
184 pos_idx_to_check += suit_positions_by_rank_step)
185
186 #else
187
188 #define MOVE_FUNCS__define_seqs_built_by() \
189 const int sequences_are_built_by = \
190 GET_INSTANCE_SEQUENCES_ARE_BUILT_BY(instance);
191 #define MOVE_FUNCS__define_empty_stacks_fill() \
192 const int empty_stacks_fill = INSTANCE_EMPTY_STACKS_FILL;
193 #define PASS_sequences_are_built_by(param) , param
194 #define POS_BY_RANK_STEP \
195 ((sequences_are_built_by == FCS_SEQ_BUILT_BY_RANK) \
196 ? 1 \
197 : (sequences_are_built_by == FCS_SEQ_BUILT_BY_SUIT) ? 4 : 2)
198 #define FCS_PROTO_CARD_SUIT_POSITIONS_BY_RANK_INITIAL_OFFSET(card) \
199 ((sequences_are_built_by == FCS_SEQ_BUILT_BY_RANK) \
200 ? 0 \
201 : (sequences_are_built_by == FCS_SEQ_BUILT_BY_SUIT) \
202 ? fcs_card_suit(card) \
203 : ((fcs_card_suit(card) ^ 0x1) & (0x2 - 1)))
204
205 #define FCS_POS_IDX_TO_CHECK_START_LOOP(src_card) \
206 const int8_t *pos_idx_to_check = &positions_by_rank[( \
207 FCS_POS_BY_RANK_WIDTH * (fcs_card_rank(src_card)))]; \
208 const int8_t *const last_pos_idx = \
209 pos_idx_to_check + FCS_POS_BY_RANK_WIDTH; \
210 \
211 for (pos_idx_to_check += POS_BY_RANK_MAP( \
212 FCS_PROTO_CARD_SUIT_POSITIONS_BY_RANK_INITIAL_OFFSET(src_card)); \
213 pos_idx_to_check < last_pos_idx; \
214 pos_idx_to_check += suit_positions_by_rank_step)
215
216 #endif
217
218 #define SET_empty_stack_idx(empty_stack_idx) \
219 stack_i empty_stack_idx; \
220 for (empty_stack_idx = 0; empty_stack_idx < LOCAL_STACKS_NUM; \
221 empty_stack_idx++) \
222 { \
223 if (fcs_state_col_is_empty(state_key, empty_stack_idx)) \
224 { \
225 break; \
226 } \
227 }
228
229 #define CALC_num_cards_in_col_threshold() \
230 (MOVE_FUNCS__should_not_empty_columns() ? 1 : 0)
231
232 #ifdef __cplusplus
233 }
234 #endif
235