■単に制約するだけではなく、予定シフトを読み込んでエラーを出力させています。
予定シフトのエラーが検出を行い、制約エンジンに行く前にエラーを表示させることが出来ます。
別な応用としては、予定シフトとスタッフプロパティを読み込んで、予定シフトが書き込まれていないときに限り、スタッフプロパティによるDefaultシフトを書き込むことが考えられます。
ソフト制約を使えば静的には、実現可能ですが、動的に判断した方が、余計なソフトエラーはなくなりメンテナンス性が良くなる場合もあります。

import sc3

def 半代休設定():
    for person in 全スタッフ:
        vlist=[]
        s='言語公休回数'+' '+staffdef[person]+'\n'
        土WORKCNT=[]
        日WORKCNT=[]
        代CNT=[]
        半CNT=[]

        for day in 今月:
            v=sc3.GetShiftVar(person,day,'訪問')
            vD=sc3.GetShiftVar(person,day,'代休')
            vH=sc3.GetShiftVar(person,day,'半休')
            if day in 土:
                土WORKCNT.append(v)
                sc3.AddHard(~vD,'土曜日は代休なし'+str(person))
                sc3.AddHard(~vH,'土曜日は半休なし'+str(person))
            elif day in 日:
                日WORKCNT.append(v)
                sc3.AddHard(~vD,'日曜日は代休なし'+str(person))
                sc3.AddHard(~vH,'日曜日は半休なし'+str(person))
            else:
                代CNT.append(vD)
                半CNT.append(vH)
            vlist.append(v)
        sc3.AddHard(sc3.SeqComp(半CNT,土WORKCNT),'seqComp+str(person)')
        sc3.AddHard(sc3.SeqComp(代CNT,日WORKCNT),'seqComp+str(person)')


        

def 訪問3日連続チェック():
    for person in 全スタッフ:
        for day in 全日:
            if day<制約開始日:
                continue

            ts=shift_schedules[person][day][0]#予定シフトを読み取る タプル1は、ソフトレベル
            tsy=shift_schedules[person][day-1][0]#予定シフトを読み取る タプル1は、ソフトレベル
            tsyy=shift_schedules[person][day-2][0]#予定シフトを読み取る タプル1は、ソフトレベル

            s='3連続訪問禁止'+staffdef[person] +' '+ daydef[day] +'\n'
            if  ts=='訪問' and  tsy=='訪問' and tsyy=='訪問':
                sc3.print( '*****3連続訪問エラーがあります。'+s)#エラー出力
            x0=sc3.GetShiftVar(person,day,'訪問')
            x1=sc3.GetShiftVar(person,day-1,'訪問')
            x2=sc3.GetShiftVar(person,day-2,'訪問')
            
            sc3.AddHard(~x0 | ~x1 | ~x2,s)#ハード制約  3連続訪問禁止
        

半代休設定()
訪問3日連続チェック()