package main
import (
"bufio"
"fmt"
"os"
)
type Grid struct {
a [4][4]bool
}
func (g *Grid) canPlaceVert(r, c int) bool {
if r < 0 || r > 2 || c < 0 || c > 3 {
return false
}
return !g.a[r][c] && !g.a[r+1][c]
}
func (g *Grid) canPlaceHori(r, c int) bool {
if r < 0 || r > 3 || c < 0 || c > 2 {
return false
}
return !g.a[r][c] && !g.a[r][c+1]
}
func (g *Grid) placeVert(r, c int) {
g.a[r][c] = true
g.a[r+1][c] = true
g.clearFull()
}
func (g *Grid) placeHori(r, c int) {
g.a[r][c] = true
g.a[r][c+1] = true
g.clearFull()
}
func (g *Grid) clearFull() {
fullRow := [4]bool{}
fullCol := [4]bool{}
for i := 0; i < 4; i++ {
fullRow[i] = true
for j := 0; j < 4; j++ {
if !g.a[i][j] {
fullRow[i] = false
break
}
}
}
for j := 0; j < 4; j++ {
fullCol[j] = true
for i := 0; i < 4; i++ {
if !g.a[i][j] {
fullCol[j] = false
break
}
}
}
for i := 0; i < 4; i++ {
for j := 0; j < 4; j++ {
if fullRow[i] || fullCol[j] {
g.a[i][j] = false
}
}
}
}
func main() {
in := bufio.NewReader(os.Stdin)
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
var s string
fmt.Fscan(in, &s)
g := &Grid{}
// Priority lists that tend to create clears quickly and avoid overlaps.
// Vertical priorities: use columns 1 and 3 (0-idx: 0 and 2), rows 1 and 3 (0-idx: 0 and 2)
vCandidates := [][2]int{{0, 0}, {2, 0}, {0, 2}, {2, 2}}
// Horizontal priorities: use rows 1 and 3 (0-idx: 0 and 2), columns 1 and 3 (0-idx: 0 and 2)
hCandidates := [][2]int{{0, 0}, {0, 2}, {2, 0}, {2, 2}}
for _, ch := range s {
if ch == '0' {
placed := false
// Try priority candidates first
for _, p := range vCandidates {
r, c := p[0], p[1]
if g.canPlaceVert(r, c) {
g.placeVert(r, c)
fmt.Fprintln(out, r+1, c+1)
placed = true
break
}
}
// Fallback: try all positions
if !placed {
done := false
for r := 0; r <= 2 && !done; r++ {
for c := 0; c < 4 && !done; c++ {
if g.canPlaceVert(r, c) {
g.placeVert(r, c)
fmt.Fprintln(out, r+1, c+1)
done = true
placed = true
}
}
}
}
if !placed {
// Should not happen
fmt.Fprintln(out, 1, 1)
}
} else {
placed := false
// Try to place a horizontal that completes a row or a column first
// Check all positions to see if any completes a row/column; prefer those.
bestR, bestC := -1, -1
for r := 0; r < 4; r++ {
for c := 0; c <= 2; c++ {
if !g.canPlaceHori(r, c) {
continue
}
// simulate
g.a[r][c], g.a[r][c+1] = true, true
fullRow := true
for j := 0; j < 4; j++ {
if !g.a[r][j] {
fullRow = false
break
}
}
fullColL, fullColR := true, true
for i := 0; i < 4; i++ {
if !g.a[i][c] {
fullColL = false
}
if !g.a[i][c+1] {
fullColR = false
}
}
// revert
g.a[r][c], g.a[r][c+1] = false, false
if fullRow || fullColL || fullColR {
bestR, bestC = r, c
break
}
}
if bestR != -1 {
break
}
}
if bestR != -1 {
g.placeHori(bestR, bestC)
fmt.Fprintln(out, bestR+1, bestC+1)
placed = true
}
if !placed {
// Try priority candidates
for _, p := range hCandidates {
r, c := p[0], p[1]
if g.canPlaceHori(r, c) {
g.placeHori(r, c)
fmt.Fprintln(out, r+1, c+1)
placed = true
break
}
}
}
if !placed {
// Fallback: try all positions
done := false
for r := 0; r < 4 && !done; r++ {
for c := 0; c <= 2 && !done; c++ {
if g.canPlaceHori(r, c) {
g.placeHori(r, c)
fmt.Fprintln(out, r+1, c+1)
done = true
placed = true
}
}
}
}
if !placed {
// Should not happen
fmt.Fprintln(out, 1, 1)
}
}
}
}