flutter-kotlin/triple_triad/test/triple_triad_game.dart

543 lines
14 KiB
Dart
Raw Normal View History

2025-10-05 22:51:24 +02:00
import 'package:flutter/material.dart';
import 'dart:math';
void main() {
runApp(const TripleTriadApp());
}
class TripleTriadApp extends StatelessWidget {
const TripleTriadApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Triple Triad',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.purple),
useMaterial3: true,
),
home: const GameScreen(),
);
}
}
class Card {
final String name;
final int top;
final int right;
final int bottom;
final int left;
final Color color;
final String owner;
Card({
required this.name,
required this.top,
required this.right,
required this.bottom,
required this.left,
required this.color,
this.owner = '',
});
Card copyWith({String? owner}) {
return Card(
name: name,
top: top,
right: right,
bottom: bottom,
left: left,
color: color,
owner: owner ?? this.owner,
);
}
}
class GameScreen extends StatefulWidget {
const GameScreen({super.key});
@override
State<GameScreen> createState() => _GameScreenState();
}
class _GameScreenState extends State<GameScreen> {
List<Card?> board = List.filled(9, null);
List<Card> playerHand = [];
List<Card> aiHand = [];
Card? selectedCard;
String currentPlayer = 'player';
int playerScore = 5;
int aiScore = 5;
bool gameOver = false;
final List<Card> allCards = [
Card(name: 'Dragon', top: 9, right: 6, bottom: 2, left: 8, color: Colors.red.shade700),
Card(name: 'Phoenix', top: 7, right: 7, bottom: 7, left: 2, color: Colors.orange.shade700),
Card(name: 'Ifrit', top: 9, right: 8, bottom: 2, left: 6, color: Colors.red.shade600),
Card(name: 'Shiva', top: 6, right: 7, bottom: 4, left: 9, color: Colors.blue.shade700),
Card(name: 'Bahamut', top: 9, right: 9, bottom: 6, left: 4, color: Colors.purple.shade700),
Card(name: 'Leviathan', top: 7, right: 5, bottom: 8, left: 7, color: Colors.blue.shade600),
Card(name: 'Odin', top: 8, right: 8, bottom: 5, left: 3, color: Colors.grey.shade700),
Card(name: 'Titan', top: 8, right: 4, bottom: 8, left: 6, color: Colors.brown.shade700),
Card(name: 'Ramuh', top: 4, right: 9, bottom: 5, left: 8, color: Colors.yellow.shade800),
Card(name: 'Carbuncle', top: 8, right: 4, bottom: 4, left: 8, color: Colors.green.shade700),
];
@override
void initState() {
super.initState();
_initGame();
}
void _initGame() {
final shuffled = List<Card>.from(allCards)..shuffle();
playerHand = shuffled.sublist(0, 5).map((c) => c.copyWith(owner: 'player')).toList();
aiHand = shuffled.sublist(5, 10).map((c) => c.copyWith(owner: 'ai')).toList();
board = List.filled(9, null);
selectedCard = null;
currentPlayer = 'player';
playerScore = 5;
aiScore = 5;
gameOver = false;
setState(() {});
}
void _selectCard(Card card) {
if (currentPlayer != 'player' || gameOver) return;
setState(() {
selectedCard = card;
});
}
void _placeCard(int position) {
if (board[position] != null || selectedCard == null || gameOver) return;
if (currentPlayer != 'player') return;
setState(() {
board[position] = selectedCard;
playerHand.remove(selectedCard);
selectedCard = null;
});
_checkCaptures(position, 'player');
_updateScore();
if (_isGameOver()) {
_endGame();
return;
}
currentPlayer = 'ai';
Future.delayed(const Duration(milliseconds: 800), _aiTurn);
}
void _aiTurn() {
if (aiHand.isEmpty || gameOver) return;
// Simple AI: find best move
int bestPosition = -1;
int bestCaptures = -1;
Card? bestCard;
for (var card in aiHand) {
for (int i = 0; i < 9; i++) {
if (board[i] == null) {
int captures = _simulateCaptures(i, card, 'ai');
if (captures > bestCaptures) {
bestCaptures = captures;
bestPosition = i;
bestCard = card;
}
}
}
}
if (bestCard != null && bestPosition != -1) {
setState(() {
board[bestPosition] = bestCard;
aiHand.remove(bestCard);
});
_checkCaptures(bestPosition, 'ai');
_updateScore();
if (_isGameOver()) {
_endGame();
return;
}
currentPlayer = 'player';
}
}
int _simulateCaptures(int position, Card card, String owner) {
int captures = 0;
final row = position ~/ 3;
final col = position % 3;
// Check top
if (row > 0) {
final topCard = board[position - 3];
if (topCard != null && topCard.owner != owner && card.top > topCard.bottom) {
captures++;
}
}
// Check right
if (col < 2) {
final rightCard = board[position + 1];
if (rightCard != null && rightCard.owner != owner && card.right > rightCard.left) {
captures++;
}
}
// Check bottom
if (row < 2) {
final bottomCard = board[position + 3];
if (bottomCard != null && bottomCard.owner != owner && card.bottom > bottomCard.top) {
captures++;
}
}
// Check left
if (col > 0) {
final leftCard = board[position - 1];
if (leftCard != null && leftCard.owner != owner && card.left > leftCard.right) {
captures++;
}
}
return captures;
}
void _checkCaptures(int position, String owner) {
final card = board[position]!;
final row = position ~/ 3;
final col = position % 3;
// Check top
if (row > 0) {
final topPos = position - 3;
final topCard = board[topPos];
if (topCard != null && topCard.owner != owner && card.top > topCard.bottom) {
board[topPos] = topCard.copyWith(owner: owner);
}
}
// Check right
if (col < 2) {
final rightPos = position + 1;
final rightCard = board[rightPos];
if (rightCard != null && rightCard.owner != owner && card.right > rightCard.left) {
board[rightPos] = rightCard.copyWith(owner: owner);
}
}
// Check bottom
if (row < 2) {
final bottomPos = position + 3;
final bottomCard = board[bottomPos];
if (bottomCard != null && bottomCard.owner != owner && card.bottom > bottomCard.top) {
board[bottomPos] = bottomCard.copyWith(owner: owner);
}
}
// Check left
if (col > 0) {
final leftPos = position - 1;
final leftCard = board[leftPos];
if (leftCard != null && leftCard.owner != owner && card.left > leftCard.right) {
board[leftPos] = leftCard.copyWith(owner: owner);
}
}
}
void _updateScore() {
int pScore = playerHand.length;
int aScore = aiHand.length;
for (var card in board) {
if (card != null) {
if (card.owner == 'player') pScore++;
else aScore++;
}
}
playerScore = pScore;
aiScore = aScore;
}
bool _isGameOver() {
return board.every((cell) => cell != null);
}
void _endGame() {
setState(() {
gameOver = true;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF1a1a2e),
appBar: AppBar(
title: const Text('Triple Triad'),
backgroundColor: const Color(0xFF16213e),
actions: [
IconButton(
icon: const Icon(Icons.refresh),
onPressed: _initGame,
),
],
),
body: SafeArea(
child: Column(
children: [
// AI Hand
Container(
height: 100,
padding: const EdgeInsets.all(8),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: aiHand.map((card) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: _buildMiniCard(card, false),
)).toList(),
),
),
// Score
Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildScoreCard('AI', aiScore, Colors.red.shade700),
_buildScoreCard('Player', playerScore, Colors.blue.shade700),
],
),
),
// Game Board
Expanded(
child: Center(
child: AspectRatio(
aspectRatio: 1,
child: Container(
padding: const EdgeInsets.all(16),
child: GridView.builder(
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
),
itemCount: 9,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () => _placeCard(index),
child: _buildBoardCell(board[index]),
);
},
),
),
),
),
),
// Player Hand
Container(
height: 120,
padding: const EdgeInsets.all(8),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: playerHand.map((card) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: GestureDetector(
onTap: () => _selectCard(card),
child: _buildHandCard(card, selectedCard == card),
),
)).toList(),
),
),
if (gameOver)
Container(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Text(
playerScore > aiScore ? 'You Win!' : playerScore < aiScore ? 'AI Wins!' : 'Draw!',
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
const SizedBox(height: 8),
ElevatedButton(
onPressed: _initGame,
child: const Text('New Game'),
),
],
),
),
],
),
),
);
}
Widget _buildScoreCard(String label, int score, Color color) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(8),
),
child: Column(
children: [
Text(
label,
style: const TextStyle(color: Colors.white, fontSize: 12),
),
Text(
'$score',
style: const TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
],
),
);
}
Widget _buildBoardCell(Card? card) {
if (card == null) {
return Container(
decoration: BoxDecoration(
color: const Color(0xFF0f3460),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.white24),
),
);
}
return _buildFullCard(card);
}
Widget _buildHandCard(Card card, bool selected) {
return Container(
width: 70,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: selected ? Colors.yellow : Colors.transparent,
width: 3,
),
),
child: _buildFullCard(card),
);
}
Widget _buildMiniCard(Card card, bool faceUp) {
return Container(
width: 50,
decoration: BoxDecoration(
color: faceUp ? card.color : Colors.grey.shade800,
borderRadius: BorderRadius.circular(6),
border: Border.all(color: Colors.white24),
),
);
}
Widget _buildFullCard(Card card) {
final isPlayerCard = card.owner == 'player';
return Container(
decoration: BoxDecoration(
color: isPlayerCard ? Colors.blue.shade700 : Colors.red.shade700,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.white24, width: 2),
),
child: Stack(
children: [
Center(
child: Text(
card.name,
style: const TextStyle(
color: Colors.white,
fontSize: 10,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
),
Positioned(
top: 4,
left: 0,
right: 0,
child: Center(
child: Text(
'${card.top}',
style: const TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
),
Positioned(
right: 4,
top: 0,
bottom: 0,
child: Center(
child: Text(
'${card.right}',
style: const TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
),
Positioned(
bottom: 4,
left: 0,
right: 0,
child: Center(
child: Text(
'${card.bottom}',
style: const TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
),
Positioned(
left: 4,
top: 0,
bottom: 0,
child: Center(
child: Text(
'${card.left}',
style: const TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
);
}
}