/* Golf puzzle in Picat. http://blogs.sas.com/content/operations/2016/03/03/golf-puzzle/ """ Here's a golf puzzle from Sam Loyd: Everybody is playing golf now, and even the lazy ones who a few weeks ago declared how much pleasanter it was to swing in a shady hammock, have caught the golf fever and are chasing the ball around the golf links. I am not much of a golfer, but I have met a genius who has a winning system based on mathematics. He says: "Just cultivate two strokes of different lengths, one a drive, the other an approach, and play directly toward the hole so that a combination of the two distances will get you there." What should be the proper lengths of strokes to learn that would make possible the lowest score on a nine-hole course, of 150 yards, 300 yards, 250 yards, 325 yards, 275 yards, 350 yards, 225 yards, 400 yards, and 425 yards? The ball must go the full length on each stroke, but you may go beyond the hole with either stroke, then play back toward the hole. All strokes are on a straight line toward the hole. """ Here are the two optimal solutions with number of strokes = 26: z = 26 All optimal: club1 = 125 club2 = 150 1: 0 1 2: 0 2 3: 2 0 4: -1 3 5: 1 1 6: 4 -1 7: 3 -1 8: 2 1 9: 1 2 club1 = 75 club2 = 175 1: 2 0 2: 4 0 3: 1 1 4: 2 1 5: -1 2 6: 0 2 7: 3 0 8: 3 1 9: 1 2 This Picat model was created by Hakan Kjellerstrand, hakank@gmail.com See also my Picat page: http://www.hakank.org/picat/ */ import cp. main => go. go => Data = [150,300,250,325,275,350,225,400,425], N = Data.len, golf(Data, Z,Club1,Club2,Holes), println(z=Z), println(club1=Club1), println(club2=Club2), nl, foreach(I in 1..N) printf("%2d: %3d %3d\n", I, Holes[I,1],Holes[I,2]) end, nl. go2 ?=> Data = [150,300,250,325,275,350,225,400,425], golf(Data, Z,_Club1,_Club2,_Holes), println(z=Z), println("All optimal:"), golf(Data, Z, Club1,Club2,Holes2), println(club1=Club1), println(club2=Club2), nl, foreach(I in 1..Data.len) printf("%2d: %3d %3d\n", I, Holes2[I,1],Holes2[I,2]) end, nl, fail, nl. go2 => true. golf(Data, Z,Club1,Club2,Holes) => N = Data.len, % decision variables Club1 :: 1..1000, % = 75, Club2 :: 1..1000, % = 175, % number of swings with each club for each hole Holes = new_array(N,2), Holes :: -10..10, % symmetry breaking Club1 #<= Club2, foreach(I in 1..N) Data[I] #= Holes[I,1]*Club1 + Holes[I,2]*Club2 end, Z #= sum([abs(Holes[I,J]) : I in 1..N, J in 1..2]), % Vars = [Club1,Club2] ++ Holes.vars(), Vars = Holes.vars() ++ [Club1,Club2], if var(Z) then solve($[ffd,updown,min(Z)],Vars) else solve($[ffd,updown],Vars) end.