Team Tic Tac Toe
Solución en video
Por Jay Fu
Video de YouTube (eEQzCy5CBDs)
Código de la solución en video
#include <fstream>
#include <iostream>
using namespace std;
char B[3][3];
// ¿Gana 1 vaca?
int cow_wins(char ch) {
// Comprobamos diagonales
if (B[0][0] == ch && B[1][1] == ch && B[2][2] == ch) return 1;
if (B[0][2] == ch && B[1][1] == ch && B[2][0] == ch) return 1;
// Comprobamos filas y columnas
for (int i = 0; i < 3; i++) {
if (B[0][i] == ch && B[1][i] == ch && B[2][i] == ch) return 1;
if (B[i][0] == ch && B[i][1] == ch && B[i][2] == ch) return 1;
}
return 0;
}
// Comprueba si un equipo gana según 3 caracteres en una fila, columna o diagonal
bool check3(char ch1, char ch2, char a, char b, char c) {
// Los 3 caracteres tienen que ser ch1 o ch2
if (a != ch1 && a != ch2) return false;
if (b != ch1 && b != ch2) return false;
if (c != ch1 && c != ch2) return false;
// ch1 y ch2 tienen que aparecer al menos una vez cada uno
if (a != ch1 && b != ch1 && c != ch1) return false;
if (a != ch2 && b != ch2 && c != ch2) return false;
return true;
}
// ¿Gana un equipo?
int team_wins(char ch1, char ch2) {
// Comprobamos diagonales
if (check3(ch1, ch2, B[0][0], B[1][1], B[2][2])) return 1;
if (check3(ch1, ch2, B[0][2], B[1][1], B[2][0])) return 1;
// Comprobamos filas y columnas
for (int i = 0; i < 3; i++) {
if (check3(ch1, ch2, B[0][i], B[1][i], B[2][i])) return 1;
if (check3(ch1, ch2, B[i][0], B[i][1], B[i][2])) return 1;
}
return 0;
}
int main(void) {
ifstream fin("tttt.in");
ofstream fout("tttt.out");
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++) fin >> B[i][j];
int answer1 = 0, answer2 = 0;
for (char ch = 'A'; ch <= 'Z'; ch++) answer1 += cow_wins(ch);
for (char ch1 = 'A'; ch1 <= 'Z'; ch1++)
for (char ch2 = ch1 + 1; ch2 <= 'Z'; ch2++) answer2 += team_wins(ch1, ch2);
fout << answer1 << "\n" << answer2 << "\n";
return 0;
}import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
public class tttt {
static char[][] B = new char[3][3];
// ¿Gana 1 vaca?
static int cow_wins(char ch) {
// Comprobamos diagonales
if (B[0][0] == ch && B[1][1] == ch && B[2][2] == ch) return 1;
if (B[0][2] == ch && B[1][1] == ch && B[2][0] == ch) return 1;
// Comprobamos filas y columnas
for (int i = 0; i < 3; i++) {
if (B[0][i] == ch && B[1][i] == ch && B[2][i] == ch) return 1;
if (B[i][0] == ch && B[i][1] == ch && B[i][2] == ch) return 1;
}
return 0;
}
// Comprueba si un equipo gana según 3 caracteres en una fila, columna o diagonal
static boolean check3(char ch1, char ch2, char a, char b, char c) {
// Los 3 caracteres tienen que ser ch1 o ch2
if (a != ch1 && a != ch2) return false;
if (b != ch1 && b != ch2) return false;
if (c != ch1 && c != ch2) return false;
// ch1 y ch2 tienen que aparecer al menos una vez cada uno
if (a != ch1 && b != ch1 && c != ch1) return false;
if (a != ch2 && b != ch2 && c != ch2) return false;
return true;
}
// ¿Gana un equipo?
static int team_wins(char ch1, char ch2) {
// Comprobamos diagonales
if (check3(ch1, ch2, B[0][0], B[1][1], B[2][2])) return 1;
if (check3(ch1, ch2, B[0][2], B[1][1], B[2][0])) return 1;
// Comprobamos filas y columnas
for (int i = 0; i < 3; i++) {
if (check3(ch1, ch2, B[0][i], B[1][i], B[2][i])) return 1;
if (check3(ch1, ch2, B[i][0], B[i][1], B[i][2])) return 1;
}
return 0;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("tttt.in"));
PrintWriter out = new PrintWriter("tttt.out");
for (int i = 0; i < 3; i++) {
String str = br.readLine();
for (int j = 0; j < 3; j++) { B[i][j] = str.charAt(j); }
}
int answer1 = 0, answer2 = 0;
for (char ch = 'A'; ch <= 'Z'; ch++) { answer1 += cow_wins(ch); }
for (char ch1 = 'A'; ch1 <= 'Z'; ch1++) {
for (char ch2 = (char)(ch1 + 1); ch2 <= 'Z'; ch2++) {
answer2 += team_wins(ch1, ch2);
}
}
out.println(answer1);
out.println(answer2);
out.close();
}
}Solución 1
Pista 1
Consideremos todas las formas posibles en que una letra puede conseguir tres en línea, y cómo comprobarlas todas.
Pista 2
¿Cuáles son todas las formas posibles en que dos vacas pueden formar equipo, y cómo comprobaríamos si ese emparejamiento es una victoria?
Respuesta a la Pista 2
Se puede emparejar cualquier letra (A…Z) con cualquier otra letra.
Solución 1
#include <bits/stdc++.h>
using namespace std;
// comprueba si la vaca ch ganó en alguna fila, columna o diagonal
bool check_single_cow_winner(char ch, const vector<string> &board) {
for (int i = 0; i < 3; i++) {
// comprobamos filas
if (board[i][0] == ch && board[i][1] == ch && board[i][2] == ch) {
return true;
}
// comprobamos columnas
if (board[0][i] == ch && board[1][i] == ch && board[2][i] == ch) {
return true;
}
}
// comprobamos diagonales
if (board[0][0] == ch && board[1][1] == ch && board[2][2] == ch) { return true; }
if (board[0][2] == ch && board[1][1] == ch && board[2][0] == ch) { return true; }
return false;
}
// determinamos la cantidad de victorias individuales de vacas
int individual_wins(const vector<string> &board) {
int single_cow_wins = 0;
for (char ch = 'A'; ch <= 'Z'; ch++) {
single_cow_wins += check_single_cow_winner(ch, board);
}
return single_cow_wins;
}
// comprueba si ambas vacas ch1 y ch2 están en la fila/columna/diagonal que estamos revisando.
bool check_if_winners(char ch1, char ch2, char x, char y, char z) {
if (x == y && x != z) {
if (x == ch1 && z == ch2) { return true; }
if (x == ch2 && z == ch1) { return true; }
} else if (x == z && x != y) {
if (x == ch1 && y == ch2) { return true; }
if (x == ch2 && y == ch1) { return true; }
} else if (y == z && x != y) {
if (y == ch1 && x == ch2) { return true; }
if (y == ch2 && x == ch1) { return true; }
}
return false;
}
// comprueba si las vacas ch1 y ch2 pueden ganar en alguna de las filas, columnas o
// diagonales
bool check_double_cow_winners(char ch1, char ch2, const vector<string> &board) {
for (int i = 0; i < 3; i++) {
// comprobamos filas
if (check_if_winners(ch1, ch2, board[i][0], board[i][1], board[i][2])) {
return true;
}
// comprobamos columnas
if (check_if_winners(ch1, ch2, board[0][i], board[1][i], board[2][i])) {
return true;
}
}
// comprobamos diagonales
if (check_if_winners(ch1, ch2, board[0][0], board[1][1], board[2][2])) {
return true;
}
if (check_if_winners(ch1, ch2, board[0][2], board[1][1], board[2][0])) {
return true;
}
return false;
}
// determinamos la cantidad de victorias de equipos
int team_wins(const vector<string> &board) {
int double_cow_wins = 0;
for (char ch1 = 'A'; ch1 <= 'Z'; ch1++) {
for (char ch2 = ch1 + 1; ch2 <= 'Z'; ch2++) {
double_cow_wins += check_double_cow_winners(ch1, ch2, board);
}
}
return double_cow_wins;
}
int main() {
freopen("tttt.in", "r", stdin);
freopen("tttt.out", "w", stdout);
vector<string> board(3);
for (int i = 0; i < 3; i++) { cin >> board[i]; }
int individual_cows = individual_wins(board);
int team_cows = team_wins(board);
cout << individual_cows << endl;
cout << team_cows << endl;
}import java.io.*;
import java.util.*;
public class TeamTicTacToe {
static char[][] board = new char[3][3];
// ¿Gana 1 vaca?
static boolean cowWins(char ch) {
// Comprobamos diagonales
if (board[0][0] == ch && board[1][1] == ch && board[2][2] == ch) {
return true;
}
if (board[0][2] == ch && board[1][1] == ch && board[2][0] == ch) {
return true;
}
// Comprobamos filas y columnas
for (int i = 0; i < 3; i++) {
if (board[0][i] == ch && board[1][i] == ch && board[2][i] == ch) {
return true;
}
if (board[i][0] == ch && board[i][1] == ch && board[i][2] == ch) {
return true;
}
}
return false;
}
// Comprueba si un equipo gana según 3 caracteres en una fila, columna o diagonal
static boolean check3(char ch1, char ch2, char a, char b, char c) {
// Los 3 caracteres tienen que ser ch1 o ch2
if (a != ch1 && a != ch2) { return false; }
if (b != ch1 && b != ch2) { return false; }
if (c != ch1 && c != ch2) { return false; }
// ch1 y ch2 tienen que aparecer al menos una vez cada uno
if (a != ch1 && b != ch1 && c != ch1) { return false; }
if (a != ch2 && b != ch2 && c != ch2) { return false; }
return true;
}
// ¿Gana un equipo?
static boolean teamWins(char ch1, char ch2) {
// Comprobamos diagonales
if (check3(ch1, ch2, board[0][0], board[1][1], board[2][2])) { return true; }
if (check3(ch1, ch2, board[0][2], board[1][1], board[2][0])) { return true; }
// Y también comprobamos filas y columnas
for (int i = 0; i < 3; i++) {
if (check3(ch1, ch2, board[0][i], board[1][i], board[2][i])) {
return true;
}
if (check3(ch1, ch2, board[i][0], board[i][1], board[i][2])) {
return true;
}
}
return false;
}
public static void main(String[] args) throws IOException {
Kattio io = new Kattio("tttt");
for (int i = 0; i < 3; i++) {
String line = io.next();
for (int j = 0; j < 3; j++) { board[i][j] = line.charAt(j); }
}
int singleWins = 0;
for (char ch = 'A'; ch <= 'Z'; ch++) { singleWins += cowWins(ch) ? 1 : 0; }
int doubleWins = 0;
for (char ch1 = 'A'; ch1 <= 'Z'; ch1++) {
for (char ch2 = (char)((int)ch1 + 1); ch2 <= 'Z'; ch2++) {
doubleWins += teamWins(ch1, ch2) ? 1 : 0;
}
}
io.println(singleWins + "\n" + doubleWins);
io.close();
}
// CodeSnip{Kattio}
}from typing import List
with open("tttt.in") as read:
board = [read.readline() for _ in range(3)]
# ¿Gana 1 vaca?
def cow_wins(game: List[str], cow: str) -> bool:
# Comprobamos diagonales
if (
game[0][0] == game[1][1] == game[2][2] == cow
or game[0][2] == game[1][1] == game[2][0] == cow
):
return True
# Comprobamos filas y columnas
for i in range(3):
if (
game[0][i] == game[1][i] == game[2][i] == cow
or game[i][0] == game[i][1] == game[i][2] == cow
):
return True
return False
# ¿Gana un equipo?
def team_wins(game: List[str], cow1: str, cow2: str) -> bool:
# Comprueba si un equipo gana según 3 caracteres en una fila, columna o diagonal
def check3(a: str, b: str, c: str) -> bool:
# Los 3 caracteres tienen que ser cow1 o cow2
if a != cow1 and a != cow2:
return False
if b != cow1 and b != cow2:
return False
if c != cow1 and c != cow2:
return False
# cow1 y cow2 tienen que aparecer al menos una vez cada una
if a != cow1 and b != cow1 and c != cow1:
return False
if a != cow2 and b != cow2 and c != cow2:
return False
return True
# Comprobamos diagonales como con una sola vaca
if check3(game[0][0], game[1][1], game[2][2]) or check3(
game[0][2], game[1][1], game[2][0]
):
return True
# Y también comprobamos filas y columnas
for i in range(3):
if check3(game[0][i], game[1][i], game[2][i]) or check3(
game[i][0], game[i][1], game[i][2]
):
return True
return False
single_wins = 0
for c in range(ord("A"), ord("Z") + 1):
single_wins += cow_wins(board, chr(c))
double_wins = 0
for c1 in range(ord("A"), ord("Z") + 1):
for c2 in range(c1 + 1, ord("Z") + 1):
double_wins += team_wins(board, chr(c1), chr(c2))
with open("tttt.out", "w") as written:
print(single_wins, file=written)
print(double_wins, file=written)Solución 2
Usando conjuntos
#include <bits/stdc++.h>
using namespace std;
const int WIDTH = 3;
vector<string> board(WIDTH);
set<set<char>> winners[WIDTH + 1];
void insert(vector<pair<int, int>> coordinates) {
set<char> contained;
for (const pair<int, int> &p : coordinates) {
contained.insert(board[p.first][p.second]);
}
// sumamos la cantidad de vacas que contribuyeron a esto al conteo de ganadoras
winners[contained.size()].insert(contained);
}
int main() {
ifstream read("tttt.in");
for (int r = 0; r < WIDTH; r++) { read >> board[r]; }
// insertamos filas
for (int i = 0; i < WIDTH; i++) { insert({{i, 0}, {i, 1}, {i, 2}}); }
// insertamos columnas
for (int i = 0; i < WIDTH; i++) { insert({{0, i}, {1, i}, {2, i}}); }
// insertamos las 2 diagonales
insert({{0, 0}, {1, 1}, {2, 2}});
insert({{2, 0}, {1, 1}, {0, 2}});
ofstream written("tttt.out");
written << winners[1].size() << endl;
written << winners[2].size() << endl;
}import java.io.*;
import java.util.*;
public class TeamTicTacToe {
private static char[][] gameboard = new char[3][3];
private static Set<Character> singleCow = new TreeSet<>();
private static Set<String> teams = new TreeSet<>();
private static void check(char first, char second, char third) {
// Guarda las vacas únicas en una fila/columna/diagonal
TreeSet<Character> contained = new TreeSet<>();
contained.add(first);
contained.add(second);
contained.add(third);
if (contained.size() == 1) {
// Hay solo una vaca única
singleCow.add(contained.first());
} else if (contained.size() == 2) {
// Hay dos vacas únicas
teams.add(contained.first() + "" + contained.last());
}
}
public static void main(String[] args) throws IOException {
Kattio io = new Kattio("tttt");
for (int i = 0; i < gameboard.length; i++) {
String line = io.next();
gameboard[i][0] = line.charAt(0);
gameboard[i][1] = line.charAt(1);
gameboard[i][2] = line.charAt(2);
}
// Comprobamos filas
for (int i = 0; i < gameboard.length; i++) {
check(gameboard[i][0], gameboard[i][1], gameboard[i][2]);
}
// Comprobamos columnas
for (int i = 0; i < gameboard.length; i++) {
check(gameboard[0][i], gameboard[1][i], gameboard[2][i]);
}
// Comprobamos diagonales
check(gameboard[0][0], gameboard[1][1], gameboard[2][2]);
check(gameboard[0][2], gameboard[1][1], gameboard[2][0]);
io.println(singleCow.size());
io.println(teams.size());
io.close();
}
// CodeSnip{Kattio}
}from typing import List, Tuple, Set
WIDTH = 3
def cow_contrib(game: List[str], pts: List[Tuple[int, int]]) -> Set[str]:
contained = set()
for pt in pts:
contained.add(game[pt[0]][pt[1]])
return contained
with open("tttt.in") as read:
board = [read.readline() for _ in range(WIDTH)]
winners = [set() for _ in range(WIDTH + 1)]
# Función que agrega un equipo ganador al arreglo winners
insert = lambda c: winners[len(c)].add(tuple(sorted(c)))
# Insertamos todas las filas
for r in range(WIDTH):
insert(cow_contrib(board, [(r, c) for c in range(WIDTH)]))
# Hacemos lo mismo para las columnas
for c in range(WIDTH):
insert(cow_contrib(board, [(r, c) for r in range(WIDTH)]))
# Y por último las diagonales
insert(cow_contrib(board, [(i, i) for i in range(WIDTH)]))
insert(cow_contrib(board, [(i, WIDTH - i - 1) for i in range(WIDTH)]))
with open("tttt.out", "w") as written:
print(len(winners[1]), file=written)
print(len(winners[2]), file=written)