実は、訓練期間が、下のようにブランクだと、右ペインに示されるようにエラーになってしまいます。
原因は、行制約で訓練期間では、2回夜勤を行うという制約をハード制約として記述したからです。
単純にソフト制約とすれば回避できますが、ソフトエラーとしてカウントされるのが面白くない、という方もおられでしょう。それが今日のテーマです。
訓練期間が定義されていないときは、制約そのものをDisableしてしまえばよい、という発想が浮かびます。下の最後の方、 夜勤新人Disable()が制約をDisableする記述です。僅か3行で済みます。
スタッフプロパティで夜勤新人を設定、上で期間設定を行う、ということをマニュアルに書いておけば、来年もまた使えます。
import sc3 def 夜勤回数設定sub(person): st=staffdef[person]+'夜勤回数を制約' sc3.print(st+'します。\n') max=-1 min=0 if person in 夜勤回数最大属性: max=夜勤回数最大属性[person] if person in 夜勤回数最小属性: min=夜勤回数最小属性[person] sc3.print(str(max)+str(min)+'\n') vlist=[] for day in 今月: v=sc3.GetShiftVar(person,day,'入り') vlist.append(v) sc3.AddSoft(sc3.SeqError(min,max,3,vlist),st,5) def 夜勤回数設定(): for person in 夜勤あり: 夜勤回数設定sub(person) def 公休数設定(): for person in 全スタッフ: max=-1 min=0 if person not in 公休数属性最大: continue st=staffdef[person]+'公休数を制約' sc3.print(st+'します。\n') if person in 公休数属性最大: max=公休数属性最大[person]#float if person in 公休数属性最小: min=公休数属性最小[person] max *=2 min *=2 if isinstance(max, float) and not max.is_integer(): sc3.print('公休数設定で、maxが整数型ではありません。') continue if isinstance(min, float) and not min.is_integer(): sc3.print('公休数設定で、minが整数型ではありません。') continue max =int(max) #float to int min =int(min) #float to int sc3.print(str(max)+str(min)+'\n') vlist=[] for day in 今月: v=sc3.GetShiftVar(person,day,'公休')#公休は2回分カウント vlist.append(v) vlist.append(v) v=sc3.GetShiftVar(person,day,'早半休')#早半休は1回 vlist.append(v) v=sc3.GetShiftVar(person,day,'半休')#半休は1回 vlist.append(v) sc3.AddSoft(sc3.SeqError(min,max,4,vlist),st,6) def 土曜以外の半休抑制(): for person in 全スタッフ: for day in 土曜でない今月: ts=shift_schedules[person][day][0] if ts !='半休': v=sc3.GetShiftVar(person,day,'半休') st=staffdef[person]+'土曜以外の半休抑制' sc3.AddSoft(~v,st,1) def 夜勤新人Disable(): if len(夜勤新人訓練期間)==0: sc3.ConstraintEnable('夜勤新人.夜勤新人は、夜勤訓練期間に2回訓練を行う',False) 夜勤回数設定() 公休数設定() 土曜以外の半休抑制() 夜勤新人Disable()
夜勤新人訓練期間がなくても意図通り動作しました。
期間を日月火水木にした例です。