Skip to Content

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

Análisis oficial (C++) 

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)