001package ball.riddler538.ant.taskdefs;
002/*-
003 * ##########################################################################
004 * Solutions for the 538 Riddler
005 * %%
006 * Copyright (C) 2015 - 2022 Allen D. Ball
007 * %%
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *      http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 * ##########################################################################
020 */
021import ball.util.ant.taskdefs.AntTask;
022import java.util.ArrayList;
023import java.util.Arrays;
024import java.util.List;
025import java.util.Random;
026import lombok.NoArgsConstructor;
027import lombok.ToString;
028import org.apache.tools.ant.BuildException;
029
030/**
031 * {@link.uri http://ant.apache.org/ Ant} {@link org.apache.tools.ant.Task}
032 * to solve
033 * {@link.uri
034 * http://fivethirtyeight.com/features/how-long-will-your-smartphone-distract-you-from-family-dinner/
035 * How Long Will Your Smartphone Distract You From Family Dinner?}
036 * <p>
037 * You’ve just finished unwrapping your holiday presents. You and your
038 * sister got brand-new smartphones, opening them at the same moment. You
039 * immediately both start doing important tasks on the Internet, and each
040 * task you do takes one to five minutes. (All tasks take exactly one, two,
041 * three, four or five minutes, with an equal probability of each). After
042 * each task, you have a brief moment of clarity. During these, you remember
043 * that you and your sister are supposed to join the rest of the family for
044 * dinner and that you promised each other you’d arrive together. You ask if
045 * your sister is ready to eat, but if she is still in the middle of a task,
046 * she asks for time to finish it. In that case, you now have time to kill,
047 * so you start a new task (again, it will take one, two, three, four or
048 * five minutes, exactly, with an equal probability of each). If she asks
049 * you if it’s time for dinner while you’re still busy, you ask for time to
050 * finish up and she starts a new task and so on. From the moment you first
051 * open your gifts, how long on average does it take for both of you to be
052 * between tasks at the same time so you can finally eat? (You can assume
053 * the “moments of clarity” are so brief as to take no measurable time at
054 * all.)
055 * </p>
056 * Solution uses the Monte Carlo method.
057 *
058 * {@ant.task}
059 *
060 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball}
061 */
062@AntTask("solve-riddle-2015-12-22")
063@NoArgsConstructor @ToString
064public class SolveRiddle20151222Task extends AbstractSimulationTask {
065    @Override
066    public void execute() throws BuildException {
067        super.execute();
068
069        try {
070            ArrayList<Try> tries = new ArrayList<>(getCount());
071
072            for (int i = 0, n = getCount(); i < n; i += 1) {
073                tries.add(new Try());
074            }
075
076            int min = tries.get(0).duration();
077            int max = tries.get(0).duration();
078            int sum = 0;
079
080            for (Try tryN : tries) {
081                int duration = tryN.duration();
082
083                min = Math.min(min, duration);
084                max = Math.max(max, duration);
085                sum += duration;
086            }
087
088            log("count: " + tries.size());
089            log("min: " + min);
090            log("max: " + max);
091            log("average: " + (((float) sum) / tries.size()));
092        } catch (BuildException exception) {
093            throw exception;
094        } catch (Throwable throwable) {
095            throwable.printStackTrace();
096            throw new BuildException(throwable);
097        }
098    }
099
100    private static final Random RANDOM = new Random();
101    private static final List<Integer> DURATIONS =
102        Arrays.asList(1, 2, 3, 4 ,5);
103
104    @ToString
105    private class Try {
106        private List<Integer> you = new ArrayList<>();
107        private List<Integer> sister = new ArrayList<>();
108
109        public Try() {
110            for (;;) {
111                if (sum(you) < sum(sister)) {
112                    you.add(DURATIONS.get(RANDOM.nextInt(DURATIONS.size())));
113                } else {
114                    sister.add(DURATIONS.get(RANDOM.nextInt(DURATIONS.size())));
115                }
116
117                if (sum(you) == sum(sister)) {
118                    break;
119                }
120            }
121        }
122
123        public int duration() { return sum(you); }
124
125        private int sum(List<Integer> list) {
126            int total = 0;
127
128            for (Integer element : list) {
129                total += element;
130            }
131
132            return total;
133        }
134    }
135}