// Arup Guha
// 3/7/2026
// Sodoku Example for Quiz 3 Review

import java.util.*;
import java.io.*;

public class Sudoku {

	final private static int N = 9;
	final private static int BOX = 3;
	
	private int[][] grid;
	private boolean[][] canEdit;
	private int numLeft;
	
	// Pre-requisite: initial is 9 by 9 only stores integers 0 through 9.
	public Sudoku(int[][] initial) {
	
		// Allocate space.
		grid = new int[N][N];
		canEdit = new boolean[N][N];
		numLeft = 0;
		
		// Fill it. Update all of our instance variables accordingly.
		for (int i=0; i<N; i++) {
			for(int j=0; j<N; j++) {
				grid[i][j] = initial[i][j];
				canEdit[i][j] = (grid[i][j] == 0);
				if (canEdit[i][j]) numLeft++;
			}
		}
	}
	
	// Returns true if there is no value on row r equal to v and
	// the square on row r, column c is currently unfilled.	
	// 0 <= r,c <= 8
	private boolean canPlaceOnRow(int r, int c, int v) {
		
		// Can't fill this square.
		if (grid[r][c] != 0) return false;
	
		// Look for v on this row, if we find it, it's not allowed.
		for (int i=0; i<N; i++) 
			if (grid[r][i] == v)
				return false;
		
		// We're good if we get here.
		return true;
	}

	// Returns true if there is no value on column c equal to v and
	// the square on row r, column c is currently unfilled.
	// 0 <= r,c <= 8
	private boolean canPlaceOnCol(int r, int c, int v) {
		
		// Can't fill this square because it's filled.
		if (grid[r][c] != 0) return false;
		
		// Look for v on this column.
		for (int i=0; i<N; i++)
			if (grid[i][c] == v)
				return false;
			
		// If we get here we're good.
		return true;
	}

	// Returns true if there is no value in the 3 x 3 box of
	// row r, column c that contains v and that square is currently
	// unfilled, 0 <= r <= c
	private boolean canPlaceInBox(int r, int c, int v) {
		
		// Can't fill this square because it's filled.
		if (grid[r][c] != 0) return false;
		
		// Figure out top left row and column of this box.
		int sR = (r/BOX)*BOX;
		int sC = (c/BOX)*BOX;
		
		// Look in this box for value v.
		for (int i=sR; i<sR+BOX; i++)
			for (int j=sC; j<sC+BOX; j++)
				if (grid[i][j] == v)
					return false;
		
		// If we get here we didn't find it so we're good.
		return true;
		
	}

	// Returns true if it's possible to place v in location row r,
	// column c, false otherwise.
	public boolean canPlace(int r, int c, int v) {
		
		// Let's just verify this here!
		if (v<1 || v>9) return false;
		
		// Now we can do this.
		return canPlaceOnRow(r,c,v) && canPlaceOnCol(r,c,v) && canPlaceInBox(r,c,v);
	}
	
	// Erases the temporary value placed in location row r, col c,
	// returns false if this is an unerasable value and also returns
	// false if there was no value filled in the square to begin
	// with. Returns true otherwise and resets value in row r col c
	// to 0.
	public boolean undo(int r, int c) {
		
		// Can't undo a forced square or one that doesn't have anything.
		if (!canEdit[r][c] || grid[r][c] == 0) return false;
		
		// Undo it!
		grid[r][c] = 0;
		numLeft++;
		return true;
	}
	
	// Attempts to place value v in row r, column c. Returns true
	// if successful and false otherwise.
	public boolean place(int r, int c, int v) {
		
		// Sorry can't do it.
		if (!canPlace(r,c,v)) return false;
		
		// Ta da!
		grid[r][c] = v;
		numLeft--;
		return true;
	}
	
	// Returns true iff all squares
	public boolean win() {
		return numLeft == 0;
	}
	
	// Returns a string representation of the this object.
	public String toString() {
		
		String res = "";
		for (int i=0; i<N; i++) {
			String row = "";
			for (int j=0; j<N; j++) {
				if (grid[i][j] != 0)
					row = row + grid[i][j] + " ";
				else
					row = row + "_ ";
			}
			res = res + row + "\n";
		}
			
		return res;
	}
	
	public static void main(String[] args) throws Exception {
		
		Scanner fin = new Scanner(new File("sudoku.in"));
		int[][] g = new int[N][N];
		for (int i=0; i<N; i++)
			for (int j=0; j<N; j++)
				g[i][j] = fin.nextInt();
		fin.close();
		
		/*** Commands: 1 r c v, places value v in row r, col c, 1-based entries
		               2 r c, undoes the placement in row r, col c
		***/
			
		// Create new object.
		Sudoku mypuzzle = new Sudoku(g);
		
		Scanner stdin = new Scanner(System.in);
		System.out.println(mypuzzle);
		
		while (!mypuzzle.win()) {
			
			// Get this operation.
			int op = stdin.nextInt();
			int r = stdin.nextInt()-1;
			int c = stdin.nextInt()-1;
			int v = 0;
			if (op == 1) v = stdin.nextInt();
			
			// Try to add a number to a square.
			if (op == 1) {
				boolean tmp = mypuzzle.place(r,c,v);
				if (tmp) System.out.println("Successful placement.");
				else System.out.println("Placement failed.");
			}
			
			// Try to erase a number from a square.
			else {
				boolean tmp = mypuzzle.undo(r,c);
				if (tmp) System.out.println("Successful erasure.");
				else System.out.println("Undo failed.");
			}
			
			// Print the board.
			System.out.println(mypuzzle);
		}
	}
	
}