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 // output_to_file.h - header file for outputting a solution to a file.
9 #pragma once
10 
11 #ifdef __cplusplus
12 extern "C" {
13 #endif
14 
15 #include "rinutils/rinutils.h"
16 #include "freecell-solver/fcs_enums.h"
17 #include "freecell-solver/fcs_user.h"
18 
19 typedef struct
20 {
21     const char *output_filename;
22     int standard_notation;
23     bool debug_iter_state_output;
24 #ifndef FC_SOLVE_IMPLICIT_PARSABLE_OUTPUT
25     bool parseable_output;
26 #endif
27     bool canonized_order_output;
28 #ifndef FC_SOLVE_IMPLICIT_T_RANK
29     bool display_10_as_t;
30 #endif
31     bool display_parent_iter_num;
32     bool display_moves;
33     bool display_states;
34     bool show_exceeded_limits;
35     bool hint_on_intract;
36     size_t iters_display_step;
37 } fc_solve_display_information_context;
38 
39 static const fc_solve_display_information_context INITIAL_DISPLAY_CONTEXT = {
40     .debug_iter_state_output = false,
41 #ifndef FC_SOLVE_IMPLICIT_PARSABLE_OUTPUT
42     .parseable_output = false,
43 #endif
44     .canonized_order_output = false,
45 #ifndef FC_SOLVE_IMPLICIT_T_RANK
46     .display_10_as_t = false,
47 #endif
48     .display_parent_iter_num = false,
49     .display_moves = false,
50     .display_states = true,
51     .standard_notation = FC_SOLVE__STANDARD_NOTATION_NO,
52     .output_filename = NULL,
53     .show_exceeded_limits = false,
54     .hint_on_intract = false,
55     .iters_display_step = 1,
56 };
57 
fc_solve_output_result_to_file(FILE * const output_fh,void * const instance,const int ret,const fc_solve_display_information_context * const dc_ptr)58 static inline void fc_solve_output_result_to_file(FILE *const output_fh,
59     void *const instance, const int ret,
60     const fc_solve_display_information_context *const dc_ptr)
61 {
62     const_AUTO(display_context, (*dc_ptr));
63     const bool was_solved = (ret == FCS_STATE_WAS_SOLVED);
64     const bool was_suspend = (ret == FCS_STATE_SUSPEND_PROCESS);
65 #ifdef FCS_WITH_MOVES
66     if (was_solved || (display_context.hint_on_intract && was_suspend))
67     {
68         fputs("-=-=-=-=-=-=-=-=-=-=-=-\n\n", output_fh);
69         fcs_move_t move;
70         char state_as_string[1000];
71 
72         if (display_context.display_states)
73         {
74             freecell_solver_user_current_state_stringify(instance,
75                 state_as_string FC_SOLVE__PASS_PARSABLE(
76                     display_context.parseable_output),
77                 display_context.canonized_order_output FC_SOLVE__PASS_T(
78                     display_context.display_10_as_t));
79 
80             fputs(state_as_string, output_fh);
81             fputs("\n\n====================\n\n", output_fh);
82         }
83 
84         int move_num = 0;
85         while (freecell_solver_user_get_next_move(instance, &move) == 0)
86         {
87             if (display_context.display_moves)
88             {
89                 if (display_context.display_states &&
90                     display_context.standard_notation)
91                 {
92                     fputs("Move: ", output_fh);
93                 }
94 
95                 freecell_solver_user_stringify_move_w_state(instance,
96                     state_as_string, move, display_context.standard_notation);
97                 fprintf(output_fh,
98                     (display_context.standard_notation ? "%s " : "%s\n"),
99                     state_as_string);
100                 move_num++;
101                 if (display_context.standard_notation)
102                 {
103                     if ((move_num % 10 == 0) || display_context.display_states)
104                     {
105                         putc('\n', output_fh);
106                     }
107                 }
108                 if (display_context.display_states)
109                 {
110                     putc('\n', output_fh);
111                 }
112                 fflush(output_fh);
113             }
114 
115             if (display_context.display_states)
116             {
117                 freecell_solver_user_current_state_stringify(instance,
118                     state_as_string FC_SOLVE__PASS_PARSABLE(
119                         display_context.parseable_output),
120                     display_context.canonized_order_output FC_SOLVE__PASS_T(
121                         display_context.display_10_as_t));
122 
123                 fprintf(output_fh, "%s\n", state_as_string);
124             }
125 
126             if (display_context.display_states ||
127                 (!display_context.standard_notation))
128             {
129                 fputs("\n====================\n\n", output_fh);
130             }
131         }
132 
133         if (display_context.standard_notation &&
134             (!display_context.display_states))
135         {
136             fputs("\n\n", output_fh);
137         }
138     }
139 #endif
140     fputs((was_solved ? "This game is solveable.\n"
141                       : (display_context.show_exceeded_limits && was_suspend)
142                             ? "Iterations count exceeded.\n"
143                             : "I could not solve this game.\n"),
144         output_fh);
145 
146     fprintf(output_fh, "Total number of states checked is %ld.\n",
147         (long)freecell_solver_user_get_num_times_long(instance));
148 #ifndef FCS_DISABLE_NUM_STORED_STATES
149     fprintf(output_fh, "This scan generated %ld states.\n",
150         (long)freecell_solver_user_get_num_states_in_collection_long(instance));
151 #endif
152 }
153 
154 #ifdef __cplusplus
155 }
156 #endif
157