From 929eeb15e68c1c9dc499eb0b8ce4bfe2af624476 Mon Sep 17 00:00:00 2001 From: Andreas Knuth Date: Fri, 6 Sep 2024 16:59:44 +0200 Subject: [PATCH] initial release --- src/app/app.component.html | 336 -------------------------------- src/app/app.component.scss | 0 src/app/app.component.spec.ts | 29 --- src/app/app.component.ts | 21 +- src/app/card-back.component.ts | 83 ++++++++ src/app/card-front.component.ts | 92 +++++++++ src/app/card.service.ts | 49 +++++ src/app/deck.component.ts | 49 +++++ src/app/game.component.ts | 184 +++++++++++++++++ src/styles.scss | 3 + 10 files changed, 474 insertions(+), 372 deletions(-) delete mode 100644 src/app/app.component.html delete mode 100644 src/app/app.component.scss delete mode 100644 src/app/app.component.spec.ts create mode 100644 src/app/card-back.component.ts create mode 100644 src/app/card-front.component.ts create mode 100644 src/app/card.service.ts create mode 100644 src/app/deck.component.ts create mode 100644 src/app/game.component.ts diff --git a/src/app/app.component.html b/src/app/app.component.html deleted file mode 100644 index 36093e1..0000000 --- a/src/app/app.component.html +++ /dev/null @@ -1,336 +0,0 @@ - - - - - - - - - - - -
-
-
- -

Hello, {{ title }}

-

Congratulations! Your app is running. 🎉

-
- -
-
- @for (item of [ - { title: 'Explore the Docs', link: 'https://angular.dev' }, - { title: 'Learn with Tutorials', link: 'https://angular.dev/tutorials' }, - { title: 'CLI Docs', link: 'https://angular.dev/tools/cli' }, - { title: 'Angular Language Service', link: 'https://angular.dev/tools/language-service' }, - { title: 'Angular DevTools', link: 'https://angular.dev/tools/devtools' }, - ]; track item.title) { - - {{ item.title }} - - - - - } -
- -
-
-
- - - - - - - - - - - diff --git a/src/app/app.component.scss b/src/app/app.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts deleted file mode 100644 index 3db5aed..0000000 --- a/src/app/app.component.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { AppComponent } from './app.component'; - -describe('AppComponent', () => { - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [AppComponent], - }).compileComponents(); - }); - - it('should create the app', () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - }); - - it(`should have the 'troxler-skat' title`, () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('troxler-skat'); - }); - - it('should render title', () => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.nativeElement as HTMLElement; - expect(compiled.querySelector('h1')?.textContent).toContain('Hello, troxler-skat'); - }); -}); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index a4ba5eb..74254ca 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,13 +1,20 @@ import { Component } from '@angular/core'; -import { RouterOutlet } from '@angular/router'; +import { CommonModule } from '@angular/common'; +import { GameComponent } from './game.component'; + @Component({ selector: 'app-root', standalone: true, - imports: [RouterOutlet], - templateUrl: './app.component.html', - styleUrl: './app.component.scss' + imports: [CommonModule, GameComponent], + template: ` + + `, + styles: [` + :host { + display: block; + padding: 0; + } + `] }) -export class AppComponent { - title = 'troxler-skat'; -} +export class AppComponent {} \ No newline at end of file diff --git a/src/app/card-back.component.ts b/src/app/card-back.component.ts new file mode 100644 index 0000000..6225287 --- /dev/null +++ b/src/app/card-back.component.ts @@ -0,0 +1,83 @@ +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +@Component({ + selector: 'app-card-back', + standalone: true, + imports: [CommonModule], + template: ` +
+
+ @for (row of rows; track row) { +
+ @for (column of columns; track column) { + 11 + } +
+ } +
+ + +
+ `, + styles: [` + .card-back { + width: 200px; + height: 300px; + background-color: white; + border: 2px solid #000; + border-radius: 10px; + position: relative; + font-family: Arial, sans-serif; + overflow: hidden; + } + .pattern-grid { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-evenly; + align-items: center; + } + .pattern-row { + display: flex; + justify-content: space-evenly; + width: 100%; + } + .pattern-cell { + font-size: 8px; + color: green; + opacity: 0.8; + } + .logo { + width: 40px; + height: 40px; + background-color: white; + border: 2px solid green; + border-radius: 50%; + position: absolute; + left: 50%; + transform: translateX(-50%); + display: flex; + align-items: center; + justify-content: center; + color: green; + font-weight: bold; + font-size: 24px; + z-index: 2; + } + .logo.top { + top: 20%; + } + .logo.bottom { + bottom: 20%; + } + `] +}) +export class CardBackComponent { + rows = Array.from({length: 25}, (_, i) => i + 1); + columns = Array.from({length: 12}, (_, i) => i + 1); +} \ No newline at end of file diff --git a/src/app/card-front.component.ts b/src/app/card-front.component.ts new file mode 100644 index 0000000..baee90d --- /dev/null +++ b/src/app/card-front.component.ts @@ -0,0 +1,92 @@ +import { Component, Input } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +@Component({ + selector: 'app-card-front', + standalone: true, + imports: [CommonModule], + template: ` +
+
{{number}}
+
{{number}}
+
{{number}}
+
+
{{number}}
+
{{number}}
+
{{number}}
+
+ `, + styles: [` + .card { + width: 200px; + height: 300px; + background-color: white; + border: 2px solid #000; + border-radius: 10px; + position: relative; + font-family: sans-serif; + color: var(--card-color, green); /* Farbe über CSS-Variable anpassbar */ + } + + .number-corner { + position: absolute; + font-size: 20px; + } + + .number-top-left { + top: 10px; + left: 10px; + } + + .number-bottom-left { + bottom: 10px; + left: 10px; + transform: rotate(180deg); + } + + .number-top-right { + top: 10px; + right: 10px; + } + + .number-bottom-right { + bottom: 10px; + right: 10px; + transform: rotate(180deg); + } + + .large-number { + font-size: 100px; + font-weight: bold; + line-height: 0.7; + position: absolute; + letter-spacing: -0.05em; + + display: flex; + justify-content: center; + width: 100%; + } + + .large-number-top { + top: 15%; + } + + .large-number-bottom { + bottom: 15%; + transform: rotate(180deg); + } + + .fraction-line { + position: absolute; + top: 50%; + left: 0; + width: 100%; + height: 2px; + background-color: var(--card-color, green); + } + `] +}) +export class CardFrontComponent { + @Input() number: number = 1; + @Input() color: string = 'green'; +} \ No newline at end of file diff --git a/src/app/card.service.ts b/src/app/card.service.ts new file mode 100644 index 0000000..2e388f4 --- /dev/null +++ b/src/app/card.service.ts @@ -0,0 +1,49 @@ +// card.model.ts +export interface Card { + number: number; + color: string; +} + +// card.service.ts +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class CardService { + private deck: Card[] = []; + + constructor() { + this.initializeDeck(); + } + + private initializeDeck() { + const colors = ['red', 'orange', 'green', 'black']; + for (let color of colors) { + for (let i = 1; i <= 20; i++) { + this.deck.push({ number: i, color }); + } + } + } + + shuffleDeck() { + for (let i = this.deck.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.deck[i], this.deck[j]] = [this.deck[j], this.deck[i]]; + } + } + + drawCards(count: number): Card[] { + if (this.deck.length < count) { + this.initializeDeck(); + this.shuffleDeck(); + } + return this.deck.splice(0, count); + } + + compareCards(card1: Card, card2: Card): number { + if (card1.number > card2.number) return 1; + if (card1.number < card2.number) return -1; + return 0; + } +} \ No newline at end of file diff --git a/src/app/deck.component.ts b/src/app/deck.component.ts new file mode 100644 index 0000000..a5622ee --- /dev/null +++ b/src/app/deck.component.ts @@ -0,0 +1,49 @@ +import { Component, OnInit } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { CardBackComponent } from './card-back.component'; +import { CardFrontComponent } from './card-front.component'; +import { Card, CardService } from './card.service'; + + +@Component({ + selector: 'app-deck', + standalone: true, + imports: [CommonModule, CardFrontComponent, CardBackComponent], + template: ` +
+
+ + +
+
+ + `, + styles: [` + .deck { + display: flex; + flex-wrap: wrap; + gap: 10px; + } + `] +}) +export class DeckComponent implements OnInit { + deck: Card[] = []; + flippedCards: boolean[] = []; + + constructor(private cardService: CardService) {} + + ngOnInit() { + // this.deck = this.cardService.getDeck(); + // this.flippedCards = new Array(this.deck.length).fill(false); + } + + // flipCard(index: number) { + // this.flippedCards[index] = !this.flippedCards[index]; + // } + + // shuffleDeck() { + // this.cardService.shuffleDeck(); + // this.deck = this.cardService.getDeck(); + // this.flippedCards = new Array(this.deck.length).fill(false); + // } +} \ No newline at end of file diff --git a/src/app/game.component.ts b/src/app/game.component.ts new file mode 100644 index 0000000..1fb9266 --- /dev/null +++ b/src/app/game.component.ts @@ -0,0 +1,184 @@ +import { Component, OnInit } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { CardFrontComponent } from './card-front.component'; +import { CardBackComponent } from './card-back.component'; +import { CardService, Card } from './card.service'; + +@Component({ + selector: 'app-game', + standalone: true, + imports: [CommonModule, CardFrontComponent, CardBackComponent], + template: ` +
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ Spieler: {{playerScore}} | Gegner: {{opponentScore}} | Runde: {{currentRound}}/10 +
+ +
+
+ `, + styles: [` + .game { + display: flex; + flex-direction: column; + height: 100vh; + padding: 20px; + box-sizing: border-box; + overflow: hidden; + } + .opponent-hand, .player-hand { + display: flex; + gap: 10px; + min-height: 320px; + align-items: center; + justify-content: center; + } + .play-area { + flex: 1 1 auto; + min-height: 200px; + display: flex; + justify-content: center; + align-items: center; + } + .played-cards { + position: relative; + width: 140px; + height: 200px; + } + .player-played-card { + position: absolute; + bottom: 0; + left: 0; + } + .opponent-played-card { + position: absolute; + top: 0; + right: 0; + } + .disabled { + opacity: 0.5; + pointer-events: none; + } + .game-info { + height: 10%; + min-height: 80px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 10px; + } + .score { + font-size: 1.2em; + font-weight: bold; + } + `] +}) +export class GameComponent implements OnInit { + playerHand: Card[] = []; + opponentHand: Card[] = []; + playerPlayedCard: Card | null = null; + opponentPlayedCard: Card | null = null; + playerScore: number = 0; + opponentScore: number = 0; + currentRound: number = 0; + + constructor(private cardService: CardService) {} + + ngOnInit() { + this.startNewRound(); + } + + startNewRound() { + if (this.currentRound >= 10) { + this.endGame(); + return; + } + + this.currentRound++; + const cardsForThisRound = this.getCardsForRound(this.currentRound); + + this.cardService.shuffleDeck(); + this.playerHand = this.cardService.drawCards(cardsForThisRound); + this.opponentHand = this.cardService.drawCards(cardsForThisRound); + this.playerPlayedCard = null; + this.opponentPlayedCard = null; + } + + getCardsForRound(round: number): number { + if (round <= 5) return round; + return 11 - round; + } + + playCard(index: number) { + if (this.playerPlayedCard) return; + + this.playerPlayedCard = this.playerHand.splice(index, 1)[0]; + setTimeout(() => this.opponentPlay(), 1000); + } + + opponentPlay() { + if (this.opponentHand.length === 0) return; + + const randomIndex = Math.floor(Math.random() * this.opponentHand.length); + this.opponentPlayedCard = this.opponentHand.splice(randomIndex, 1)[0]; + + setTimeout(() => this.evaluatePlay(), 1000); + } + + evaluatePlay() { + if (!this.playerPlayedCard || !this.opponentPlayedCard) return; + + const result = this.cardService.compareCards(this.playerPlayedCard, this.opponentPlayedCard); + if (result > 0) { + this.playerScore++; + } else if (result < 0) { + this.opponentScore++; + } + + if (this.playerHand.length === 0) { + if (this.currentRound < 10) { + setTimeout(() => { + alert(`Runde ${this.currentRound} beendet! Spieler: ${this.playerScore}, Gegner: ${this.opponentScore}`); + this.playerPlayedCard = null; + this.opponentPlayedCard = null; + }, 500); + } else { + this.endGame(); + } + } else { + setTimeout(() => { + this.playerPlayedCard = null; + this.opponentPlayedCard = null; + }, 1500); + } + } + + endGame() { + let result = "Unentschieden!"; + if (this.playerScore > this.opponentScore) { + result = "Sie haben gewonnen!"; + } else if (this.playerScore < this.opponentScore) { + result = "Der Gegner hat gewonnen!"; + } + alert(`Spiel beendet! ${result}\nEndstand - Spieler: ${this.playerScore}, Gegner: ${this.opponentScore}`); + } +} \ No newline at end of file diff --git a/src/styles.scss b/src/styles.scss index 90d4ee0..d2e2fe0 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -1 +1,4 @@ /* You can add global styles to this file, and also import other style files */ +body{ + margin:0; +} \ No newline at end of file