/* Improved bicycle program. Ask: ?-partlist( bike ). */


basicpart( rim ).
basicpart( rearframe ).
basicpart( gears ).
basicpart( nut ).
basicpart( spoke ).
basicpart( handles ).
basicpart( bolt ).
basicpart( fork ).

assembly( bike, [quant( wheel, 2 ), quant( frame, 1 )] ).
assembly( wheel, [quant( spoke, 20 ), quant( rim, 1 ), quant( hub, 1)] ).
assembly( frame, [quant( rearframe, 1), quant( frontframe, 1 ) ] ).
assembly( frontframe, [quant( fork, 1 ), quant( handles, 1 )] ).
assembly( hub, [quant( gears, 1 ), quant( bolt, 7 ), quant( axle, 1 ) ] ).
assembly( axle, [quant( bolt, 1 ), quant( nut, 2) ] ).

partlist( T ) :- partsof( 1, T, P ), collect( P, Q ),
  printpartlist( Q ).

partsof( N, X, P ) :- assembly( X, S ), partsoflist( N, S, P ).
partsof( N,X,[quant(X,N)]) :- basicpart( X ).

partsoflist( _, [], [] ).
partsoflist( N, [quant( X, Num) | L ], T ) :-
  M is N * Num,
  partsof( M, X, Xparts ),
  partsoflist( N, L, Restparts ),
  append( Xparts, Restparts, T ).

collect( [], [] ).
collect( [quant(X, N )|R], [quant( X, Ntotal)|R2] ) :-
  collectrest( X, N, R, O, Ntotal ),
  collect( O, R2 ).

collectrest( _, N, [], [], N ).
collectrest( X, N, [quant( X, Num)|Rest ], Others, Ntotal ) :-
  !,
  M is N + Num,
  collectrest( X, M, Rest, Others, Ntotal ).
collectrest( X,N,[Other|Rest],[Other|Others],Ntotal ) :-
  collectrest( X, N, Rest, Others, Ntotal ).

printpartlist( [] ).
printpartlist( [quant( X, N )|R] ) :- nl,
  print( '    ' ), print( N ), print( '     ' ),
  print( X ), printpartlist( R ).

append( [], L, L ).
append( [X|L1], L2, [X|L3] ) :- append( L1, L2, L3 ).



