I would create a structure called Washer as a User Data Type containing things like CycleState, DoorLockSol, ColdWaterSol, HotWaterSol, DetergentPump, etc. Then create a memory block with a size of 3, so you would have Washer0, Washer1, Washer2 (this way you don't use the one named 0, as that probably doesn't jive with what the operators call it). Possibly also create a UDT called Cycle, and contain things like ColdWaterSec, DetergentPumpSec, etc. Use this UDT to create Heap Items called FirstRinse, SecondRinse, etc.
Setup the Click PLC as a device in the Modbus I/O Scanner. Possibly only mapping your X and Y bits to bits you create in your UDT (this is in theory bad practice as you may want the Click PLC to have backup control over the outputs in event of a comm failure, etc).
Then you can make a FOR/NEXT loop, index V0, from 1 to 2. Then you can write rungs like: STR Washer[V0].StartButton AND Washer[V0].CycleState == Idle, COPY Start to Washer[V0].CycleState. This would allow the code to be identical, and the Washer[V0].Name bits/words would be mapped to each physical washer via the Modbus scanner tools.
A few caveats about FOR/NEXT loops is that you can't use timers nor edge bits in the rungs. You'll have to do workarounds like MATH UTC+FirstRinse.ColdWaterSec, create a block of LastScan bits, etc.