├── ios
├── Runner
│ ├── Runner-Bridging-Header.h
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ ├── 100.png
│ │ │ ├── 114.png
│ │ │ ├── 120.png
│ │ │ ├── 128.png
│ │ │ ├── 144.png
│ │ │ ├── 152.png
│ │ │ ├── 16.png
│ │ │ ├── 167.png
│ │ │ ├── 172.png
│ │ │ ├── 180.png
│ │ │ ├── 196.png
│ │ │ ├── 20.png
│ │ │ ├── 216.png
│ │ │ ├── 256.png
│ │ │ ├── 29.png
│ │ │ ├── 32.png
│ │ │ ├── 40.png
│ │ │ ├── 48.png
│ │ │ ├── 50.png
│ │ │ ├── 512.png
│ │ │ ├── 55.png
│ │ │ ├── 57.png
│ │ │ ├── 58.png
│ │ │ ├── 60.png
│ │ │ ├── 64.png
│ │ │ ├── 72.png
│ │ │ ├── 76.png
│ │ │ ├── 80.png
│ │ │ ├── 87.png
│ │ │ ├── 88.png
│ │ │ ├── 1024.png
│ │ │ └── Contents.json
│ │ └── LaunchImage.imageset
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ ├── README.md
│ │ │ └── Contents.json
│ ├── Runner.entitlements
│ ├── AppDelegate.swift
│ ├── Info.plist
│ └── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
├── build
│ └── XCBuildData
│ │ ├── build.db
│ │ ├── 10384adf67b739ef6ccb4819b7a9ee33-desc.xcbuild
│ │ ├── 31509be1ca8a7dbad0e96e4f30d83a0b-desc.xcbuild
│ │ ├── 31c3a98e90579f090f39295b8569b992-desc.xcbuild
│ │ ├── a72cf2a1d171c9732e1ecc72dd2b5a94-desc.xcbuild
│ │ └── BuildDescriptionCacheIndex-79501a06438c4d881c8e99681e89acaa
├── Flutter
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ └── AppFrameworkInfo.plist
├── Runner.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── xcshareddata
│ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ └── project.pbxproj
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── IDEWorkspaceChecks.plist
├── .gitignore
├── Podfile.lock
└── Podfile
├── web
├── favicon.png
├── icons
│ ├── Icon-192.png
│ └── Icon-512.png
├── manifest.json
└── index.html
├── assets
├── icons
│ ├── icon.png
│ ├── icon_background.png
│ └── icon_foreground.png
├── images
│ ├── logo.png
│ └── pieces
│ │ ├── 8-bit
│ │ ├── king_black.png
│ │ ├── king_white.png
│ │ ├── pawn_black.png
│ │ ├── pawn_white.png
│ │ ├── rook_black.png
│ │ ├── rook_white.png
│ │ ├── bishop_black.png
│ │ ├── bishop_white.png
│ │ ├── knight_black.png
│ │ ├── knight_white.png
│ │ ├── queen_black.png
│ │ └── queen_white.png
│ │ ├── angular
│ │ ├── king_black.png
│ │ ├── king_white.png
│ │ ├── pawn_black.png
│ │ ├── pawn_white.png
│ │ ├── rook_black.png
│ │ ├── rook_white.png
│ │ ├── bishop_black.png
│ │ ├── bishop_white.png
│ │ ├── knight_black.png
│ │ ├── knight_white.png
│ │ ├── queen_black.png
│ │ └── queen_white.png
│ │ ├── classic
│ │ ├── king_black.png
│ │ ├── king_white.png
│ │ ├── pawn_black.png
│ │ ├── pawn_white.png
│ │ ├── rook_black.png
│ │ ├── rook_white.png
│ │ ├── bishop_black.png
│ │ ├── bishop_white.png
│ │ ├── knight_black.png
│ │ ├── knight_white.png
│ │ ├── queen_black.png
│ │ └── queen_white.png
│ │ ├── letters
│ │ ├── king_black.png
│ │ ├── king_white.png
│ │ ├── pawn_black.png
│ │ ├── pawn_white.png
│ │ ├── rook_black.png
│ │ ├── rook_white.png
│ │ ├── bishop_black.png
│ │ ├── bishop_white.png
│ │ ├── knight_black.png
│ │ ├── knight_white.png
│ │ ├── queen_black.png
│ │ └── queen_white.png
│ │ ├── mexicocity
│ │ ├── king_black.png
│ │ ├── king_white.png
│ │ ├── pawn_black.png
│ │ ├── pawn_white.png
│ │ ├── rook_black.png
│ │ ├── rook_white.png
│ │ ├── bishop_black.png
│ │ ├── bishop_white.png
│ │ ├── knight_black.png
│ │ ├── knight_white.png
│ │ ├── queen_black.png
│ │ └── queen_white.png
│ │ ├── videochess
│ │ ├── king_black.png
│ │ ├── king_white.png
│ │ ├── pawn_black.png
│ │ ├── pawn_white.png
│ │ ├── rook_black.png
│ │ ├── rook_white.png
│ │ ├── bishop_black.png
│ │ ├── bishop_white.png
│ │ ├── knight_black.png
│ │ ├── knight_white.png
│ │ ├── queen_black.png
│ │ └── queen_white.png
│ │ └── lewischessmen
│ │ ├── bishop_black.png
│ │ ├── bishop_white.png
│ │ ├── king_black.png
│ │ ├── king_white.png
│ │ ├── knight_black.png
│ │ ├── knight_white.png
│ │ ├── pawn_black.png
│ │ ├── pawn_white.png
│ │ ├── queen_black.png
│ │ ├── queen_white.png
│ │ ├── rook_black.png
│ │ └── rook_white.png
├── audio
│ └── piece_moved.mp3
└── font
│ └── Jura-VariableFont_wght.ttf
├── lib
├── logic
│ ├── move_calculation
│ │ ├── move_classes
│ │ │ ├── move_and_value.dart
│ │ │ ├── direction.dart
│ │ │ ├── move.dart
│ │ │ ├── move_stack_object.dart
│ │ │ └── move_meta.dart
│ │ ├── openings.dart
│ │ ├── ai_move_calculation.dart
│ │ ├── piece_square_tables.dart
│ │ └── move_calculation.dart
│ ├── chess_piece.dart
│ ├── shared_functions.dart
│ ├── chess_piece_sprite.dart
│ ├── chess_game.dart
│ └── chess_board.dart
├── views
│ ├── components
│ │ ├── shared
│ │ │ ├── bottom_padding.dart
│ │ │ ├── rounded_button.dart
│ │ │ └── text_variable.dart
│ │ ├── main_menu_view
│ │ │ ├── game_options
│ │ │ │ ├── game_mode_picker.dart
│ │ │ │ ├── ai_difficulty_picker.dart
│ │ │ │ ├── side_picker.dart
│ │ │ │ ├── time_limit_picker.dart
│ │ │ │ └── picker.dart
│ │ │ ├── game_options.dart
│ │ │ └── main_menu_buttons.dart
│ │ ├── settings_view
│ │ │ ├── toggle.dart
│ │ │ ├── toggles.dart
│ │ │ ├── app_theme_picker.dart
│ │ │ ├── piece_preview.dart
│ │ │ └── piece_theme_picker.dart
│ │ └── chess_view
│ │ │ ├── game_info_and_controls
│ │ │ ├── moves_undo_redo_row
│ │ │ │ ├── rounded_icon_button.dart
│ │ │ │ ├── undo_redo_buttons.dart
│ │ │ │ └── move_list.dart
│ │ │ ├── restart_exit_buttons.dart
│ │ │ ├── timers.dart
│ │ │ ├── moves_undo_redo_row.dart
│ │ │ ├── rounded_alert_button.dart
│ │ │ ├── timer_widget.dart
│ │ │ └── game_status.dart
│ │ │ ├── promotion_dialog.dart
│ │ │ ├── promotion_option.dart
│ │ │ ├── game_info_and_controls.dart
│ │ │ └── chess_board_widget.dart
│ ├── main_menu_view.dart
│ ├── settings_view.dart
│ └── chess_view.dart
├── main.dart
└── model
│ ├── app_model.dart
│ └── app_themes.dart
├── .metadata
├── .gitignore
├── README.md
└── pubspec.yaml
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/web/favicon.png
--------------------------------------------------------------------------------
/assets/icons/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/icons/icon.png
--------------------------------------------------------------------------------
/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/logo.png
--------------------------------------------------------------------------------
/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/assets/audio/piece_moved.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/audio/piece_moved.mp3
--------------------------------------------------------------------------------
/ios/build/XCBuildData/build.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/build/XCBuildData/build.db
--------------------------------------------------------------------------------
/assets/icons/icon_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/icons/icon_background.png
--------------------------------------------------------------------------------
/assets/icons/icon_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/icons/icon_foreground.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/assets/font/Jura-VariableFont_wght.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/font/Jura-VariableFont_wght.ttf
--------------------------------------------------------------------------------
/assets/images/pieces/8-bit/king_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/8-bit/king_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/8-bit/king_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/8-bit/king_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/8-bit/pawn_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/8-bit/pawn_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/8-bit/pawn_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/8-bit/pawn_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/8-bit/rook_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/8-bit/rook_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/8-bit/rook_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/8-bit/rook_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/8-bit/bishop_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/8-bit/bishop_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/8-bit/bishop_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/8-bit/bishop_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/8-bit/knight_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/8-bit/knight_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/8-bit/knight_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/8-bit/knight_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/8-bit/queen_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/8-bit/queen_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/8-bit/queen_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/8-bit/queen_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/angular/king_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/angular/king_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/angular/king_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/angular/king_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/angular/pawn_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/angular/pawn_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/angular/pawn_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/angular/pawn_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/angular/rook_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/angular/rook_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/angular/rook_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/angular/rook_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/classic/king_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/classic/king_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/classic/king_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/classic/king_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/classic/pawn_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/classic/pawn_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/classic/pawn_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/classic/pawn_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/classic/rook_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/classic/rook_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/classic/rook_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/classic/rook_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/letters/king_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/letters/king_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/letters/king_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/letters/king_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/letters/pawn_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/letters/pawn_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/letters/pawn_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/letters/pawn_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/letters/rook_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/letters/rook_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/letters/rook_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/letters/rook_white.png
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/assets/images/pieces/angular/bishop_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/angular/bishop_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/angular/bishop_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/angular/bishop_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/angular/knight_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/angular/knight_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/angular/knight_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/angular/knight_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/angular/queen_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/angular/queen_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/angular/queen_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/angular/queen_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/classic/bishop_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/classic/bishop_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/classic/bishop_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/classic/bishop_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/classic/knight_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/classic/knight_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/classic/knight_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/classic/knight_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/classic/queen_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/classic/queen_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/classic/queen_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/classic/queen_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/letters/bishop_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/letters/bishop_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/letters/bishop_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/letters/bishop_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/letters/knight_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/letters/knight_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/letters/knight_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/letters/knight_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/letters/queen_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/letters/queen_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/letters/queen_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/letters/queen_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/mexicocity/king_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/mexicocity/king_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/mexicocity/king_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/mexicocity/king_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/mexicocity/pawn_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/mexicocity/pawn_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/mexicocity/pawn_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/mexicocity/pawn_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/mexicocity/rook_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/mexicocity/rook_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/mexicocity/rook_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/mexicocity/rook_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/videochess/king_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/videochess/king_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/videochess/king_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/videochess/king_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/videochess/pawn_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/videochess/pawn_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/videochess/pawn_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/videochess/pawn_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/videochess/rook_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/videochess/rook_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/videochess/rook_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/videochess/rook_white.png
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/assets/images/pieces/mexicocity/bishop_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/mexicocity/bishop_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/mexicocity/bishop_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/mexicocity/bishop_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/mexicocity/knight_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/mexicocity/knight_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/mexicocity/knight_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/mexicocity/knight_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/mexicocity/queen_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/mexicocity/queen_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/mexicocity/queen_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/mexicocity/queen_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/videochess/bishop_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/videochess/bishop_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/videochess/bishop_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/videochess/bishop_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/videochess/knight_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/videochess/knight_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/videochess/knight_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/videochess/knight_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/videochess/queen_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/videochess/queen_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/videochess/queen_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/videochess/queen_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/lewischessmen/bishop_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/lewischessmen/bishop_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/lewischessmen/bishop_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/lewischessmen/bishop_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/lewischessmen/king_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/lewischessmen/king_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/lewischessmen/king_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/lewischessmen/king_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/lewischessmen/knight_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/lewischessmen/knight_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/lewischessmen/knight_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/lewischessmen/knight_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/lewischessmen/pawn_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/lewischessmen/pawn_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/lewischessmen/pawn_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/lewischessmen/pawn_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/lewischessmen/queen_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/lewischessmen/queen_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/lewischessmen/queen_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/lewischessmen/queen_white.png
--------------------------------------------------------------------------------
/assets/images/pieces/lewischessmen/rook_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/lewischessmen/rook_black.png
--------------------------------------------------------------------------------
/assets/images/pieces/lewischessmen/rook_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/assets/images/pieces/lewischessmen/rook_white.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/100.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/114.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/128.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/144.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/152.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/16.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/167.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/167.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/172.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/172.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/196.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/196.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/20.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/216.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/216.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/256.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/32.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/48.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/50.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/512.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/55.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/55.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/64.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/72.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/76.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/88.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/88.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/build/XCBuildData/10384adf67b739ef6ccb4819b7a9ee33-desc.xcbuild:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/build/XCBuildData/10384adf67b739ef6ccb4819b7a9ee33-desc.xcbuild
--------------------------------------------------------------------------------
/ios/build/XCBuildData/31509be1ca8a7dbad0e96e4f30d83a0b-desc.xcbuild:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/build/XCBuildData/31509be1ca8a7dbad0e96e4f30d83a0b-desc.xcbuild
--------------------------------------------------------------------------------
/ios/build/XCBuildData/31c3a98e90579f090f39295b8569b992-desc.xcbuild:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/build/XCBuildData/31c3a98e90579f090f39295b8569b992-desc.xcbuild
--------------------------------------------------------------------------------
/ios/build/XCBuildData/a72cf2a1d171c9732e1ecc72dd2b5a94-desc.xcbuild:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/build/XCBuildData/a72cf2a1d171c9732e1ecc72dd2b5a94-desc.xcbuild
--------------------------------------------------------------------------------
/lib/logic/move_calculation/move_classes/move_and_value.dart:
--------------------------------------------------------------------------------
1 | import 'move.dart';
2 |
3 | class MoveAndValue {
4 | Move move;
5 | int value;
6 |
7 | MoveAndValue(this.move, this.value);
8 | }
9 |
--------------------------------------------------------------------------------
/ios/build/XCBuildData/BuildDescriptionCacheIndex-79501a06438c4d881c8e99681e89acaa:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PScottZero/EnPassant/HEAD/ios/build/XCBuildData/BuildDescriptionCacheIndex-79501a06438c4d881c8e99681e89acaa
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 78910062997c3a836feee883712c241a5fd22983
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/ios/Runner/Runner.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.network.client
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/lib/logic/move_calculation/move_classes/direction.dart:
--------------------------------------------------------------------------------
1 | class Direction {
2 | final int up;
3 | final int right;
4 |
5 | const Direction(this.up, this.right);
6 | }
7 |
8 | const UP = Direction(1, 0);
9 | const UP_RIGHT = Direction(1, 1);
10 | const RIGHT = Direction(0, 1);
11 | const DOWN_RIGHT = Direction(-1, 1);
12 | const DOWN = Direction(-1, 0);
13 | const DOWN_LEFT = Direction(-1, -1);
14 | const LEFT = Direction(0, -1);
15 | const UP_LEFT = Direction(1, -1);
16 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/lib/logic/move_calculation/move_classes/move.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/logic/chess_piece.dart';
2 |
3 | class Move {
4 | int from;
5 | int to;
6 | ChessPieceType promotionType;
7 |
8 | Move(this.from, this.to, {this.promotionType = ChessPieceType.promotion});
9 |
10 | @override
11 | bool operator ==(move) =>
12 | this.from == (move as Move).from && (this as Move).to == move.to;
13 |
14 | @override
15 | int get hashCode => super.hashCode;
16 | }
17 |
--------------------------------------------------------------------------------
/lib/views/components/shared/bottom_padding.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 | import 'dart:math';
3 |
4 | import 'package:flutter/cupertino.dart';
5 |
6 | class BottomPadding extends StatelessWidget {
7 | @override
8 | Widget build(BuildContext context) {
9 | return SizedBox(
10 | height: Platform.isAndroid
11 | ? max(MediaQuery.of(context).viewInsets.bottom,
12 | MediaQuery.of(context).padding.bottom)
13 | : 0,
14 | );
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/logic/move_calculation/move_classes/move_stack_object.dart:
--------------------------------------------------------------------------------
1 | import '../../chess_piece.dart';
2 | import 'move.dart';
3 |
4 | class MoveStackObject {
5 | Move move;
6 | ChessPiece? movedPiece;
7 | ChessPiece? takenPiece;
8 | ChessPiece? enPassantPiece;
9 | bool castled = false;
10 | bool promotion = false;
11 | ChessPieceType? promotionType;
12 | bool enPassant = false;
13 | List>? possibleOpenings;
14 |
15 | MoveStackObject(this.move, this.movedPiece, this.takenPiece,
16 | this.enPassantPiece, this.possibleOpenings);
17 | }
18 |
--------------------------------------------------------------------------------
/lib/logic/move_calculation/move_classes/move_meta.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/views/components/main_menu_view/game_options/side_picker.dart';
2 |
3 | import '../../chess_piece.dart';
4 | import 'move.dart';
5 |
6 | class MoveMeta {
7 | Move? move;
8 | Player? player;
9 | ChessPieceType? type;
10 | bool took = false;
11 | bool kingCastle = false;
12 | bool queenCastle = false;
13 | bool promotion = false;
14 | ChessPieceType? promotionType;
15 | bool isCheck = false;
16 | bool isCheckmate = false;
17 | bool isStalemate = false;
18 | bool rowIsAmbiguous = false;
19 | bool colIsAmbiguous = false;
20 |
21 | MoveMeta(this.move, this.player, this.type);
22 | }
23 |
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "en_passant",
3 | "short_name": "en_passant",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#0175C2",
7 | "theme_color": "#0175C2",
8 | "description": "A new Flutter project.",
9 | "orientation": "portrait-primary",
10 | "prefer_related_applications": false,
11 | "icons": [
12 | {
13 | "src": "icons/Icon-192.png",
14 | "sizes": "192x192",
15 | "type": "image/png"
16 | },
17 | {
18 | "src": "icons/Icon-512.png",
19 | "sizes": "512x512",
20 | "type": "image/png"
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/app.flx
22 | Flutter/app.zip
23 | Flutter/flutter_assets/
24 | Flutter/flutter_export_environment.sh
25 | ServiceDefinitions.json
26 | Runner/GeneratedPluginRegistrant.*
27 |
28 | # Exceptions to above rules.
29 | !default.mode1v3
30 | !default.mode2v3
31 | !default.pbxuser
32 | !default.perspectivev3
33 |
--------------------------------------------------------------------------------
/lib/views/components/main_menu_view/game_options/game_mode_picker.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 |
3 | import 'picker.dart';
4 |
5 | class GameModePicker extends StatelessWidget {
6 | final Map playerCountOptions = const {
7 | 1: Text('One Player'),
8 | 2: Text('Two Player')
9 | };
10 |
11 | final int playerCount;
12 | final Function(int?) setFunc;
13 |
14 | GameModePicker(this.playerCount, this.setFunc);
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | return Picker(
19 | label: 'Game Mode',
20 | options: playerCountOptions,
21 | selection: playerCount,
22 | setFunc: setFunc,
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/views/components/settings_view/toggle.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 |
3 | import '../shared/text_variable.dart';
4 |
5 | class Toggle extends StatelessWidget {
6 | final String label;
7 | final bool? toggle;
8 | final Function(bool)? setFunc;
9 |
10 | Toggle(this.label, {this.toggle, this.setFunc});
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Container(
15 | height: 55,
16 | child: Row(
17 | children: [
18 | TextRegular(label),
19 | Spacer(),
20 | CupertinoSwitch(
21 | value: toggle ?? false,
22 | onChanged: setFunc,
23 | ),
24 | ],
25 | ),
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/views/components/chess_view/game_info_and_controls/moves_undo_redo_row/rounded_icon_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 |
3 | class RoundedIconButton extends StatelessWidget {
4 | final IconData icon;
5 | final void Function()? onPressed;
6 |
7 | RoundedIconButton(this.icon, {this.onPressed});
8 |
9 | @override
10 | Widget build(BuildContext context) {
11 | return Container(
12 | child: CupertinoButton(
13 | padding: EdgeInsets.zero,
14 | color: Color(0x20000000),
15 | child: Icon(icon, color: Color(0xffffffff)),
16 | borderRadius: BorderRadius.all(Radius.circular(15)),
17 | onPressed: onPressed,
18 | ),
19 | width: double.infinity,
20 | height: 60,
21 | );
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/views/components/main_menu_view/game_options/ai_difficulty_picker.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 |
3 | import 'picker.dart';
4 |
5 | class AIDifficultyPicker extends StatelessWidget {
6 | final Map difficultyOptions = {
7 | 1: Text('1'),
8 | 2: Text('2'),
9 | 3: Text('3'),
10 | 4: Text('4'),
11 | 5: Text('5'),
12 | 6: Text('6')
13 | };
14 |
15 | final int aiDifficulty;
16 | final Function(int?) setFunc;
17 |
18 | AIDifficultyPicker(this.aiDifficulty, this.setFunc);
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | return Picker(
23 | label: 'AI Difficulty',
24 | options: difficultyOptions,
25 | selection: aiDifficulty,
26 | setFunc: setFunc,
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/views/components/main_menu_view/game_options/side_picker.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 |
3 | import 'picker.dart';
4 |
5 | enum Player { player1, player2, random }
6 |
7 | class SidePicker extends StatelessWidget {
8 | final Map colorOptions = const {
9 | Player.player1: Text('White'),
10 | Player.player2: Text('Black'),
11 | Player.random: Text('Random')
12 | };
13 |
14 | final Player playerSide;
15 | final Function(Player?) setFunc;
16 |
17 | SidePicker(this.playerSide, this.setFunc);
18 |
19 | @override
20 | Widget build(BuildContext context) {
21 | return Picker(
22 | label: 'Side',
23 | options: colorOptions,
24 | selection: playerSide,
25 | setFunc: setFunc,
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 |
34 | # Web related
35 | lib/generated_plugin_registrant.dart
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
--------------------------------------------------------------------------------
/lib/views/components/main_menu_view/game_options/time_limit_picker.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/views/components/main_menu_view/game_options/picker.dart';
2 | import 'package:flutter/cupertino.dart';
3 |
4 | class TimeLimitPicker extends StatelessWidget {
5 | final int? selectedTime;
6 | final Function(int?)? setTime;
7 |
8 | TimeLimitPicker({this.selectedTime, this.setTime});
9 |
10 | final Map timeOptions = const {
11 | 0: Text('None'),
12 | 15: Text('15m'),
13 | 30: Text('30m'),
14 | 60: Text('1h'),
15 | 90: Text('1.5h'),
16 | 120: Text('2h')
17 | };
18 |
19 | @override
20 | Widget build(BuildContext context) {
21 | return Picker(
22 | label: 'Time Limit',
23 | options: timeOptions,
24 | selection: selectedTime,
25 | setFunc: setTime,
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/views/components/shared/rounded_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class RoundedButton extends StatelessWidget {
5 | final String label;
6 | final Function() onPressed;
7 |
8 | RoundedButton(this.label, {required this.onPressed});
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return Container(
13 | child: CupertinoButton(
14 | padding: EdgeInsets.zero,
15 | color: Color(0x20000000),
16 | child: Text(
17 | label,
18 | style: TextStyle(
19 | color: Colors.white,
20 | fontSize: 24,
21 | ),
22 | ),
23 | borderRadius: BorderRadius.all(Radius.circular(15)),
24 | onPressed: onPressed,
25 | ),
26 | width: double.infinity,
27 | height: 60,
28 | );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/lib/views/components/chess_view/game_info_and_controls/restart_exit_buttons.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/model/app_model.dart';
2 | import 'package:en_passant/views/components/chess_view/game_info_and_controls/rounded_alert_button.dart';
3 | import 'package:flutter/cupertino.dart';
4 |
5 | class RestartExitButtons extends StatelessWidget {
6 | final AppModel appModel;
7 |
8 | RestartExitButtons(this.appModel);
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return Row(
13 | children: [
14 | Expanded(
15 | child: RoundedAlertButton(
16 | 'Restart',
17 | onConfirm: () {
18 | appModel.newGame(context);
19 | },
20 | ),
21 | ),
22 | SizedBox(width: 10),
23 | Expanded(
24 | child: RoundedAlertButton(
25 | 'Exit',
26 | onConfirm: () {
27 | appModel.exitChessView();
28 | Navigator.pop(context);
29 | },
30 | ),
31 | ),
32 | ],
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/views/components/chess_view/promotion_dialog.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/logic/chess_piece.dart';
2 | import 'package:en_passant/model/app_model.dart';
3 | import 'package:en_passant/views/components/chess_view/promotion_option.dart';
4 | import 'package:flutter/cupertino.dart';
5 |
6 | const PROMOTIONS = [
7 | ChessPieceType.queen,
8 | ChessPieceType.rook,
9 | ChessPieceType.bishop,
10 | ChessPieceType.knight
11 | ];
12 |
13 | class PromotionDialog extends StatelessWidget {
14 | final AppModel appModel;
15 |
16 | PromotionDialog(this.appModel);
17 |
18 | @override
19 | Widget build(BuildContext context) {
20 | return CupertinoAlertDialog(
21 | actions: [
22 | Container(
23 | height: 66,
24 | child: Row(
25 | children: PROMOTIONS
26 | .map(
27 | (promotionType) => PromotionOption(
28 | appModel,
29 | promotionType,
30 | ),
31 | )
32 | .toList(),
33 | ),
34 | ),
35 | ],
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/views/components/chess_view/promotion_option.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/logic/chess_piece.dart';
2 | import 'package:en_passant/logic/shared_functions.dart';
3 | import 'package:en_passant/model/app_model.dart';
4 | import 'package:en_passant/views/components/main_menu_view/game_options/side_picker.dart';
5 | import 'package:flutter/cupertino.dart';
6 |
7 | class PromotionOption extends StatelessWidget {
8 | final AppModel appModel;
9 | final ChessPieceType promotionType;
10 |
11 | PromotionOption(this.appModel, this.promotionType);
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return CupertinoButton(
16 | child: Image(
17 | image: AssetImage(
18 | 'assets/images/pieces/${formatPieceTheme(appModel.pieceTheme)}' +
19 | '/${pieceTypeToString(promotionType)}_${_playerColor()}.png',
20 | ),
21 | ),
22 | onPressed: () {
23 | appModel.game?.promote(promotionType);
24 | appModel.update();
25 | Navigator.pop(context);
26 | },
27 | );
28 | }
29 |
30 | String _playerColor() {
31 | return appModel.turn == Player.player1 ? 'white' : 'black';
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/views/components/chess_view/game_info_and_controls/timers.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/model/app_model.dart';
2 | import 'package:en_passant/views/components/chess_view/game_info_and_controls/timer_widget.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | class Timers extends StatelessWidget {
6 | final AppModel appModel;
7 |
8 | Timers(this.appModel);
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return appModel.timeLimit != 0
13 | ? Column(
14 | children: [
15 | Container(
16 | child: Row(
17 | children: [
18 | TimerWidget(
19 | timeLeft: appModel.player1TimeLeft,
20 | color: Colors.white,
21 | ),
22 | SizedBox(width: 10),
23 | TimerWidget(
24 | timeLeft: appModel.player2TimeLeft,
25 | color: Colors.black,
26 | ),
27 | ],
28 | ),
29 | ),
30 | SizedBox(height: 14),
31 | ],
32 | )
33 | : Container();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/views/components/chess_view/game_info_and_controls/moves_undo_redo_row.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/model/app_model.dart';
2 | import 'package:en_passant/views/components/chess_view/game_info_and_controls/moves_undo_redo_row/undo_redo_buttons.dart';
3 | import 'package:flutter/cupertino.dart';
4 |
5 | import 'moves_undo_redo_row/move_list.dart';
6 |
7 | class MovesUndoRedoRow extends StatelessWidget {
8 | final AppModel appModel;
9 |
10 | MovesUndoRedoRow(this.appModel);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Column(
15 | children: [
16 | Row(
17 | children: [
18 | appModel.showMoveHistory
19 | ? Expanded(child: MoveList(appModel))
20 | : Container(),
21 | appModel.showMoveHistory && appModel.allowUndoRedo
22 | ? SizedBox(width: 10)
23 | : Container(),
24 | appModel.allowUndoRedo
25 | ? Expanded(child: UndoRedoButtons(appModel))
26 | : Container(),
27 | ],
28 | ),
29 | appModel.showMoveHistory || appModel.allowUndoRedo
30 | ? SizedBox(height: 10)
31 | : Container(),
32 | ],
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/views/components/shared/text_variable.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 |
3 | class TextDefault extends StatelessWidget {
4 | final String text;
5 | final Color color;
6 |
7 | TextDefault(this.text, {this.color = CupertinoColors.white});
8 |
9 | @override
10 | Widget build(BuildContext context) {
11 | return Text(
12 | text,
13 | style: TextStyle(
14 | fontSize: 16,
15 | fontFamily: 'Jura',
16 | color: color,
17 | ),
18 | );
19 | }
20 | }
21 |
22 | class TextSmall extends StatelessWidget {
23 | final String text;
24 |
25 | TextSmall(this.text);
26 |
27 | @override
28 | Widget build(BuildContext context) {
29 | return Text(text, style: TextStyle(fontSize: 20));
30 | }
31 | }
32 |
33 | class TextRegular extends StatelessWidget {
34 | final String text;
35 |
36 | TextRegular(this.text);
37 |
38 | @override
39 | Widget build(BuildContext context) {
40 | return Text(text, style: TextStyle(fontSize: 24));
41 | }
42 | }
43 |
44 | class TextLarge extends StatelessWidget {
45 | final String text;
46 |
47 | TextLarge(this.text);
48 |
49 | @override
50 | Widget build(BuildContext context) {
51 | return Text(text, style: TextStyle(fontSize: 36));
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/lib/logic/chess_piece.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/views/components/main_menu_view/game_options/side_picker.dart';
2 |
3 | enum ChessPieceType { pawn, rook, knight, bishop, king, queen, promotion }
4 |
5 | class ChessPiece {
6 | int id;
7 | ChessPieceType type;
8 | Player player;
9 | int moveCount = 0;
10 | int tile;
11 |
12 | int get value {
13 | int value = 0;
14 | switch (type) {
15 | case ChessPieceType.pawn:
16 | {
17 | value = 100;
18 | }
19 | break;
20 | case ChessPieceType.knight:
21 | {
22 | value = 320;
23 | }
24 | break;
25 | case ChessPieceType.bishop:
26 | {
27 | value = 330;
28 | }
29 | break;
30 | case ChessPieceType.rook:
31 | {
32 | value = 500;
33 | }
34 | break;
35 | case ChessPieceType.queen:
36 | {
37 | value = 900;
38 | }
39 | break;
40 | case ChessPieceType.king:
41 | {
42 | value = 20000;
43 | }
44 | break;
45 | default:
46 | {
47 | value = 0;
48 | }
49 | }
50 | return (player == Player.player1) ? value : -value;
51 | }
52 |
53 | ChessPiece(this.id, this.type, this.player, this.tile);
54 | }
55 |
--------------------------------------------------------------------------------
/lib/logic/shared_functions.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/logic/chess_piece.dart';
2 | import 'package:en_passant/model/app_model.dart';
3 | import 'package:en_passant/views/components/main_menu_view/game_options/side_picker.dart';
4 |
5 | int tileToRow(int tile) {
6 | return (tile / 8).floor();
7 | }
8 |
9 | int tileToCol(int tile) {
10 | return tile % 8;
11 | }
12 |
13 | double getXFromTile(int tile, double tileSize, AppModel appModel) {
14 | return appModel.flip &&
15 | appModel.playingWithAI &&
16 | appModel.playerSide == Player.player2
17 | ? (7 - tileToCol(tile)) * tileSize
18 | : tileToCol(tile) * tileSize;
19 | }
20 |
21 | double getYFromTile(int tile, double tileSize, AppModel appModel) {
22 | return appModel.flip &&
23 | appModel.playingWithAI &&
24 | appModel.playerSide == Player.player2
25 | ? (7 - tileToRow(tile)) * tileSize
26 | : tileToRow(tile) * tileSize;
27 | }
28 |
29 | Player oppositePlayer(Player player) {
30 | return player == Player.player1 ? Player.player2 : Player.player1;
31 | }
32 |
33 | String formatPieceTheme(String themeString) {
34 | return themeString.toLowerCase().replaceAll(' ', '');
35 | }
36 |
37 | String pieceTypeToString(ChessPieceType type) {
38 | return type.toString().substring(type.toString().indexOf('.') + 1);
39 | }
40 |
--------------------------------------------------------------------------------
/lib/views/components/chess_view/game_info_and_controls.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/model/app_model.dart';
2 | import 'package:flutter/cupertino.dart';
3 |
4 | import 'game_info_and_controls/moves_undo_redo_row.dart';
5 | import 'game_info_and_controls/restart_exit_buttons.dart';
6 | import 'game_info_and_controls/timers.dart';
7 |
8 | class GameInfoAndControls extends StatelessWidget {
9 | final AppModel appModel;
10 | final ScrollController scrollController = ScrollController();
11 |
12 | GameInfoAndControls(this.appModel);
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | WidgetsBinding.instance.addPostFrameCallback((_) => _scrollToBottom());
17 | return Container(
18 | constraints: BoxConstraints(
19 | maxHeight: MediaQuery.of(context).size.height > 700 ? 204 : 134,
20 | ),
21 | child: ListView(
22 | controller: scrollController,
23 | physics: ClampingScrollPhysics(),
24 | shrinkWrap: true,
25 | padding: EdgeInsets.zero,
26 | children: [
27 | Timers(appModel),
28 | MovesUndoRedoRow(appModel),
29 | RestartExitButtons(appModel),
30 | ],
31 | ),
32 | );
33 | }
34 |
35 | void _scrollToBottom() {
36 | scrollController.jumpTo(scrollController.position.maxScrollExtent);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/views/components/settings_view/toggles.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:en_passant/model/app_model.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | import 'toggle.dart';
7 |
8 | class Toggles extends StatelessWidget {
9 | final AppModel appModel;
10 |
11 | Toggles(this.appModel);
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return Column(
16 | children: [
17 | Toggle(
18 | 'Show Hints',
19 | toggle: appModel.showHints,
20 | setFunc: appModel.setShowHints,
21 | ),
22 | Toggle(
23 | 'Allow Undo/Redo',
24 | toggle: appModel.allowUndoRedo,
25 | setFunc: appModel.setAllowUndoRedo,
26 | ),
27 | Toggle(
28 | 'Show Move History',
29 | toggle: appModel.showMoveHistory,
30 | setFunc: appModel.setShowMoveHistory,
31 | ),
32 | Toggle(
33 | 'Flip Board For Black',
34 | toggle: appModel.flip,
35 | setFunc: appModel.setFlipBoard,
36 | ),
37 | Platform.isAndroid
38 | ? Toggle(
39 | 'Sound Enabled',
40 | toggle: appModel.soundEnabled,
41 | setFunc: appModel.setSoundEnabled,
42 | )
43 | : Container(),
44 | ],
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - audioplayers (0.0.1):
3 | - Flutter
4 | - Flutter (1.0.0)
5 | - path_provider (0.0.1):
6 | - Flutter
7 | - shared_preferences (0.0.1):
8 | - Flutter
9 | - url_launcher (0.0.1):
10 | - Flutter
11 |
12 | DEPENDENCIES:
13 | - audioplayers (from `.symlinks/plugins/audioplayers/ios`)
14 | - Flutter (from `Flutter`)
15 | - path_provider (from `.symlinks/plugins/path_provider/ios`)
16 | - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
17 | - url_launcher (from `.symlinks/plugins/url_launcher/ios`)
18 |
19 | EXTERNAL SOURCES:
20 | audioplayers:
21 | :path: ".symlinks/plugins/audioplayers/ios"
22 | Flutter:
23 | :path: Flutter
24 | path_provider:
25 | :path: ".symlinks/plugins/path_provider/ios"
26 | shared_preferences:
27 | :path: ".symlinks/plugins/shared_preferences/ios"
28 | url_launcher:
29 | :path: ".symlinks/plugins/url_launcher/ios"
30 |
31 | SPEC CHECKSUMS:
32 | audioplayers: 455322b54050b30ea4b1af7cd9e9d105f74efa8c
33 | Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
34 | path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
35 | shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
36 | url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
37 |
38 | PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
39 |
40 | COCOAPODS: 1.10.1
41 |
--------------------------------------------------------------------------------
/lib/views/components/chess_view/chess_board_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/model/app_model.dart';
2 | import 'package:flame/game.dart';
3 | import 'package:flutter/cupertino.dart';
4 |
5 | class ChessBoardWidget extends StatelessWidget {
6 | final AppModel appModel;
7 |
8 | ChessBoardWidget(this.appModel);
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return Container(
13 | decoration: appModel.theme.name != 'Video Chess'
14 | ? BoxDecoration(
15 | border: Border.all(
16 | color: appModel.theme.border,
17 | width: 4,
18 | ),
19 | borderRadius: BorderRadius.circular(14),
20 | boxShadow: [
21 | BoxShadow(
22 | blurRadius: 10,
23 | color: Color(0x88000000),
24 | ),
25 | ],
26 | )
27 | : BoxDecoration(),
28 | child: ClipRRect(
29 | borderRadius: appModel.theme.name != 'Video Chess'
30 | ? BorderRadius.circular(10)
31 | : BorderRadius.zero,
32 | child: Container(
33 | child: GameWidget(game: appModel.game!),
34 | width: MediaQuery.of(context).size.width - 68,
35 | height: MediaQuery.of(context).size.width - 68,
36 | ),
37 | ),
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/views/components/main_menu_view/game_options/picker.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 |
3 | import '../../shared/text_variable.dart';
4 |
5 | class Picker extends StatelessWidget {
6 | final String? label;
7 | final Map? options;
8 | final T? selection;
9 | final Function(T?)? setFunc;
10 |
11 | Picker({this.label, this.options, this.selection, this.setFunc});
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return Column(
16 | children: [
17 | TextSmall(label ?? ""),
18 | SizedBox(height: 10),
19 | Container(
20 | child: CupertinoTheme(
21 | data: CupertinoThemeData(
22 | textTheme: CupertinoTextThemeData(
23 | textStyle: TextStyle(fontFamily: 'Jura', fontSize: 8),
24 | ),
25 | ),
26 | child: CupertinoSlidingSegmentedControl(
27 | children: options ?? {},
28 | groupValue: selection,
29 | onValueChanged: (T? val) {
30 | if (setFunc != null) {
31 | setFunc!(val);
32 | }
33 | },
34 | thumbColor: Color(0x88FFFFFF),
35 | backgroundColor: Color(0x20000000),
36 | ),
37 | ),
38 | width: double.infinity,
39 | )
40 | ],
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/views/main_menu_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/model/app_model.dart';
2 | import 'package:en_passant/views/components/main_menu_view/game_options.dart';
3 | import 'package:en_passant/views/components/shared/bottom_padding.dart';
4 | import 'package:flutter/cupertino.dart';
5 | import 'package:provider/provider.dart';
6 |
7 | import 'components/main_menu_view/main_menu_buttons.dart';
8 |
9 | class MainMenuView extends StatefulWidget {
10 | @override
11 | _MainMenuViewState createState() => _MainMenuViewState();
12 | }
13 |
14 | class _MainMenuViewState extends State {
15 | @override
16 | Widget build(BuildContext context) {
17 | return Consumer(
18 | builder: (context, appModel, child) {
19 | return Container(
20 | decoration: BoxDecoration(gradient: appModel.theme.background),
21 | padding: EdgeInsets.all(30),
22 | child: Column(
23 | children: [
24 | Container(
25 | padding: EdgeInsets.fromLTRB(
26 | 10, MediaQuery.of(context).padding.top + 10, 10, 0),
27 | child: Image.asset('assets/images/logo.png'),
28 | ),
29 | SizedBox(height: 20),
30 | GameOptions(appModel),
31 | SizedBox(height: 10),
32 | MainMenuButtons(appModel),
33 | BottomPadding(),
34 | ],
35 | ),
36 | );
37 | },
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # En Passant
2 |
3 | En Passant is a chess app written in Flutter using Flame engine. It is a remake of [Checkmate](https://github.com/PScottZero/Checkmate), a SwiftUI project which I submitted as my final project for an application development course I took at Penn State (CMPSC 475) during the fall of 2020.
4 |
5 |
6 |
7 | ## Features
8 | - 1 or 2 player gameplay (2 player is offline)
9 | - Six AI difficulty levels
10 | - Customizable app theme
11 | - Customizable piece theme
12 |
13 | ## AI Description
14 |
15 | The chess AI I developed for this app uses the minimax algorithm with alpha-beta pruning to calculate which moves to make. There are six difficulty levels in the app, each level corresponding to the depth of the search used in the minimax algorithm. The highest difficulty is 6, which corresponds to 3 full chess moves. To learn more about how this algorithm works, use the following link: https://en.wikipedia.org/wiki/Alpha–beta_pruning.
16 |
17 | ## Screenshots
18 |
19 |
20 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | end
36 |
37 | post_install do |installer|
38 | installer.pods_project.targets.each do |target|
39 | flutter_additional_ios_build_settings(target)
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/lib/views/components/chess_view/game_info_and_controls/rounded_alert_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 |
3 | import '../../shared/rounded_button.dart';
4 | import '../../shared/text_variable.dart';
5 |
6 | class RoundedAlertButton extends StatelessWidget {
7 | final String label;
8 | final Function onConfirm;
9 |
10 | RoundedAlertButton(this.label, {required this.onConfirm});
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return RoundedButton(label, onPressed: () {
15 | showCupertinoDialog(
16 | context: context,
17 | builder: (BuildContext context) {
18 | return CupertinoAlertDialog(
19 | title: TextDefault(label),
20 | content: TextDefault(
21 | 'Are you sure you want to ${label.toLowerCase()}?',
22 | ),
23 | actions: [
24 | CupertinoButton(
25 | child: TextDefault(
26 | label,
27 | color: CupertinoColors.destructiveRed,
28 | ),
29 | onPressed: () {
30 | onConfirm();
31 | Navigator.pop(context);
32 | },
33 | ),
34 | CupertinoButton(
35 | child: TextDefault('Cancel', color: CupertinoColors.activeBlue),
36 | onPressed: () {
37 | Navigator.pop(context);
38 | },
39 | ),
40 | ],
41 | );
42 | },
43 | );
44 | });
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/model/app_model.dart';
2 | import 'package:en_passant/views/main_menu_view.dart';
3 | import 'package:flame/flame.dart';
4 | import 'package:flutter/cupertino.dart';
5 | import 'package:flutter/services.dart';
6 | import 'package:provider/provider.dart';
7 |
8 | import 'logic/shared_functions.dart';
9 |
10 | void main() {
11 | runApp(
12 | ChangeNotifierProvider(
13 | create: (context) => AppModel(),
14 | child: EnPassantApp(),
15 | ),
16 | );
17 | _loadFlameAssets();
18 | }
19 |
20 | void _loadFlameAssets() async {
21 | List pieceImages = [];
22 | for (var theme in PIECE_THEMES) {
23 | for (var color in ['black', 'white']) {
24 | for (var piece in ['king', 'queen', 'rook', 'bishop', 'knight', 'pawn']) {
25 | pieceImages
26 | .add('pieces/${formatPieceTheme(theme)}/${piece}_$color.png');
27 | }
28 | }
29 | }
30 | await Flame.images.loadAll(pieceImages);
31 | }
32 |
33 | class EnPassantApp extends StatelessWidget {
34 | @override
35 | Widget build(BuildContext context) {
36 | SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
37 | return CupertinoApp(
38 | title: 'En Passant',
39 | theme: CupertinoThemeData(
40 | brightness: Brightness.dark,
41 | textTheme: CupertinoTextThemeData(
42 | textStyle: TextStyle(fontFamily: 'Jura', fontSize: 16),
43 | pickerTextStyle: TextStyle(fontFamily: 'Jura'),
44 | ),
45 | ),
46 | home: MainMenuView(),
47 | );
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | En Passant
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 |
33 | UISupportedInterfaceOrientations~ipad
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationPortraitUpsideDown
37 | UIInterfaceOrientationLandscapeLeft
38 | UIInterfaceOrientationLandscapeRight
39 |
40 | UIViewControllerBasedStatusBarAppearance
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/lib/views/components/chess_view/game_info_and_controls/timer_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/views/components/shared/text_variable.dart';
2 | import 'package:flutter/cupertino.dart';
3 |
4 | class TimerWidget extends StatelessWidget {
5 | final Duration timeLeft;
6 | final Color color;
7 |
8 | TimerWidget({required this.timeLeft, required this.color});
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return Expanded(
13 | child: Container(
14 | height: 60,
15 | child: Center(
16 | child: TextRegular(_durationToString(timeLeft)),
17 | ),
18 | decoration: BoxDecoration(
19 | border: Border.all(color: color, width: 2),
20 | borderRadius: BorderRadius.circular(14),
21 | color: Color(0x20000000),
22 | ),
23 | ),
24 | );
25 | }
26 |
27 | String _durationToString(Duration duration) {
28 | if (duration.inHours > 0) {
29 | String hours = duration.inHours.toString();
30 | String minutes =
31 | duration.inMinutes.remainder(60).toString().padLeft(2, '0');
32 | String seconds =
33 | duration.inSeconds.remainder(60).toString().padLeft(2, '0');
34 | return '$hours:$minutes:$seconds';
35 | } else if (duration.inMinutes > 0) {
36 | String minutes = duration.inMinutes.toString();
37 | String seconds =
38 | duration.inSeconds.remainder(60).toString().padLeft(2, '0');
39 | return '$minutes:$seconds';
40 | } else {
41 | String seconds = duration.inSeconds.toString();
42 | return '$seconds';
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/views/components/main_menu_view/game_options.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/model/app_model.dart';
2 | import 'package:flutter/cupertino.dart';
3 |
4 | import 'game_options/ai_difficulty_picker.dart';
5 | import 'game_options/game_mode_picker.dart';
6 | import 'game_options/side_picker.dart';
7 | import 'game_options/time_limit_picker.dart';
8 |
9 | class GameOptions extends StatelessWidget {
10 | final AppModel appModel;
11 |
12 | GameOptions(this.appModel);
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Expanded(
17 | child: ListView(
18 | padding: EdgeInsets.zero,
19 | physics: ClampingScrollPhysics(),
20 | children: [
21 | GameModePicker(
22 | appModel.playerCount,
23 | appModel.setPlayerCount,
24 | ),
25 | SizedBox(height: 20),
26 | appModel.playerCount == 1
27 | ? Column(
28 | children: [
29 | AIDifficultyPicker(
30 | appModel.aiDifficulty,
31 | appModel.setAIDifficulty,
32 | ),
33 | SizedBox(height: 20),
34 | SidePicker(
35 | appModel.selectedSide,
36 | appModel.setPlayerSide,
37 | ),
38 | SizedBox(height: 20),
39 | ],
40 | )
41 | : Container(),
42 | TimeLimitPicker(
43 | selectedTime: appModel.timeLimit,
44 | setTime: appModel.setTimeLimit,
45 | ),
46 | ],
47 | ),
48 | );
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | en_passant
30 |
31 |
32 |
33 |
36 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/lib/views/components/settings_view/app_theme_picker.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/model/app_model.dart';
2 | import 'package:en_passant/model/app_themes.dart';
3 | import 'package:en_passant/views/components/shared/text_variable.dart';
4 | import 'package:flutter/cupertino.dart';
5 | import 'package:provider/provider.dart';
6 |
7 | class AppThemePicker extends StatelessWidget {
8 | @override
9 | Widget build(BuildContext context) {
10 | return Consumer(
11 | builder: (context, appModel, child) => Column(
12 | children: [
13 | Container(
14 | child: TextSmall('App Theme'),
15 | padding: EdgeInsets.all(10),
16 | ),
17 | Container(
18 | height: 120,
19 | decoration: BoxDecoration(
20 | borderRadius: BorderRadius.all(Radius.circular(15)),
21 | color: Color(0x20000000),
22 | ),
23 | child: CupertinoPicker(
24 | scrollController: FixedExtentScrollController(
25 | initialItem: appModel.themeIndex,
26 | ),
27 | selectionOverlay: CupertinoPickerDefaultSelectionOverlay(
28 | background: Color(0x20000000),
29 | ),
30 | itemExtent: 50,
31 | onSelectedItemChanged: appModel.setTheme,
32 | children: themeList
33 | .map(
34 | (theme) => Container(
35 | padding: EdgeInsets.all(10),
36 | child: TextRegular(theme.name ?? ""),
37 | ),
38 | )
39 | .toList(),
40 | ),
41 | ),
42 | ],
43 | ),
44 | );
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/lib/views/settings_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/model/app_model.dart';
2 | import 'package:en_passant/views/components/settings_view/piece_theme_picker.dart';
3 | import 'package:en_passant/views/components/shared/rounded_button.dart';
4 | import 'package:flutter/cupertino.dart';
5 | import 'package:provider/provider.dart';
6 |
7 | import 'components/settings_view/app_theme_picker.dart';
8 | import 'components/settings_view/toggles.dart';
9 | import 'components/shared/bottom_padding.dart';
10 | import 'components/shared/text_variable.dart';
11 |
12 | class SettingsView extends StatelessWidget {
13 | @override
14 | Widget build(BuildContext context) {
15 | return Consumer(
16 | builder: (context, appModel, child) => Container(
17 | decoration: BoxDecoration(gradient: appModel.theme.background),
18 | padding: EdgeInsets.all(30),
19 | child: Column(
20 | children: [
21 | SizedBox(height: MediaQuery.of(context).padding.top),
22 | TextLarge('Settings'),
23 | SizedBox(height: 20),
24 | Expanded(
25 | child: ListView(
26 | padding: EdgeInsets.zero,
27 | physics: ClampingScrollPhysics(),
28 | children: [
29 | AppThemePicker(),
30 | SizedBox(height: 20),
31 | PieceThemePicker(),
32 | SizedBox(height: 10),
33 | Toggles(appModel),
34 | ],
35 | ),
36 | ),
37 | SizedBox(height: 30),
38 | RoundedButton(
39 | 'Back',
40 | onPressed: () {
41 | Navigator.pop(context);
42 | },
43 | ),
44 | BottomPadding(),
45 | ],
46 | ),
47 | ),
48 | );
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/lib/logic/move_calculation/openings.dart:
--------------------------------------------------------------------------------
1 | import 'move_classes/move.dart';
2 |
3 | var openings = [
4 | [
5 | // Ruy Lopez
6 | Move(tileToInt('e2'), tileToInt('e4')),
7 | Move(tileToInt('e7'), tileToInt('e5')),
8 | Move(tileToInt('g1'), tileToInt('f3')),
9 | Move(tileToInt('b8'), tileToInt('c6')),
10 | Move(tileToInt('f1'), tileToInt('b5')),
11 | ],
12 | [
13 | // Italian Game
14 | Move(tileToInt('e2'), tileToInt('e4')),
15 | Move(tileToInt('e7'), tileToInt('e5')),
16 | Move(tileToInt('g1'), tileToInt('f3')),
17 | Move(tileToInt('b8'), tileToInt('c6')),
18 | Move(tileToInt('f1'), tileToInt('c4'))
19 | ],
20 | [
21 | // Sicilian Defense
22 | Move(tileToInt('e2'), tileToInt('e4')),
23 | Move(tileToInt('c7'), tileToInt('c5')),
24 | ],
25 | [
26 | // French Defense
27 | Move(tileToInt('e2'), tileToInt('e4')),
28 | Move(tileToInt('e7'), tileToInt('e6')),
29 | ],
30 | [
31 | // Caro-Kann Defense
32 | Move(tileToInt('e2'), tileToInt('e4')),
33 | Move(tileToInt('c7'), tileToInt('c6')),
34 | ],
35 | [
36 | // Pirc Defense
37 | Move(tileToInt('e2'), tileToInt('e4')),
38 | Move(tileToInt('d7'), tileToInt('d6')),
39 | ],
40 | [
41 | // Queen's Gambit
42 | Move(tileToInt('d2'), tileToInt('d4')),
43 | Move(tileToInt('d7'), tileToInt('d5')),
44 | Move(tileToInt('c2'), tileToInt('c4')),
45 | ],
46 | [
47 | // Indian Defense
48 | Move(tileToInt('d2'), tileToInt('d4')),
49 | Move(tileToInt('g8'), tileToInt('f6')),
50 | ],
51 | [
52 | // English Opening
53 | Move(tileToInt('c2'), tileToInt('c4')),
54 | ],
55 | [
56 | // Reti Opening
57 | Move(tileToInt('g1'), tileToInt('f3')),
58 | ]
59 | ];
60 |
61 | int tileToInt(String tile) {
62 | var file = tile.codeUnitAt(0) - 97;
63 | var rank = 8 - (int.tryParse(tile[1]) ?? 0);
64 | return rank * 8 + file;
65 | }
66 |
--------------------------------------------------------------------------------
/lib/views/components/chess_view/game_info_and_controls/moves_undo_redo_row/undo_redo_buttons.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/model/app_model.dart';
2 | import 'package:en_passant/views/components/chess_view/game_info_and_controls/moves_undo_redo_row/rounded_icon_button.dart';
3 | import 'package:flutter/cupertino.dart';
4 |
5 | class UndoRedoButtons extends StatelessWidget {
6 | final AppModel appModel;
7 |
8 | bool get undoEnabled {
9 | if (appModel.playingWithAI) {
10 | return (appModel.game?.board.moveStack.length ?? 0) > 1 &&
11 | !appModel.isAIsTurn;
12 | } else {
13 | return appModel.game?.board.moveStack.isNotEmpty ?? false;
14 | }
15 | }
16 |
17 | bool get redoEnabled {
18 | if (appModel.playingWithAI) {
19 | return (appModel.game?.board.redoStack.length ?? 0) > 1 &&
20 | !appModel.isAIsTurn;
21 | } else {
22 | return appModel.game?.board.redoStack.isNotEmpty ?? false;
23 | }
24 | }
25 |
26 | UndoRedoButtons(this.appModel);
27 |
28 | @override
29 | Widget build(BuildContext context) {
30 | return Row(
31 | children: [
32 | Expanded(
33 | child: RoundedIconButton(
34 | CupertinoIcons.arrow_counterclockwise,
35 | onPressed: undoEnabled ? () => undo() : null,
36 | ),
37 | ),
38 | SizedBox(width: 10),
39 | Expanded(
40 | child: RoundedIconButton(
41 | CupertinoIcons.arrow_clockwise,
42 | onPressed: redoEnabled ? () => redo() : null,
43 | ),
44 | ),
45 | ],
46 | );
47 | }
48 |
49 | void undo() {
50 | if (appModel.playingWithAI) {
51 | appModel.game?.undoTwoMoves();
52 | } else {
53 | appModel.game?.undoMove();
54 | }
55 | }
56 |
57 | void redo() {
58 | if (appModel.playingWithAI) {
59 | appModel.game?.redoTwoMoves();
60 | } else {
61 | appModel.game?.redoMove();
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/lib/views/components/chess_view/game_info_and_controls/game_status.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/model/app_model.dart';
2 | import 'package:en_passant/views/components/main_menu_view/game_options/side_picker.dart';
3 | import 'package:en_passant/views/components/shared/text_variable.dart';
4 | import 'package:flutter/cupertino.dart';
5 | import 'package:provider/provider.dart';
6 |
7 | class GameStatus extends StatelessWidget {
8 | @override
9 | Widget build(BuildContext context) {
10 | return Consumer(
11 | builder: (context, appModel, child) => Row(
12 | children: [
13 | TextRegular(_getStatus(appModel)),
14 | !appModel.gameOver && appModel.playerCount == 1 && appModel.isAIsTurn
15 | ? CupertinoActivityIndicator(radius: 12)
16 | : Container()
17 | ],
18 | mainAxisAlignment: MainAxisAlignment.center,
19 | ),
20 | );
21 | }
22 |
23 | String _getStatus(AppModel appModel) {
24 | if (!appModel.gameOver) {
25 | if (appModel.playerCount == 1) {
26 | if (appModel.isAIsTurn) {
27 | return 'AI [Level ${appModel.aiDifficulty}] is thinking ';
28 | } else {
29 | return 'Your turn';
30 | }
31 | } else {
32 | if (appModel.turn == Player.player1) {
33 | return 'White\'s turn';
34 | } else {
35 | return 'Black\'s turn';
36 | }
37 | }
38 | } else {
39 | if (appModel.stalemate) {
40 | return 'Stalemate';
41 | } else {
42 | if (appModel.playerCount == 1) {
43 | if (appModel.isAIsTurn) {
44 | return 'You Win!';
45 | } else {
46 | return 'You Lose :(';
47 | }
48 | } else {
49 | if (appModel.turn == Player.player1) {
50 | return 'Black wins!';
51 | } else {
52 | return 'White wins!';
53 | }
54 | }
55 | }
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/lib/views/components/settings_view/piece_preview.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 |
3 | import 'package:en_passant/logic/shared_functions.dart';
4 | import 'package:en_passant/model/app_model.dart';
5 | import 'package:flame/flame.dart';
6 | import 'package:flame/game.dart';
7 | import 'package:flame/sprite.dart';
8 | import 'package:flutter/cupertino.dart';
9 |
10 | class PiecePreview extends Game {
11 | AppModel appModel;
12 |
13 | Map get imageMap {
14 | return {
15 | 0: 'pieces/${formatPieceTheme(appModel.pieceTheme)}/king_black.png',
16 | 1: 'pieces/${formatPieceTheme(appModel.pieceTheme)}/queen_white.png',
17 | 2: 'pieces/${formatPieceTheme(appModel.pieceTheme)}/rook_white.png',
18 | 3: 'pieces/${formatPieceTheme(appModel.pieceTheme)}/bishop_black.png',
19 | 4: 'pieces/${formatPieceTheme(appModel.pieceTheme)}/knight_black.png',
20 | 5: 'pieces/${formatPieceTheme(appModel.pieceTheme)}/pawn_white.png',
21 | };
22 | }
23 |
24 | Map spriteMap = Map();
25 | bool rendered = false;
26 |
27 | PiecePreview(this.appModel) {
28 | loadSpriteImages();
29 | }
30 |
31 | loadSpriteImages() async {
32 | for (var index = 0; index < 6; index++) {
33 | spriteMap[index] = Sprite(await Flame.images.load(imageMap[index] ?? ""));
34 | }
35 | }
36 |
37 | @override
38 | void render(Canvas canvas) {
39 | for (var index = 0; index < 6; index++) {
40 | canvas.drawRect(
41 | Rect.fromLTWH((index % 2) * 40.0, (index / 2).floor() * 40.0, 40, 40),
42 | Paint()
43 | ..color = (index + (index / 2).floor()) % 2 == 0
44 | ? appModel.theme.lightTile
45 | : appModel.theme.darkTile,
46 | );
47 | spriteMap[index]?.render(
48 | canvas,
49 | size: Vector2(30, 30),
50 | position: Vector2(
51 | (index % 2) * 40.0 + 5,
52 | (index / 2).floor() * 40.0 + 5,
53 | ),
54 | );
55 | }
56 | }
57 |
58 | @override
59 | void update(double t) {}
60 | }
61 |
--------------------------------------------------------------------------------
/lib/views/components/main_menu_view/main_menu_buttons.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/model/app_model.dart';
2 | import 'package:en_passant/views/components/shared/rounded_button.dart';
3 | import 'package:flutter/cupertino.dart';
4 | import 'package:url_launcher/url_launcher.dart';
5 |
6 | import '../../chess_view.dart';
7 | import '../../settings_view.dart';
8 |
9 | class MainMenuButtons extends StatelessWidget {
10 | final AppModel appModel;
11 |
12 | MainMenuButtons(this.appModel);
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Container(
17 | width: double.infinity,
18 | child: Column(
19 | children: [
20 | RoundedButton(
21 | 'Start',
22 | onPressed: () {
23 | Navigator.push(
24 | context,
25 | CupertinoPageRoute(
26 | builder: (context) {
27 | appModel.newGame(context, notify: false);
28 | return ChessView(appModel);
29 | },
30 | ),
31 | );
32 | },
33 | ),
34 | SizedBox(height: 10),
35 | Row(
36 | children: [
37 | Expanded(
38 | child: RoundedButton(
39 | 'GitHub',
40 | onPressed: () {
41 | _openGitHub();
42 | },
43 | ),
44 | ),
45 | SizedBox(width: 10),
46 | Expanded(
47 | child: RoundedButton(
48 | 'Settings',
49 | onPressed: () {
50 | Navigator.push(
51 | context,
52 | CupertinoPageRoute(
53 | builder: (context) => SettingsView(),
54 | ),
55 | );
56 | },
57 | ),
58 | ),
59 | ],
60 | ),
61 | ],
62 | ),
63 | );
64 | }
65 |
66 | void _openGitHub() async {
67 | const url = 'https://github.com/PScottZero/EnPassant';
68 | if (await canLaunch(url)) {
69 | await launch(url);
70 | } else {
71 | throw 'Could not launch $url';
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/lib/views/chess_view.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:en_passant/model/app_model.dart';
4 | import 'package:en_passant/views/components/chess_view/chess_board_widget.dart';
5 | import 'package:en_passant/views/components/chess_view/game_info_and_controls.dart';
6 | import 'package:en_passant/views/components/chess_view/promotion_dialog.dart';
7 | import 'package:flutter/cupertino.dart';
8 | import 'package:provider/provider.dart';
9 |
10 | import 'components/chess_view/game_info_and_controls/game_status.dart';
11 | import 'components/shared/bottom_padding.dart';
12 |
13 | class ChessView extends StatefulWidget {
14 | final AppModel appModel;
15 |
16 | ChessView(this.appModel);
17 |
18 | @override
19 | _ChessViewState createState() => _ChessViewState(appModel);
20 | }
21 |
22 | class _ChessViewState extends State {
23 | AppModel appModel;
24 |
25 | _ChessViewState(this.appModel);
26 |
27 | @override
28 | Widget build(BuildContext context) {
29 | return Consumer(
30 | builder: (context, appModel, child) {
31 | if (appModel.promotionRequested) {
32 | appModel.promotionRequested = false;
33 | WidgetsBinding.instance
34 | .addPostFrameCallback((_) => _showPromotionDialog(appModel));
35 | }
36 | return WillPopScope(
37 | onWillPop: _willPopCallback,
38 | child: Container(
39 | decoration: BoxDecoration(gradient: appModel.theme.background),
40 | padding: EdgeInsets.all(30),
41 | child: Column(
42 | children: [
43 | Spacer(),
44 | ChessBoardWidget(appModel),
45 | SizedBox(height: 30),
46 | GameStatus(),
47 | Spacer(),
48 | GameInfoAndControls(appModel),
49 | BottomPadding(),
50 | ],
51 | ),
52 | ),
53 | );
54 | },
55 | );
56 | }
57 |
58 | void _showPromotionDialog(AppModel appModel) {
59 | showCupertinoDialog(
60 | context: context,
61 | builder: (BuildContext context) {
62 | return PromotionDialog(appModel);
63 | },
64 | );
65 | }
66 |
67 | Future _willPopCallback() async {
68 | appModel.exitChessView();
69 | return true;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/lib/views/components/settings_view/piece_theme_picker.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/model/app_model.dart';
2 | import 'package:en_passant/views/components/settings_view/piece_preview.dart';
3 | import 'package:en_passant/views/components/shared/text_variable.dart';
4 | import 'package:flame/game.dart';
5 | import 'package:flutter/cupertino.dart';
6 | import 'package:provider/provider.dart';
7 |
8 | class PieceThemePicker extends StatelessWidget {
9 | @override
10 | Widget build(BuildContext context) {
11 | return Consumer(
12 | builder: (context, appModel, child) => Column(
13 | children: [
14 | Container(
15 | child: TextSmall('Piece Theme'),
16 | padding: EdgeInsets.all(10),
17 | ),
18 | ClipRRect(
19 | borderRadius: BorderRadius.all(Radius.circular(15)),
20 | child: Container(
21 | height: 120,
22 | decoration: BoxDecoration(color: Color(0x20000000)),
23 | child: Row(
24 | children: [
25 | Expanded(
26 | child: CupertinoPicker(
27 | scrollController: FixedExtentScrollController(
28 | initialItem: appModel.pieceThemeIndex,
29 | ),
30 | selectionOverlay: CupertinoPickerDefaultSelectionOverlay(
31 | background: Color(0x20000000),
32 | ),
33 | itemExtent: 50,
34 | onSelectedItemChanged: appModel.setPieceTheme,
35 | children: appModel.pieceThemes
36 | .map(
37 | (theme) => Container(
38 | padding: EdgeInsets.all(10),
39 | child: TextRegular(theme),
40 | ),
41 | )
42 | .toList(),
43 | ),
44 | ),
45 | Container(
46 | height: 120,
47 | width: 80,
48 | child: GameWidget(
49 | game: PiecePreview(appModel),
50 | ),
51 | ),
52 | ],
53 | ),
54 | ),
55 | ),
56 | ],
57 | ),
58 | );
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/lib/logic/move_calculation/ai_move_calculation.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:en_passant/logic/move_calculation/move_classes/move_and_value.dart';
4 | import 'package:en_passant/views/components/main_menu_view/game_options/side_picker.dart';
5 |
6 | import '../chess_board.dart';
7 | import '../shared_functions.dart';
8 | import 'move_calculation.dart';
9 | import 'move_classes/move.dart';
10 |
11 | const INITIAL_ALPHA = -40000;
12 | const STALEMATE_ALPHA = -20000;
13 | const INITIAL_BETA = 40000;
14 | const STALEMATE_BETA = 20000;
15 |
16 | Move calculateAIMove(Map args) {
17 | ChessBoard board = args['board'];
18 | if (board.possibleOpenings.isNotEmpty) {
19 | return _openingMove(board, args['aiPlayer']);
20 | } else {
21 | return _alphaBeta(board, args['aiPlayer'], Move(0, 0), 0,
22 | args['aiDifficulty'], INITIAL_ALPHA, INITIAL_BETA)
23 | .move;
24 | }
25 | }
26 |
27 | MoveAndValue _alphaBeta(ChessBoard board, Player player, Move move, int depth,
28 | int maxDepth, int alpha, int beta) {
29 | if (depth == maxDepth) {
30 | return MoveAndValue(move, boardValue(board));
31 | }
32 | var bestMove = MoveAndValue(
33 | Move(0, 0), player == Player.player1 ? INITIAL_ALPHA : INITIAL_BETA);
34 | for (var move in allMoves(player, board, maxDepth)) {
35 | push(move, board, promotionType: move.promotionType);
36 | var result = _alphaBeta(
37 | board, oppositePlayer(player), move, depth + 1, maxDepth, alpha, beta);
38 | result.move = move;
39 | pop(board);
40 | if (player == Player.player1) {
41 | if (result.value > bestMove.value) {
42 | bestMove = result;
43 | }
44 | alpha = max(alpha, bestMove.value);
45 | if (alpha >= beta) {
46 | break;
47 | }
48 | } else {
49 | if (result.value < bestMove.value) {
50 | bestMove = result;
51 | }
52 | beta = min(beta, bestMove.value);
53 | if (beta <= alpha) {
54 | break;
55 | }
56 | }
57 | }
58 | if (bestMove.value.abs() == INITIAL_BETA && !kingInCheck(player, board)) {
59 | if (piecesForPlayer(player, board).length == 1) {
60 | bestMove.value =
61 | player == Player.player1 ? STALEMATE_BETA : STALEMATE_ALPHA;
62 | } else {
63 | bestMove.value =
64 | player == Player.player1 ? STALEMATE_ALPHA : STALEMATE_BETA;
65 | }
66 | }
67 | return bestMove;
68 | }
69 |
70 | Move _openingMove(ChessBoard board, Player aiPlayer) {
71 | List possibleMoves = board.possibleOpenings
72 | .map((opening) => opening[board.moveCount])
73 | .toList();
74 | return possibleMoves[Random.secure().nextInt(possibleMoves.length)];
75 | }
76 |
--------------------------------------------------------------------------------
/lib/logic/chess_piece_sprite.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/model/app_model.dart';
2 | import 'package:en_passant/views/components/main_menu_view/game_options/side_picker.dart';
3 | import 'package:flame/components.dart';
4 | import 'package:flame/flame.dart';
5 | import 'package:flame_audio/flame_audio.dart';
6 | import 'package:flame/sprite.dart';
7 |
8 | import 'chess_piece.dart';
9 | import 'shared_functions.dart';
10 |
11 | class ChessPieceSprite {
12 | ChessPieceType? type;
13 | String? pieceTheme;
14 | int? tile;
15 | Sprite? sprite;
16 | double? spriteX;
17 | double? spriteY;
18 | double offsetX = 0;
19 | double offsetY = 0;
20 |
21 | ChessPieceSprite(ChessPiece piece, String pieceTheme) {
22 | this.tile = piece.tile;
23 | this.type = piece.type;
24 | this.pieceTheme = pieceTheme;
25 | initSprite(piece);
26 | }
27 |
28 | void update(double tileSize, AppModel appModel, ChessPiece piece) {
29 | if (piece.type != this.type) {
30 | this.type = piece.type;
31 | initSprite(piece);
32 | }
33 | if (piece.tile != this.tile) {
34 | this.tile = piece.tile;
35 | offsetX = 0;
36 | offsetY = 0;
37 | }
38 | var destX = getXFromTile(tile ?? 0, tileSize, appModel);
39 | var destY = getYFromTile(tile ?? 0, tileSize, appModel);
40 | if ((destX - (spriteX ?? 0)).abs() <= 0.1) {
41 | spriteX = destX;
42 | offsetX = 0;
43 | } else {
44 | if (offsetX == 0) {
45 | offsetX = (destX - (spriteX ?? 0)) / 10;
46 | }
47 | if (spriteX != null) {
48 | spriteX = (spriteX ?? 0) + offsetX;
49 | }
50 | playSound(destX, destY, appModel);
51 | }
52 | if ((destY - (spriteY ?? 0)).abs() <= 0.1) {
53 | spriteY = destY;
54 | offsetY = 0;
55 | } else {
56 | if (offsetY == 0) {
57 | offsetY += (destY - (spriteY ?? 0)) / 10;
58 | }
59 | if (spriteX != null) {
60 | spriteY = (spriteY ?? 0) + offsetY;
61 | }
62 | playSound(destX, destY, appModel);
63 | }
64 | }
65 |
66 | void playSound(double destX, double destY, AppModel appModel) async {
67 | if ((destX - (spriteX ?? 0)).abs() <= 0.1 &&
68 | (destY - (spriteY ?? 0)).abs() <= 0.1) {
69 | if (appModel.soundEnabled) {
70 | FlameAudio.play('audio/piece_moved.mp3');
71 | }
72 | }
73 | }
74 |
75 | void initSprite(ChessPiece piece) async {
76 | String color = piece.player == Player.player1 ? 'white' : 'black';
77 | String pieceName = pieceTypeToString(piece.type);
78 | if (piece.type == ChessPieceType.promotion) {
79 | pieceName = 'pawn';
80 | }
81 | sprite = Sprite(await Flame.images.load(
82 | 'pieces/${formatPieceTheme(pieceTheme ?? "")}/${pieceName}_$color.png'));
83 | }
84 |
85 | void initSpritePosition(double tileSize, AppModel appModel) {
86 | spriteX = getXFromTile(tile ?? 0, tileSize, appModel);
87 | spriteY = getYFromTile(tile ?? 0, tileSize, appModel);
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
52 |
54 |
60 |
61 |
62 |
63 |
69 |
71 |
77 |
78 |
79 |
80 |
82 |
83 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/lib/logic/move_calculation/piece_square_tables.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/logic/chess_piece.dart';
2 | import 'package:en_passant/views/components/main_menu_view/game_options/side_picker.dart';
3 |
4 | const KING_TABLE = [
5 | -30, -40, -40, -50, -50, -40, -40, -30,
6 | -30, -40, -40, -50, -50, -40, -40, -30,
7 | -30, -40, -40, -50, -50, -40, -40, -30,
8 | -30, -40, -40, -50, -50, -40, -40, -30,
9 | -20, -30, -30, -40, -40, -30, -30, -20,
10 | -10, -20, -20, -20, -20, -20, -20, -10,
11 | 20, 20, 0, 0, 0, 0, 20, 20,
12 | 20, 30, 10, 0, 0, 10, 30, 20
13 | ];
14 |
15 | const KING_ENDGAME_TABLE = [
16 | -50, -40, -30, -20, -20, -30, -40, -50,
17 | -30, -20, -10, 0, 0, -10, -20, -30,
18 | -30, -10, 20, 30, 30, 20, -10, -30,
19 | -30, -10, 30, 40, 40, 30, -10, -30,
20 | -30, -10, 30, 40, 40, 30, -10, -30,
21 | -30, -10, 20, 30, 30, 20, -10, -30,
22 | -30, -30, 0, 0, 0, 0, -30, -30,
23 | -50, -30, -30, -30, -30, -30, -30, -50
24 | ];
25 |
26 | const QUEEN_TABLE = [
27 | -20, -10, -10, -5, -5, -10, -10, -20,
28 | -10, 0, 0, 0, 0, 0, 0, -10,
29 | -10, 0, 5, 5, 5, 5, 0, -10,
30 | -5, 0, 5, 5, 5, 5, 0, -5,
31 | 0, 0, 5, 5, 5, 5, 0, -5,
32 | -10, 5, 5, 5, 5, 5, 0, -10,
33 | -10, 0, 5, 0, 0, 0, 0, -10,
34 | -20, -10, -10, -5, -5, -10, -10, -20
35 | ];
36 |
37 | const ROOK_TABLE = [
38 | 0, 0, 0, 0, 0, 0, 0, 0,
39 | 5, 10, 10, 10, 10, 10, 10, 5,
40 | -5, 0, 0, 0, 0, 0, 0, -5,
41 | -5, 0, 0, 0, 0, 0, 0, -5,
42 | -5, 0, 0, 0, 0, 0, 0, -5,
43 | -5, 0, 0, 0, 0, 0, 0, -5,
44 | -5, 0, 0, 0, 0, 0, 0, -5,
45 | 0, 0, 0, 5, 5, 0, 0, 0
46 | ];
47 |
48 | const BISHOP_TABLE = [
49 | -20, -10, -10, -10, -10, -10, -10, -20,
50 | -10, 0, 0, 0, 0, 0, 0, -10,
51 | -10, 0, 5, 10, 10, 5, 0, -10,
52 | -10, 5, 5, 10, 10, 5, 5, -10,
53 | -10, 0, 10, 10, 10, 10, 0, -10,
54 | -10, 10, 10, 10, 10, 10, 10, -10,
55 | -10, 5, 0, 0, 0, 0, 5, -10,
56 | -20, -10, -10, -10, -10, -10, -10, -20
57 | ];
58 |
59 | const KNIGHT_TABLE = [
60 | -50, -40, -30, -30, -30, -30, -40, -50,
61 | -40, -20, 0, 0, 0, 0, -20, -40,
62 | -30, 0, 10, 15, 15, 10, 0, -30,
63 | -30, 5, 15, 20, 20, 15, 5, -30,
64 | -30, 0, 15, 20, 20, 15, 0, -30,
65 | -30, 5, 10, 15, 15, 10, 5, -30,
66 | -40, -20, 0, 5, 5, 0, -20, -40,
67 | -50, -40, -30, -30, -30, -30, -40, -50
68 | ];
69 |
70 | const PAWN_TABLE = [
71 | 0, 0, 0, 0, 0, 0, 0, 0,
72 | 50, 50, 50, 50, 50, 50, 50, 50,
73 | 10, 10, 20, 30, 30, 20, 10, 10,
74 | 5, 5, 10, 25, 25, 10, 5, 5,
75 | 0, 0, 0, 20, 20, 0, 0, 0,
76 | 5, -5, -10, 0, 0, -10, -5, 5,
77 | 5, 10, 10, -20, -20, 10, 10, 5,
78 | 0, 0, 0, 0, 0, 0, 0, 0
79 | ];
80 |
81 | int squareValue(ChessPiece piece, bool inEndGame) {
82 | var tile = piece.player == Player.player1 ?
83 | piece.tile : piece.tile + 56 - 16 * (piece.tile / 8).floor();
84 | int value;
85 | switch (piece.type) {
86 | case ChessPieceType.pawn: { value = PAWN_TABLE[tile]; }
87 | break;
88 | case ChessPieceType.knight: { value = KNIGHT_TABLE[tile]; }
89 | break;
90 | case ChessPieceType.bishop: { value = BISHOP_TABLE[tile]; }
91 | break;
92 | case ChessPieceType.rook: { value = ROOK_TABLE[tile]; }
93 | break;
94 | case ChessPieceType.queen: { value = QUEEN_TABLE[tile]; }
95 | break;
96 | case ChessPieceType.king: {
97 | value = inEndGame ? KING_ENDGAME_TABLE[tile] : KING_TABLE[tile];
98 | }
99 | break;
100 | default: { value = 0; }
101 | break;
102 | }
103 | return piece.player == Player.player1 ? value : -value;
104 | }
105 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: en_passant
2 | description: A Flutter chess app.
3 |
4 | # The following line prevents the package from being accidentally published to
5 | # pub.dev using `pub publish`. This is preferred for private packages.
6 | publish_to: "none" # Remove this line if you wish to publish to pub.dev
7 |
8 | # The following defines the version and build number for your application.
9 | # A version number is three numbers separated by dots, like 1.2.43
10 | # followed by an optional build number separated by a +.
11 | # Both the version and the builder number may be overridden in flutter
12 | # build by specifying --build-name and --build-number, respectively.
13 | # In Android, build-name is used as versionName while build-number used as versionCode.
14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
16 | # Read more about iOS versioning at
17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
18 | version: 1.7.5+19
19 |
20 | environment:
21 | sdk: ">=3.0.0"
22 |
23 | dependencies:
24 | flutter:
25 | sdk: flutter
26 | provider: ^6.0.5
27 | flame: ^1.7.3
28 | flame_audio:
29 | url_launcher: ^6.0.2
30 | shared_preferences:
31 | async:
32 |
33 | # The following adds the Cupertino Icons font to your application.
34 | # Use with the CupertinoIcons class for iOS style icons.
35 | cupertino_icons: ^1.0.0
36 |
37 | dev_dependencies:
38 | flutter_test:
39 | sdk: flutter
40 | flutter_launcher_icons: ^0.13.1
41 |
42 | flutter_icons:
43 | android: true
44 | ios: true
45 | image_path_android: "assets/icons/icon.png"
46 | image_path_ios: "assets/icons/icon.png"
47 | adaptive_icon_foreground: "assets/icons/icon_foreground.png"
48 | adaptive_icon_background: "assets/icons/icon_background.png"
49 |
50 | # For information on the generic Dart part of this file, see the
51 | # following page: https://dart.dev/tools/pub/pubspec
52 |
53 | # The following section is specific to Flutter.
54 | flutter:
55 | fonts:
56 | - family: Jura
57 | fonts:
58 | - asset: assets/font/Jura-VariableFont_wght.ttf
59 |
60 | # The following line ensures that the Material Icons font is
61 | # included with your application, so that you can use the icons in
62 | # the material Icons class.
63 | uses-material-design: true
64 |
65 | # To add assets to your application, add an assets section, like this:
66 | # assets:
67 | # - images/a_dot_burr.jpeg
68 | # - images/a_dot_ham.jpeg
69 |
70 | # An image asset can refer to one or more resolution-specific "variants", see
71 | # https://flutter.dev/assets-and-images/#resolution-aware.
72 |
73 | # For details regarding adding assets from package dependencies, see
74 | # https://flutter.dev/assets-and-images/#from-packages
75 |
76 | # To add custom fonts to your application, add a fonts section here,
77 | # in this "flutter" section. Each entry in this list should have a
78 | # "family" key with the font family name, and a "fonts" key with a
79 | # list giving the asset and other descriptors for the font. For
80 | # example:
81 | # fonts:
82 | # - family: Schyler
83 | # fonts:
84 | # - asset: fonts/Schyler-Regular.ttf
85 | # - asset: fonts/Schyler-Italic.ttf
86 | # style: italic
87 | # - family: Trajan Pro
88 | # fonts:
89 | # - asset: fonts/TrajanPro.ttf
90 | # - asset: fonts/TrajanPro_Bold.ttf
91 | # weight: 700
92 | #
93 | # For details regarding fonts from package dependencies,
94 | # see https://flutter.dev/custom-fonts/#from-packages
95 | assets:
96 | - assets/images/
97 | - assets/images/pieces/classic/
98 | - assets/images/pieces/letters/
99 | - assets/images/pieces/angular/
100 | - assets/images/pieces/8-bit/
101 | - assets/images/pieces/videochess/
102 | - assets/images/pieces/lewischessmen/
103 | - assets/images/pieces/mexicocity/
104 | - assets/audio/piece_moved.mp3
105 |
--------------------------------------------------------------------------------
/lib/views/components/chess_view/game_info_and_controls/moves_undo_redo_row/move_list.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/logic/chess_piece.dart';
2 | import 'package:en_passant/logic/move_calculation/move_classes/move_meta.dart';
3 | import 'package:en_passant/logic/shared_functions.dart';
4 | import 'package:en_passant/model/app_model.dart';
5 | import 'package:en_passant/views/components/main_menu_view/game_options/side_picker.dart';
6 | import 'package:en_passant/views/components/shared/text_variable.dart';
7 | import 'package:flutter/cupertino.dart';
8 |
9 | class MoveList extends StatelessWidget {
10 | final AppModel appModel;
11 | final ScrollController scrollController = ScrollController();
12 |
13 | MoveList(this.appModel);
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | WidgetsBinding.instance.addPostFrameCallback((_) => _scrollToBottom());
18 | return Container(
19 | height: 60,
20 | decoration: BoxDecoration(
21 | borderRadius: BorderRadius.all(Radius.circular(15)),
22 | color: Color(0x20000000),
23 | ),
24 | child: SingleChildScrollView(
25 | scrollDirection: Axis.horizontal,
26 | controller: scrollController,
27 | padding: EdgeInsets.only(left: 15, right: 15),
28 | child: Center(child: TextRegular(_allMoves())),
29 | ),
30 | );
31 | }
32 |
33 | void _scrollToBottom() {
34 | if (appModel.moveListUpdated) {
35 | scrollController.jumpTo(scrollController.position.maxScrollExtent);
36 | appModel.moveListUpdated = false;
37 | }
38 | }
39 |
40 | String _allMoves() {
41 | var moveString = '';
42 | appModel.moveMetaList.asMap().forEach((index, move) {
43 | var turnNumber = ((index + 1) / 2).ceil();
44 | if (index % 2 == 0) {
45 | moveString += index == 0 ? '$turnNumber. ' : ' $turnNumber. ';
46 | }
47 | moveString += _moveToString(move);
48 | if (index % 2 == 0) {
49 | moveString += ' ';
50 | }
51 | });
52 | if (appModel.gameOver) {
53 | if (appModel.turn == Player.player1) {
54 | moveString += ' ';
55 | }
56 | if (appModel.stalemate) {
57 | moveString += ' ½-½';
58 | } else {
59 | moveString += appModel.turn == Player.player2 ? ' 1-0' : ' 0-1';
60 | }
61 | }
62 | return moveString;
63 | }
64 |
65 | String _moveToString(MoveMeta meta) {
66 | String move;
67 | if (meta.kingCastle) {
68 | move = 'O-O';
69 | } else if (meta.queenCastle) {
70 | move = 'O-O-O';
71 | } else {
72 | String ambiguity = meta.rowIsAmbiguous
73 | ? '${_colToChar(tileToCol(meta.move?.from ?? 0))}'
74 | : '';
75 | ambiguity +=
76 | meta.colIsAmbiguous ? '${8 - tileToRow(meta.move?.from ?? 0)}' : '';
77 | String takeString = meta.took ? 'x' : '';
78 | String promotion = meta.promotion
79 | ? '=${_pieceToChar(meta.promotionType ?? ChessPieceType.promotion)}'
80 | : '';
81 | String row = '${8 - tileToRow(meta.move?.to ?? 0)}';
82 | String col = '${_colToChar(tileToCol(meta.move?.to ?? 0))}';
83 | move =
84 | '${_pieceToChar(meta.type ?? ChessPieceType.promotion)}$ambiguity$takeString' +
85 | '$col$row$promotion';
86 | }
87 | String check = meta.isCheck ? '+' : '';
88 | String checkmate = meta.isCheckmate && !meta.isStalemate ? '#' : '';
89 | return move + '$check$checkmate';
90 | }
91 |
92 | String _pieceToChar(ChessPieceType type) {
93 | switch (type) {
94 | case ChessPieceType.king:
95 | {
96 | return 'K';
97 | }
98 | case ChessPieceType.queen:
99 | {
100 | return 'Q';
101 | }
102 | case ChessPieceType.rook:
103 | {
104 | return 'R';
105 | }
106 | case ChessPieceType.bishop:
107 | {
108 | return 'B';
109 | }
110 | case ChessPieceType.knight:
111 | {
112 | return 'N';
113 | }
114 | case ChessPieceType.pawn:
115 | {
116 | return '';
117 | }
118 | default:
119 | {
120 | return '?';
121 | }
122 | }
123 | }
124 |
125 | String _colToChar(int col) {
126 | return String.fromCharCode(97 + col);
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "40.png",
5 | "idiom" : "iphone",
6 | "scale" : "2x",
7 | "size" : "20x20"
8 | },
9 | {
10 | "filename" : "60.png",
11 | "idiom" : "iphone",
12 | "scale" : "3x",
13 | "size" : "20x20"
14 | },
15 | {
16 | "filename" : "29.png",
17 | "idiom" : "iphone",
18 | "scale" : "1x",
19 | "size" : "29x29"
20 | },
21 | {
22 | "filename" : "58.png",
23 | "idiom" : "iphone",
24 | "scale" : "2x",
25 | "size" : "29x29"
26 | },
27 | {
28 | "filename" : "87.png",
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "29x29"
32 | },
33 | {
34 | "filename" : "80.png",
35 | "idiom" : "iphone",
36 | "scale" : "2x",
37 | "size" : "40x40"
38 | },
39 | {
40 | "filename" : "120.png",
41 | "idiom" : "iphone",
42 | "scale" : "3x",
43 | "size" : "40x40"
44 | },
45 | {
46 | "filename" : "57.png",
47 | "idiom" : "iphone",
48 | "scale" : "1x",
49 | "size" : "57x57"
50 | },
51 | {
52 | "filename" : "114.png",
53 | "idiom" : "iphone",
54 | "scale" : "2x",
55 | "size" : "57x57"
56 | },
57 | {
58 | "filename" : "120.png",
59 | "idiom" : "iphone",
60 | "scale" : "2x",
61 | "size" : "60x60"
62 | },
63 | {
64 | "filename" : "180.png",
65 | "idiom" : "iphone",
66 | "scale" : "3x",
67 | "size" : "60x60"
68 | },
69 | {
70 | "filename" : "20.png",
71 | "idiom" : "ipad",
72 | "scale" : "1x",
73 | "size" : "20x20"
74 | },
75 | {
76 | "filename" : "40.png",
77 | "idiom" : "ipad",
78 | "scale" : "2x",
79 | "size" : "20x20"
80 | },
81 | {
82 | "filename" : "29.png",
83 | "idiom" : "ipad",
84 | "scale" : "1x",
85 | "size" : "29x29"
86 | },
87 | {
88 | "filename" : "58.png",
89 | "idiom" : "ipad",
90 | "scale" : "2x",
91 | "size" : "29x29"
92 | },
93 | {
94 | "filename" : "40.png",
95 | "idiom" : "ipad",
96 | "scale" : "1x",
97 | "size" : "40x40"
98 | },
99 | {
100 | "filename" : "80.png",
101 | "idiom" : "ipad",
102 | "scale" : "2x",
103 | "size" : "40x40"
104 | },
105 | {
106 | "filename" : "50.png",
107 | "idiom" : "ipad",
108 | "scale" : "1x",
109 | "size" : "50x50"
110 | },
111 | {
112 | "filename" : "100.png",
113 | "idiom" : "ipad",
114 | "scale" : "2x",
115 | "size" : "50x50"
116 | },
117 | {
118 | "filename" : "72.png",
119 | "idiom" : "ipad",
120 | "scale" : "1x",
121 | "size" : "72x72"
122 | },
123 | {
124 | "filename" : "144.png",
125 | "idiom" : "ipad",
126 | "scale" : "2x",
127 | "size" : "72x72"
128 | },
129 | {
130 | "filename" : "76.png",
131 | "idiom" : "ipad",
132 | "scale" : "1x",
133 | "size" : "76x76"
134 | },
135 | {
136 | "filename" : "152.png",
137 | "idiom" : "ipad",
138 | "scale" : "2x",
139 | "size" : "76x76"
140 | },
141 | {
142 | "filename" : "167.png",
143 | "idiom" : "ipad",
144 | "scale" : "2x",
145 | "size" : "83.5x83.5"
146 | },
147 | {
148 | "filename" : "1024.png",
149 | "idiom" : "ios-marketing",
150 | "scale" : "1x",
151 | "size" : "1024x1024"
152 | },
153 | {
154 | "filename" : "48.png",
155 | "idiom" : "watch",
156 | "role" : "notificationCenter",
157 | "scale" : "2x",
158 | "size" : "24x24",
159 | "subtype" : "38mm"
160 | },
161 | {
162 | "filename" : "55.png",
163 | "idiom" : "watch",
164 | "role" : "notificationCenter",
165 | "scale" : "2x",
166 | "size" : "27.5x27.5",
167 | "subtype" : "42mm"
168 | },
169 | {
170 | "filename" : "58.png",
171 | "idiom" : "watch",
172 | "role" : "companionSettings",
173 | "scale" : "2x",
174 | "size" : "29x29"
175 | },
176 | {
177 | "filename" : "87.png",
178 | "idiom" : "watch",
179 | "role" : "companionSettings",
180 | "scale" : "3x",
181 | "size" : "29x29"
182 | },
183 | {
184 | "filename" : "80.png",
185 | "idiom" : "watch",
186 | "role" : "appLauncher",
187 | "scale" : "2x",
188 | "size" : "40x40",
189 | "subtype" : "38mm"
190 | },
191 | {
192 | "filename" : "88.png",
193 | "idiom" : "watch",
194 | "role" : "appLauncher",
195 | "scale" : "2x",
196 | "size" : "44x44",
197 | "subtype" : "40mm"
198 | },
199 | {
200 | "filename" : "100.png",
201 | "idiom" : "watch",
202 | "role" : "appLauncher",
203 | "scale" : "2x",
204 | "size" : "50x50",
205 | "subtype" : "44mm"
206 | },
207 | {
208 | "filename" : "172.png",
209 | "idiom" : "watch",
210 | "role" : "quickLook",
211 | "scale" : "2x",
212 | "size" : "86x86",
213 | "subtype" : "38mm"
214 | },
215 | {
216 | "filename" : "196.png",
217 | "idiom" : "watch",
218 | "role" : "quickLook",
219 | "scale" : "2x",
220 | "size" : "98x98",
221 | "subtype" : "42mm"
222 | },
223 | {
224 | "filename" : "216.png",
225 | "idiom" : "watch",
226 | "role" : "quickLook",
227 | "scale" : "2x",
228 | "size" : "108x108",
229 | "subtype" : "44mm"
230 | },
231 | {
232 | "filename" : "1024.png",
233 | "idiom" : "watch-marketing",
234 | "scale" : "1x",
235 | "size" : "1024x1024"
236 | },
237 | {
238 | "filename" : "16.png",
239 | "idiom" : "mac",
240 | "scale" : "1x",
241 | "size" : "16x16"
242 | },
243 | {
244 | "filename" : "32.png",
245 | "idiom" : "mac",
246 | "scale" : "2x",
247 | "size" : "16x16"
248 | },
249 | {
250 | "filename" : "32.png",
251 | "idiom" : "mac",
252 | "scale" : "1x",
253 | "size" : "32x32"
254 | },
255 | {
256 | "filename" : "64.png",
257 | "idiom" : "mac",
258 | "scale" : "2x",
259 | "size" : "32x32"
260 | },
261 | {
262 | "filename" : "128.png",
263 | "idiom" : "mac",
264 | "scale" : "1x",
265 | "size" : "128x128"
266 | },
267 | {
268 | "filename" : "256.png",
269 | "idiom" : "mac",
270 | "scale" : "2x",
271 | "size" : "128x128"
272 | },
273 | {
274 | "filename" : "256.png",
275 | "idiom" : "mac",
276 | "scale" : "1x",
277 | "size" : "256x256"
278 | },
279 | {
280 | "filename" : "512.png",
281 | "idiom" : "mac",
282 | "scale" : "2x",
283 | "size" : "256x256"
284 | },
285 | {
286 | "filename" : "512.png",
287 | "idiom" : "mac",
288 | "scale" : "1x",
289 | "size" : "512x512"
290 | },
291 | {
292 | "filename" : "1024.png",
293 | "idiom" : "mac",
294 | "scale" : "2x",
295 | "size" : "512x512"
296 | }
297 | ],
298 | "info" : {
299 | "author" : "xcode",
300 | "version" : 1
301 | }
302 | }
303 |
--------------------------------------------------------------------------------
/lib/model/app_model.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:math';
3 |
4 | import 'package:en_passant/logic/chess_game.dart';
5 | import 'package:en_passant/logic/move_calculation/move_classes/move_meta.dart';
6 | import 'package:en_passant/logic/shared_functions.dart';
7 | import 'package:en_passant/views/components/main_menu_view/game_options/side_picker.dart';
8 | import 'package:flutter/material.dart';
9 | import 'package:shared_preferences/shared_preferences.dart';
10 |
11 | import 'app_themes.dart';
12 |
13 | const TIMER_ACCURACY_MS = 100;
14 | const PIECE_THEMES = [
15 | 'Classic',
16 | 'Angular',
17 | '8-Bit',
18 | 'Letters',
19 | 'Video Chess',
20 | 'Lewis Chessmen',
21 | 'Mexico City'
22 | ];
23 |
24 | class AppModel extends ChangeNotifier {
25 | int playerCount = 1;
26 | int aiDifficulty = 3;
27 | Player selectedSide = Player.player1;
28 | Player playerSide = Player.player1;
29 | int timeLimit = 0;
30 | String pieceTheme = 'Classic';
31 | String themeName = 'Green';
32 | bool showMoveHistory = true;
33 | bool allowUndoRedo = true;
34 | bool soundEnabled = true;
35 | bool showHints = true;
36 | bool flip = true;
37 |
38 | ChessGame? game;
39 | Timer? timer;
40 | bool gameOver = false;
41 | bool stalemate = false;
42 | bool promotionRequested = false;
43 | bool moveListUpdated = false;
44 | Player turn = Player.player1;
45 | List moveMetaList = [];
46 | Duration player1TimeLeft = Duration.zero;
47 | Duration player2TimeLeft = Duration.zero;
48 |
49 | List get pieceThemes {
50 | var pieceThemes = List.from(PIECE_THEMES);
51 | pieceThemes.sort();
52 | return pieceThemes;
53 | }
54 |
55 | AppTheme get theme {
56 | return themeList[themeIndex];
57 | }
58 |
59 | int get themeIndex {
60 | var themeIndex = 0;
61 | themeList.asMap().forEach((index, theme) {
62 | if (theme.name == themeName) {
63 | themeIndex = index;
64 | }
65 | });
66 | return themeIndex;
67 | }
68 |
69 | int get pieceThemeIndex {
70 | var pieceThemeIndex = 0;
71 | pieceThemes.asMap().forEach((index, theme) {
72 | if (theme == pieceTheme) {
73 | pieceThemeIndex = index;
74 | }
75 | });
76 | return pieceThemeIndex;
77 | }
78 |
79 | Player get aiTurn {
80 | return oppositePlayer(playerSide);
81 | }
82 |
83 | bool get isAIsTurn {
84 | return playingWithAI && (turn == aiTurn);
85 | }
86 |
87 | bool get playingWithAI {
88 | return playerCount == 1;
89 | }
90 |
91 | AppModel() {
92 | loadSharedPrefs();
93 | }
94 |
95 | void newGame(BuildContext context, {bool notify = true}) {
96 | game?.cancelAIMove();
97 | timer?.cancel();
98 | gameOver = false;
99 | stalemate = false;
100 | turn = Player.player1;
101 | moveMetaList = [];
102 | player1TimeLeft = Duration(minutes: timeLimit);
103 | player2TimeLeft = Duration(minutes: timeLimit);
104 | if (selectedSide == Player.random) {
105 | playerSide =
106 | Random.secure().nextInt(2) == 0 ? Player.player1 : Player.player2;
107 | }
108 | game = ChessGame(this, context);
109 | timer = Timer.periodic(Duration(milliseconds: TIMER_ACCURACY_MS), (timer) {
110 | turn == Player.player1
111 | ? decrementPlayer1Timer()
112 | : decrementPlayer2Timer();
113 | if ((player1TimeLeft == Duration.zero ||
114 | player2TimeLeft == Duration.zero) &&
115 | timeLimit != 0) {
116 | endGame();
117 | }
118 | });
119 | if (notify) {
120 | notifyListeners();
121 | }
122 | }
123 |
124 | void exitChessView() {
125 | game?.cancelAIMove();
126 | timer?.cancel();
127 | notifyListeners();
128 | }
129 |
130 | void pushMoveMeta(MoveMeta meta) {
131 | moveMetaList.add(meta);
132 | moveListUpdated = true;
133 | notifyListeners();
134 | }
135 |
136 | void popMoveMeta() {
137 | moveMetaList.removeLast();
138 | moveListUpdated = true;
139 | notifyListeners();
140 | }
141 |
142 | void endGame() {
143 | gameOver = true;
144 | notifyListeners();
145 | }
146 |
147 | void undoEndGame() {
148 | gameOver = false;
149 | notifyListeners();
150 | }
151 |
152 | void changeTurn() {
153 | turn = oppositePlayer(turn);
154 | notifyListeners();
155 | }
156 |
157 | void requestPromotion() {
158 | promotionRequested = true;
159 | notifyListeners();
160 | }
161 |
162 | void setPlayerCount(int? count) {
163 | if (count != null) {
164 | playerCount = count;
165 | notifyListeners();
166 | }
167 | }
168 |
169 | void setAIDifficulty(int? difficulty) {
170 | if (difficulty != null) {
171 | aiDifficulty = difficulty;
172 | notifyListeners();
173 | }
174 | }
175 |
176 | void setPlayerSide(Player? side) {
177 | if (side != null) {
178 | selectedSide = side;
179 | if (side != Player.random) {
180 | playerSide = side;
181 | }
182 | notifyListeners();
183 | }
184 | }
185 |
186 | void setTimeLimit(int? duration) {
187 | if (duration != null) {
188 | timeLimit = duration;
189 | player1TimeLeft = Duration(minutes: timeLimit);
190 | player2TimeLeft = Duration(minutes: timeLimit);
191 | notifyListeners();
192 | }
193 | }
194 |
195 | void decrementPlayer1Timer() {
196 | if (player1TimeLeft.inMilliseconds > 0 && !gameOver) {
197 | player1TimeLeft = Duration(
198 | milliseconds: player1TimeLeft.inMilliseconds - TIMER_ACCURACY_MS);
199 | notifyListeners();
200 | }
201 | }
202 |
203 | void decrementPlayer2Timer() {
204 | if (player2TimeLeft.inMilliseconds > 0 && !gameOver) {
205 | player2TimeLeft = Duration(
206 | milliseconds: player2TimeLeft.inMilliseconds - TIMER_ACCURACY_MS);
207 | notifyListeners();
208 | }
209 | }
210 |
211 | void setTheme(int index) async {
212 | themeName = themeList[index].name ?? "";
213 | final prefs = await SharedPreferences.getInstance();
214 | prefs.setString('themeName', themeName);
215 | notifyListeners();
216 | }
217 |
218 | void setPieceTheme(int index) async {
219 | pieceTheme = pieceThemes[index];
220 | final prefs = await SharedPreferences.getInstance();
221 | prefs.setString('pieceTheme', pieceTheme);
222 | notifyListeners();
223 | }
224 |
225 | void setShowMoveHistory(bool show) async {
226 | final prefs = await SharedPreferences.getInstance();
227 | showMoveHistory = show;
228 | prefs.setBool('showMoveHistory', show);
229 | notifyListeners();
230 | }
231 |
232 | void setSoundEnabled(bool enabled) async {
233 | final prefs = await SharedPreferences.getInstance();
234 | soundEnabled = enabled;
235 | prefs.setBool('soundEnabled', enabled);
236 | notifyListeners();
237 | }
238 |
239 | void setShowHints(bool show) async {
240 | final prefs = await SharedPreferences.getInstance();
241 | showHints = show;
242 | prefs.setBool('showHints', show);
243 | notifyListeners();
244 | }
245 |
246 | void setFlipBoard(bool flip) async {
247 | final prefs = await SharedPreferences.getInstance();
248 | this.flip = flip;
249 | prefs.setBool('flip', flip);
250 | notifyListeners();
251 | }
252 |
253 | void setAllowUndoRedo(bool allow) async {
254 | final prefs = await SharedPreferences.getInstance();
255 | this.allowUndoRedo = allow;
256 | prefs.setBool('allowUndoRedo', allow);
257 | notifyListeners();
258 | }
259 |
260 | void loadSharedPrefs() async {
261 | final prefs = await SharedPreferences.getInstance();
262 | themeName = prefs.getString('themeName') ?? 'Green';
263 | pieceTheme = prefs.getString('pieceTheme') ?? 'Classic';
264 | showMoveHistory = prefs.getBool('showMoveHistory') ?? true;
265 | soundEnabled = prefs.getBool('soundEnabled') ?? true;
266 | showHints = prefs.getBool('showHints') ?? true;
267 | flip = prefs.getBool('flip') ?? true;
268 | allowUndoRedo = prefs.getBool('allowUndoRedo') ?? true;
269 | notifyListeners();
270 | }
271 |
272 | void update() {
273 | notifyListeners();
274 | }
275 | }
276 |
--------------------------------------------------------------------------------
/lib/logic/move_calculation/move_calculation.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/logic/move_calculation/move_classes/direction.dart';
2 | import 'package:en_passant/logic/move_calculation/move_classes/move_and_value.dart';
3 | import 'package:en_passant/logic/shared_functions.dart';
4 | import 'package:en_passant/views/components/chess_view/promotion_dialog.dart';
5 | import 'package:en_passant/views/components/main_menu_view/game_options/side_picker.dart';
6 |
7 | import '../chess_board.dart';
8 | import '../chess_piece.dart';
9 | import 'move_classes/move.dart';
10 |
11 | const PAWN_DIAGONALS_1 = [DOWN_LEFT, DOWN_RIGHT];
12 | const PAWN_DIAGONALS_2 = [UP_LEFT, UP_RIGHT];
13 | const KNIGHT_MOVES = [
14 | Direction(1, 2),
15 | Direction(-1, 2),
16 | Direction(1, -2),
17 | Direction(-1, -2),
18 | Direction(2, 1),
19 | Direction(-2, 1),
20 | Direction(2, -1),
21 | Direction(-2, -1)
22 | ];
23 | const BISHOP_MOVES = [UP_RIGHT, DOWN_RIGHT, DOWN_LEFT, UP_LEFT];
24 | const ROOK_MOVES = [UP, RIGHT, DOWN, LEFT];
25 | const KING_QUEEN_MOVES = [
26 | UP,
27 | UP_RIGHT,
28 | RIGHT,
29 | DOWN_RIGHT,
30 | DOWN,
31 | DOWN_LEFT,
32 | LEFT,
33 | UP_LEFT
34 | ];
35 |
36 | List allMoves(Player player, ChessBoard board, int aiDifficulty) {
37 | List moves = [];
38 | var pieces = List.from(piecesForPlayer(player, board));
39 | for (var piece in pieces) {
40 | var tiles = movesForPiece(piece, board);
41 | for (var tile in tiles) {
42 | if (piece.type == ChessPieceType.pawn &&
43 | (tileToRow(tile) == 0 || tileToRow(tile) == 7)) {
44 | for (var promotion in PROMOTIONS) {
45 | var move =
46 | MoveAndValue(Move(piece.tile, tile, promotionType: promotion), 0);
47 | push(move.move, board, promotionType: promotion);
48 | move.value = boardValue(board);
49 | pop(board);
50 | moves.add(move);
51 | }
52 | } else {
53 | var move = MoveAndValue(Move(piece.tile, tile), 0);
54 | push(move.move, board);
55 | move.value = boardValue(board);
56 | pop(board);
57 | moves.add(move);
58 | }
59 | }
60 | }
61 | moves.sort((a, b) => _compareMoves(a, b, player, board));
62 | return moves.map((move) => move.move).toList();
63 | }
64 |
65 | int _compareMoves(
66 | MoveAndValue a, MoveAndValue b, Player player, ChessBoard board) {
67 | return player == Player.player1
68 | ? b.value.compareTo(a.value)
69 | : a.value.compareTo(b.value);
70 | }
71 |
72 | List movesForPiece(ChessPiece piece, ChessBoard board,
73 | {bool legal = true}) {
74 | List moves;
75 | switch (piece.type) {
76 | case ChessPieceType.pawn:
77 | {
78 | moves = _pawnMoves(piece, board);
79 | }
80 | break;
81 | case ChessPieceType.knight:
82 | {
83 | moves = _knightMoves(piece, board);
84 | }
85 | break;
86 | case ChessPieceType.bishop:
87 | {
88 | moves = _bishopMoves(piece, board);
89 | }
90 | break;
91 | case ChessPieceType.rook:
92 | {
93 | moves = _rookMoves(piece, board, legal);
94 | }
95 | break;
96 | case ChessPieceType.queen:
97 | {
98 | moves = _queenMoves(piece, board);
99 | }
100 | break;
101 | case ChessPieceType.king:
102 | {
103 | moves = _kingMoves(piece, board, legal);
104 | }
105 | break;
106 | default:
107 | {
108 | moves = [];
109 | }
110 | }
111 | if (legal) {
112 | moves.removeWhere((move) => _movePutsKingInCheck(piece, move, board));
113 | }
114 | return moves;
115 | }
116 |
117 | List _pawnMoves(ChessPiece pawn, ChessBoard board) {
118 | List moves = [];
119 | var offset = pawn.player == Player.player1 ? -8 : 8;
120 | var firstTile = pawn.tile + offset;
121 | if (board.tiles[firstTile] == null) {
122 | moves.add(firstTile);
123 | if (pawn.moveCount == 0) {
124 | var secondTile = firstTile + offset;
125 | if (board.tiles[secondTile] == null) {
126 | moves.add(secondTile);
127 | }
128 | }
129 | }
130 | return moves + _pawnDiagonalAttacks(pawn, board);
131 | }
132 |
133 | List _pawnDiagonalAttacks(ChessPiece pawn, ChessBoard board) {
134 | List moves = [];
135 | var diagonals =
136 | pawn.player == Player.player1 ? PAWN_DIAGONALS_1 : PAWN_DIAGONALS_2;
137 | for (var diagonal in diagonals) {
138 | var row = tileToRow(pawn.tile) + diagonal.up;
139 | var col = tileToCol(pawn.tile) + diagonal.right;
140 | if (_inBounds(row, col)) {
141 | var takenPiece = board.tiles[_rowColToTile(row, col)];
142 | if ((takenPiece != null &&
143 | takenPiece.player == oppositePlayer(pawn.player)) ||
144 | _canTakeEnPassant(pawn.player, _rowColToTile(row, col), board)) {
145 | moves.add(_rowColToTile(row, col));
146 | }
147 | }
148 | }
149 | return moves;
150 | }
151 |
152 | bool _canTakeEnPassant(Player pawnPlayer, int diagonal, ChessBoard board) {
153 | var offset = (pawnPlayer == Player.player1) ? 8 : -8;
154 | var takenPiece = board.tiles[diagonal + offset];
155 | return takenPiece != null &&
156 | takenPiece.player != pawnPlayer &&
157 | takenPiece == board.enPassantPiece;
158 | }
159 |
160 | List _knightMoves(ChessPiece knight, ChessBoard board) {
161 | return _movesFromDirections(knight, board, KNIGHT_MOVES, false);
162 | }
163 |
164 | List _bishopMoves(ChessPiece bishop, ChessBoard board) {
165 | return _movesFromDirections(bishop, board, BISHOP_MOVES, true);
166 | }
167 |
168 | List _rookMoves(ChessPiece rook, ChessBoard board, bool legal) {
169 | return _movesFromDirections(rook, board, ROOK_MOVES, true) +
170 | _rookCastleMove(rook, board, legal);
171 | }
172 |
173 | List _queenMoves(ChessPiece queen, ChessBoard board) {
174 | return _movesFromDirections(queen, board, KING_QUEEN_MOVES, true);
175 | }
176 |
177 | List _kingMoves(ChessPiece king, ChessBoard board, bool legal) {
178 | return _movesFromDirections(king, board, KING_QUEEN_MOVES, false) +
179 | _kingCastleMoves(king, board, legal);
180 | }
181 |
182 | List _rookCastleMove(ChessPiece rook, ChessBoard board, bool legal) {
183 | if (!legal || !kingInCheck(rook.player, board)) {
184 | var king = kingForPlayer(rook.player, board);
185 | if (_canCastle(king, rook, board, legal)) {
186 | return [king?.tile ?? 0];
187 | }
188 | }
189 | return [];
190 | }
191 |
192 | List _kingCastleMoves(ChessPiece king, ChessBoard board, bool legal) {
193 | List moves = [];
194 | if (!legal || !kingInCheck(king.player, board)) {
195 | for (var rook in rooksForPlayer(king.player, board)) {
196 | if (_canCastle(king, rook, board, legal)) {
197 | moves.add(rook.tile);
198 | }
199 | }
200 | }
201 | return moves;
202 | }
203 |
204 | bool _canCastle(
205 | ChessPiece? king, ChessPiece rook, ChessBoard board, bool legal) {
206 | if (rook.moveCount == 0 && king?.moveCount == 0) {
207 | var offset = (king?.tile ?? 0) - rook.tile > 0 ? 1 : -1;
208 | var tile = rook.tile;
209 | while (tile != king?.tile) {
210 | tile += offset;
211 | if ((board.tiles[tile] != null && tile != king?.tile) ||
212 | (legal &&
213 | _kingInCheckAtTile(
214 | tile, king?.player ?? Player.player1, board))) {
215 | return false;
216 | }
217 | }
218 | return true;
219 | }
220 | return false;
221 | }
222 |
223 | List _movesFromDirections(ChessPiece piece, ChessBoard board,
224 | List directions, bool repeat) {
225 | List moves = [];
226 | for (var direction in directions) {
227 | var row = tileToRow(piece.tile);
228 | var col = tileToCol(piece.tile);
229 | do {
230 | row += direction.up;
231 | col += direction.right;
232 | if (_inBounds(row, col)) {
233 | var possiblePiece = board.tiles[_rowColToTile(row, col)];
234 | if (possiblePiece != null) {
235 | if (possiblePiece.player != piece.player) {
236 | moves.add(_rowColToTile(row, col));
237 | }
238 | break;
239 | } else {
240 | moves.add(_rowColToTile(row, col));
241 | }
242 | }
243 | if (!repeat) {
244 | break;
245 | }
246 | } while (_inBounds(row, col));
247 | }
248 | return moves;
249 | }
250 |
251 | bool _movePutsKingInCheck(ChessPiece piece, int move, ChessBoard board) {
252 | push(Move(piece.tile, move), board);
253 | var check = kingInCheck(piece.player, board);
254 | pop(board);
255 | return check;
256 | }
257 |
258 | bool _kingInCheckAtTile(int tile, Player player, ChessBoard board) {
259 | for (var piece in piecesForPlayer(oppositePlayer(player), board)) {
260 | if (movesForPiece(piece, board, legal: false).contains(tile)) {
261 | return true;
262 | }
263 | }
264 | return false;
265 | }
266 |
267 | bool kingInCheck(Player player, ChessBoard board) {
268 | for (var piece in piecesForPlayer(oppositePlayer(player), board)) {
269 | if (movesForPiece(piece, board, legal: false)
270 | .contains(kingForPlayer(player, board)?.tile)) {
271 | return true;
272 | }
273 | }
274 | return false;
275 | }
276 |
277 | bool kingInCheckmate(Player player, ChessBoard board) {
278 | for (var piece in piecesForPlayer(player, board)) {
279 | if (movesForPiece(piece, board).isNotEmpty) {
280 | return false;
281 | }
282 | }
283 | return true;
284 | }
285 |
286 | bool _inBounds(int row, int col) {
287 | return row >= 0 && row < 8 && col >= 0 && col < 8;
288 | }
289 |
290 | int _rowColToTile(int row, int col) {
291 | return row * 8 + col;
292 | }
293 |
--------------------------------------------------------------------------------
/lib/model/app_themes.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class AppTheme {
4 | String? name;
5 | LinearGradient? background;
6 | Color lightTile;
7 | Color darkTile;
8 | Color moveHint;
9 | Color checkHint;
10 | Color latestMove;
11 | Color border;
12 |
13 | AppTheme({
14 | this.name,
15 | this.background,
16 | this.lightTile = const Color(0xFFC9B28F),
17 | this.darkTile = const Color(0xFF69493b),
18 | this.moveHint = const Color(0xdd5c81c4),
19 | this.latestMove = const Color(0xccc47937),
20 | this.checkHint = const Color(0x88ff0000),
21 | this.border = const Color(0xffffffff),
22 | });
23 | }
24 |
25 | List get themeList {
26 | var themeList = [
27 | AppTheme(
28 | name: 'Bismuth',
29 | background: LinearGradient(
30 | begin: Alignment.topCenter,
31 | end: Alignment.bottomCenter,
32 | colors: [
33 | Color(0xff2560a5),
34 | Color(0xff2f6e72),
35 | Color(0xff4faa55),
36 | Color(0xffe6de50),
37 | Color(0xffdb70eb),
38 | ],
39 | ),
40 | lightTile: Color(0xff4faa55),
41 | darkTile: Color(0xff2560a5),
42 | moveHint: Color(0xaaffff00),
43 | latestMove: Color(0xaadb70eb),
44 | border: Color(0xff184387),
45 | ),
46 | AppTheme(
47 | name: 'Candy',
48 | background: LinearGradient(
49 | begin: Alignment.topCenter,
50 | end: Alignment.bottomCenter,
51 | colors: [
52 | Color(0xff8934eb),
53 | Color(0xff004f80),
54 | ],
55 | ),
56 | lightTile: Color(0xff0088ff),
57 | darkTile: Color(0xff8934eb),
58 | moveHint: Color(0xdddb70eb),
59 | checkHint: Color(0x88ff0000),
60 | latestMove: Color(0xcc2dba6f),
61 | border: Color(0xffdb70eb),
62 | ),
63 | AppTheme(
64 | name: 'Blue',
65 | background: LinearGradient(
66 | begin: Alignment.topCenter,
67 | end: Alignment.bottomCenter,
68 | colors: [
69 | Color(0xff236e91),
70 | Color(0xff0f4964),
71 | ],
72 | ),
73 | ),
74 | AppTheme(
75 | name: 'Green',
76 | background: LinearGradient(
77 | begin: Alignment.topCenter,
78 | end: Alignment.bottomCenter,
79 | colors: [
80 | Color(0xff25804f),
81 | Color(0xff00584f),
82 | ],
83 | ),
84 | ),
85 | AppTheme(
86 | name: 'Red',
87 | background: LinearGradient(
88 | begin: Alignment.topCenter,
89 | end: Alignment.bottomCenter,
90 | colors: [
91 | Color(0xfff54242),
92 | Color(0xff912323),
93 | ],
94 | ),
95 | ),
96 | AppTheme(
97 | name: 'Iridescent',
98 | background: LinearGradient(
99 | begin: Alignment.topCenter,
100 | end: Alignment.bottomCenter,
101 | colors: [
102 | Color(0xffb2b2b2),
103 | Color(0xffb24d00),
104 | Color(0xffb2004d),
105 | Color(0xff004db2),
106 | Color(0xff4d4d4d),
107 | ],
108 | ),
109 | lightTile: Color(0xffabc0d1),
110 | darkTile: Color(0xff7991a6),
111 | moveHint: Color(0xcc004db2),
112 | border: Color(0xff4d5d6b),
113 | ),
114 | AppTheme(
115 | name: 'Black & White',
116 | background: LinearGradient(
117 | begin: Alignment.topCenter,
118 | end: Alignment.bottomCenter,
119 | colors: [
120 | Color(0xffb2b2b2),
121 | Color(0xff4e4e4e),
122 | ],
123 | ),
124 | lightTile: Color(0xffb2b2b2),
125 | darkTile: Color(0xff808080),
126 | moveHint: Color(0xdd555555),
127 | checkHint: Color(0xff333333),
128 | latestMove: Color(0xdddddddd),
129 | ),
130 | AppTheme(
131 | name: 'Opal',
132 | background: LinearGradient(
133 | begin: Alignment.topCenter,
134 | end: Alignment.bottomCenter,
135 | colors: [
136 | Color(0xffb5b8c9),
137 | Color(0xffc7958a),
138 | Color(0xffdbd879),
139 | Color(0xff96cf8a),
140 | Color(0xff6a81df),
141 | Color(0xff507fc2),
142 | ],
143 | ),
144 | lightTile: Color(0xffd1d7e0),
145 | darkTile: Color(0xff6494d6),
146 | moveHint: Color(0xcc8ad979),
147 | latestMove: Color(0xddc7958a),
148 | border: Color(0xff9cc5d9),
149 | ),
150 | AppTheme(
151 | name: 'Regal',
152 | background: LinearGradient(
153 | begin: Alignment.topCenter,
154 | end: Alignment.bottomCenter,
155 | colors: [
156 | Color(0xff2c0078),
157 | Color(0xff6d3ac7),
158 | ],
159 | ),
160 | lightTile: Color(0xfff0c76e),
161 | darkTile: Color(0xff942222),
162 | moveHint: Color(0xcc5d27ba),
163 | checkHint: Color(0xffff0000),
164 | border: Color(0xff6b0707),
165 | ),
166 | AppTheme(
167 | name: 'Vaporwave',
168 | background: LinearGradient(
169 | begin: Alignment.topCenter,
170 | end: Alignment.bottomCenter,
171 | colors: [
172 | Color(0xffff78ed),
173 | Color(0xff602af5),
174 | ],
175 | ),
176 | lightTile: Color(0xffff78ed),
177 | darkTile: Color(0xff602af5),
178 | moveHint: Color(0xddd1116b),
179 | checkHint: Color(0x80ff0000),
180 | latestMove: Color(0xaa00d0d4),
181 | border: Color(0xff926bff),
182 | ),
183 | AppTheme(
184 | name: 'Dark',
185 | background: LinearGradient(
186 | begin: Alignment.topCenter,
187 | end: Alignment.bottomCenter,
188 | colors: [
189 | Color(0xff1e1e1e),
190 | Color(0xff2e2e2e),
191 | ],
192 | ),
193 | border: Color(0xff888888),
194 | ),
195 | AppTheme(
196 | name: 'Light',
197 | background: LinearGradient(
198 | begin: Alignment.topCenter,
199 | end: Alignment.bottomCenter,
200 | colors: [
201 | Color(0xffaeaeae),
202 | Color(0xff8e8e8e),
203 | ],
204 | ),
205 | ),
206 | AppTheme(
207 | name: 'E2-E4',
208 | background: LinearGradient(
209 | begin: Alignment.topCenter,
210 | end: Alignment.bottomCenter,
211 | colors: [
212 | Color(0xfff9f1c2),
213 | Color(0xff530b0e),
214 | ],
215 | ),
216 | lightTile: Color(0xffd4cb97),
217 | darkTile: Color(0xff73181c),
218 | checkHint: Color(0xffff0000),
219 | moveHint: Color(0xdd666666),
220 | ),
221 | AppTheme(
222 | name: 'Gold Ore',
223 | background: LinearGradient(
224 | begin: Alignment.topCenter,
225 | end: Alignment.bottomCenter,
226 | colors: [
227 | Color(0xff595959),
228 | Color(0xff807126),
229 | ],
230 | ),
231 | lightTile: Color(0xfff0d656),
232 | darkTile: Color(0xff807126),
233 | moveHint: Color(0xdd444444),
234 | border: Color(0xff5c563c),
235 | ),
236 | AppTheme(
237 | name: 'Aquamarine',
238 | background: LinearGradient(
239 | begin: Alignment.topCenter,
240 | end: Alignment.bottomCenter,
241 | colors: [
242 | Color(0xff03e8fc),
243 | Color(0xff0345fc),
244 | ],
245 | ),
246 | lightTile: Color(0xff03e8fc),
247 | darkTile: Color(0xff0345fc),
248 | moveHint: Color(0xdd2aad46),
249 | latestMove: Color(0xdd0683d6),
250 | border: Color(0xffc2e3ff),
251 | ),
252 | AppTheme(
253 | name: 'Video Chess',
254 | background: LinearGradient(
255 | begin: Alignment.topCenter,
256 | end: Alignment.bottomCenter,
257 | colors: [
258 | Color(0xff382db5),
259 | Color(0xff382db5),
260 | ]),
261 | lightTile: Color(0xff584fdb),
262 | darkTile: Color(0xff382db5),
263 | moveHint: Color(0x88c4c6ff),
264 | latestMove: Color(0x88c47937),
265 | ),
266 | AppTheme(
267 | name: 'AMOLED',
268 | background: LinearGradient(
269 | begin: Alignment.topCenter,
270 | end: Alignment.bottomCenter,
271 | colors: [
272 | Color(0xff000000),
273 | Color(0xff000000),
274 | ],
275 | ),
276 | lightTile: Color(0xff444444),
277 | darkTile: Color(0xff333333),
278 | border: Color(0xff555555),
279 | ),
280 | AppTheme(
281 | name: 'Lewis',
282 | background: LinearGradient(
283 | begin: Alignment.topCenter,
284 | end: Alignment.bottomCenter,
285 | colors: [
286 | Color(0xff423428),
287 | Color(0xff423428),
288 | ],
289 | ),
290 | lightTile: Color(0xffdbd1c1),
291 | darkTile: Color(0xffab3848),
292 | moveHint: Color(0xdd800b0b),
293 | latestMove: Color(0xddcc9c6c),
294 | border: Color(0xffbdaa8c),
295 | ),
296 | AppTheme(
297 | name: 'Neon',
298 | background: LinearGradient(
299 | begin: Alignment.topCenter,
300 | end: Alignment.bottomCenter,
301 | colors: [
302 | Color(0xffb734eb),
303 | Color(0xff34d3eb),
304 | Color(0xff34eb62),
305 | ],
306 | ),
307 | lightTile: Color(0xff34d3eb),
308 | darkTile: Color(0xffb734eb),
309 | moveHint: Color(0xdd34eb62),
310 | latestMove: Color(0xddd9eb34),
311 | ),
312 | AppTheme(
313 | name: 'Pink Marble',
314 | background: LinearGradient(
315 | begin: Alignment.topCenter,
316 | end: Alignment.bottomCenter,
317 | colors: [
318 | Color(0xff45a881),
319 | Color(0xff2782b0),
320 | ],
321 | ),
322 | lightTile: Color(0xffebc0c0),
323 | darkTile: Color(0xff472d22),
324 | moveHint: Color(0xaa45a881),
325 | latestMove: Color(0xaa2782b0),
326 | border: Color(0xffebc0c0),
327 | ),
328 | AppTheme(
329 | name: 'Cherry-Coloured Funk',
330 | background: LinearGradient(
331 | begin: Alignment.topCenter,
332 | end: Alignment.bottomCenter,
333 | colors: [
334 | Color(0xff434783),
335 | Color(0xffdc3b39),
336 | ],
337 | ),
338 | lightTile: Color(0xffdb5e5c),
339 | darkTile: Color(0xff645183),
340 | moveHint: Color(0xaabdacce),
341 | latestMove: Color(0xaaf0b35d),
342 | border: Color(0xff434783),
343 | ),
344 | ];
345 | themeList.sort((a, b) => a.name?.compareTo(b.name ?? "") ?? 0);
346 | return themeList;
347 | }
348 |
--------------------------------------------------------------------------------
/lib/logic/chess_game.dart:
--------------------------------------------------------------------------------
1 | import 'package:async/async.dart';
2 | import 'package:en_passant/logic/chess_piece_sprite.dart';
3 | import 'package:en_passant/logic/move_calculation/ai_move_calculation.dart';
4 | import 'package:en_passant/logic/move_calculation/move_calculation.dart';
5 | import 'package:en_passant/logic/move_calculation/move_classes/move_meta.dart';
6 | import 'package:en_passant/logic/shared_functions.dart';
7 | import 'package:en_passant/model/app_model.dart';
8 | import 'package:en_passant/views/components/main_menu_view/game_options/side_picker.dart';
9 | import 'package:flame/events.dart';
10 | import 'package:flame/game.dart';
11 | import 'package:flutter/cupertino.dart';
12 | import 'package:flutter/foundation.dart';
13 |
14 | import 'chess_board.dart';
15 | import 'chess_piece.dart';
16 | import 'move_calculation/move_classes/move.dart';
17 |
18 | class ChessGame extends Game with TapDetector {
19 | double? width;
20 | double? tileSize;
21 | AppModel appModel;
22 | BuildContext context;
23 | ChessBoard board = ChessBoard();
24 | Map spriteMap = Map();
25 |
26 | CancelableOperation? aiOperation;
27 | List validMoves = [];
28 | ChessPiece? selectedPiece;
29 | int? checkHintTile;
30 | Move? latestMove;
31 |
32 | ChessGame(this.appModel, this.context) {
33 | width = MediaQuery.of(context).size.width - 68;
34 | tileSize = (width ?? 0) / 8;
35 | for (var piece in board.player1Pieces + board.player2Pieces) {
36 | spriteMap[piece] = ChessPieceSprite(piece, appModel.pieceTheme);
37 | }
38 | _initSpritePositions();
39 | if (appModel.isAIsTurn) {
40 | _aiMove();
41 | }
42 | }
43 |
44 | @override
45 | void onTapDown(TapDownInfo details) {
46 | if (appModel.gameOver || !(appModel.isAIsTurn)) {
47 | var tile = _vector2ToTile(details.eventPosition.widget);
48 | var touchedPiece = board.tiles[tile];
49 | if (touchedPiece == selectedPiece) {
50 | validMoves = [];
51 | selectedPiece = null;
52 | } else {
53 | if (selectedPiece != null &&
54 | touchedPiece != null &&
55 | touchedPiece.player == selectedPiece?.player) {
56 | if (validMoves.contains(tile)) {
57 | _movePiece(tile);
58 | } else {
59 | validMoves = [];
60 | _selectPiece(touchedPiece);
61 | }
62 | } else if (selectedPiece == null) {
63 | _selectPiece(touchedPiece);
64 | } else {
65 | _movePiece(tile);
66 | }
67 | }
68 | }
69 | }
70 |
71 | @override
72 | void render(Canvas canvas) {
73 | _drawBoard(canvas);
74 | if (appModel.showHints) {
75 | _drawCheckHint(canvas);
76 | _drawLatestMove(canvas);
77 | }
78 | _drawSelectedPieceHint(canvas);
79 | _drawPieces(canvas);
80 | if (appModel.showHints) {
81 | _drawMoveHints(canvas);
82 | }
83 | }
84 |
85 | @override
86 | void update(double t) {
87 | for (var piece in board.player1Pieces + board.player2Pieces) {
88 | spriteMap[piece]?.update(tileSize ?? 0, appModel, piece);
89 | }
90 | }
91 |
92 | void _initSpritePositions() {
93 | for (var piece in board.player1Pieces + board.player2Pieces) {
94 | spriteMap[piece]?.initSpritePosition(tileSize ?? 0, appModel);
95 | }
96 | }
97 |
98 | void _selectPiece(ChessPiece? piece) {
99 | if (piece != null) {
100 | if (piece.player == appModel.turn) {
101 | selectedPiece = piece;
102 | if (selectedPiece != null) {
103 | validMoves = movesForPiece(piece, board);
104 | }
105 | if (validMoves.isEmpty) {
106 | selectedPiece = null;
107 | }
108 | }
109 | }
110 | }
111 |
112 | void _movePiece(int tile) {
113 | if (validMoves.contains(tile)) {
114 | validMoves = [];
115 | var meta =
116 | push(Move(selectedPiece?.tile ?? 0, tile), board, getMeta: true);
117 | if (meta.promotion) {
118 | appModel.requestPromotion();
119 | }
120 | _moveCompletion(meta, changeTurn: !meta.promotion);
121 | }
122 | }
123 |
124 | void _aiMove() async {
125 | await Future.delayed(Duration(milliseconds: 500));
126 | var args = Map();
127 | args['aiPlayer'] = appModel.aiTurn;
128 | args['aiDifficulty'] = appModel.aiDifficulty;
129 | args['board'] = board;
130 | aiOperation = CancelableOperation.fromFuture(
131 | compute(calculateAIMove, args),
132 | );
133 | aiOperation?.value.then((move) {
134 | if (move == null || appModel.gameOver) {
135 | appModel.endGame();
136 | } else {
137 | validMoves = [];
138 | var meta = push(move, board, getMeta: true);
139 | _moveCompletion(meta, changeTurn: !meta.promotion);
140 | if (meta.promotion) {
141 | promote(move.promotionType);
142 | }
143 | }
144 | });
145 | }
146 |
147 | void cancelAIMove() {
148 | aiOperation?.cancel();
149 | }
150 |
151 | void undoMove() {
152 | board.redoStack.add(pop(board));
153 | if (appModel.moveMetaList.length > 1) {
154 | var meta = appModel.moveMetaList[appModel.moveMetaList.length - 2];
155 | _moveCompletion(meta, clearRedo: false, undoing: true);
156 | } else {
157 | _undoOpeningMove();
158 | appModel.changeTurn();
159 | }
160 | }
161 |
162 | void undoTwoMoves() {
163 | board.redoStack.add(pop(board));
164 | board.redoStack.add(pop(board));
165 | appModel.popMoveMeta();
166 | if (appModel.moveMetaList.length > 1) {
167 | _moveCompletion(appModel.moveMetaList[appModel.moveMetaList.length - 2],
168 | clearRedo: false, undoing: true, changeTurn: false);
169 | } else {
170 | _undoOpeningMove();
171 | }
172 | }
173 |
174 | void _undoOpeningMove() {
175 | selectedPiece = null;
176 | validMoves = [];
177 | latestMove = null;
178 | checkHintTile = null;
179 | appModel.popMoveMeta();
180 | }
181 |
182 | void redoMove() {
183 | _moveCompletion(pushMSO(board.redoStack.removeLast(), board),
184 | clearRedo: false);
185 | }
186 |
187 | void redoTwoMoves() {
188 | _moveCompletion(pushMSO(board.redoStack.removeLast(), board),
189 | clearRedo: false, updateMetaList: true);
190 | _moveCompletion(pushMSO(board.redoStack.removeLast(), board),
191 | clearRedo: false, updateMetaList: true);
192 | }
193 |
194 | void promote(ChessPieceType type) {
195 | board.moveStack.last.movedPiece?.type = type;
196 | board.moveStack.last.promotionType = type;
197 | addPromotedPiece(board, board.moveStack.last);
198 | appModel.moveMetaList.last.promotionType = type;
199 | _moveCompletion(appModel.moveMetaList.last, updateMetaList: false);
200 | }
201 |
202 | void _moveCompletion(
203 | MoveMeta meta, {
204 | bool clearRedo = true,
205 | bool undoing = false,
206 | bool changeTurn = true,
207 | bool updateMetaList = true,
208 | }) {
209 | if (clearRedo) {
210 | board.redoStack = [];
211 | }
212 | validMoves = [];
213 | latestMove = meta.move;
214 | checkHintTile = null;
215 | var oppositeTurn = oppositePlayer(appModel.turn);
216 | if (kingInCheck(oppositeTurn, board)) {
217 | meta.isCheck = true;
218 | checkHintTile = kingForPlayer(oppositeTurn, board)?.tile;
219 | }
220 | if (kingInCheckmate(oppositeTurn, board)) {
221 | if (!meta.isCheck) {
222 | appModel.stalemate = true;
223 | meta.isStalemate = true;
224 | }
225 | meta.isCheck = false;
226 | meta.isCheckmate = true;
227 | appModel.endGame();
228 | }
229 | if (undoing) {
230 | appModel.popMoveMeta();
231 | appModel.undoEndGame();
232 | } else if (updateMetaList) {
233 | appModel.pushMoveMeta(meta);
234 | }
235 | if (changeTurn) {
236 | appModel.changeTurn();
237 | }
238 | selectedPiece = null;
239 | if (appModel.isAIsTurn && clearRedo && changeTurn) {
240 | _aiMove();
241 | }
242 | }
243 |
244 | int _vector2ToTile(Vector2 vector2) {
245 | if (appModel.flip &&
246 | appModel.playingWithAI &&
247 | appModel.playerSide == Player.player2) {
248 | return (7 - (vector2.y / (tileSize ?? 0)).floor()) * 8 +
249 | (7 - (vector2.x / (tileSize ?? 0)).floor());
250 | } else {
251 | return (vector2.y / (tileSize ?? 0)).floor() * 8 +
252 | (vector2.x / (tileSize ?? 0)).floor();
253 | }
254 | }
255 |
256 | void _drawBoard(Canvas canvas) {
257 | for (int tileNo = 0; tileNo < 64; tileNo++) {
258 | canvas.drawRect(
259 | Rect.fromLTWH(
260 | (tileNo % 8) * (tileSize ?? 0),
261 | (tileNo / 8).floor() * (tileSize ?? 0),
262 | (tileSize ?? 0),
263 | (tileSize ?? 0),
264 | ),
265 | Paint()
266 | ..color = (tileNo + (tileNo / 8).floor()) % 2 == 0
267 | ? appModel.theme.lightTile
268 | : appModel.theme.darkTile,
269 | );
270 | }
271 | }
272 |
273 | void _drawPieces(Canvas canvas) {
274 | for (var piece in board.player1Pieces + board.player2Pieces) {
275 | spriteMap[piece]?.sprite?.render(
276 | canvas,
277 | size: Vector2((tileSize ?? 0) - 10, (tileSize ?? 0) - 10),
278 | position: Vector2(
279 | (spriteMap[piece]?.spriteX ?? 0) + 5,
280 | (spriteMap[piece]?.spriteY ?? 0) + 5,
281 | ),
282 | );
283 | }
284 | }
285 |
286 | void _drawMoveHints(Canvas canvas) {
287 | for (var tile in validMoves) {
288 | canvas.drawCircle(
289 | Offset(
290 | getXFromTile(tile, (tileSize ?? 0), appModel) + ((tileSize ?? 0) / 2),
291 | getYFromTile(tile, (tileSize ?? 0), appModel) + ((tileSize ?? 0) / 2),
292 | ),
293 | (tileSize ?? 0) / 5,
294 | Paint()..color = appModel.theme.moveHint,
295 | );
296 | }
297 | }
298 |
299 | void _drawLatestMove(Canvas canvas) {
300 | if (latestMove != null) {
301 | canvas.drawRect(
302 | Rect.fromLTWH(
303 | getXFromTile(latestMove!.from, tileSize ?? 0, appModel),
304 | getYFromTile(latestMove!.from, tileSize ?? 0, appModel),
305 | tileSize ?? 0,
306 | tileSize ?? 0,
307 | ),
308 | Paint()..color = appModel.theme.latestMove,
309 | );
310 | canvas.drawRect(
311 | Rect.fromLTWH(
312 | getXFromTile(latestMove!.to, tileSize ?? 0, appModel),
313 | getYFromTile(latestMove!.to, tileSize ?? 0, appModel),
314 | tileSize ?? 0,
315 | tileSize ?? 0,
316 | ),
317 | Paint()..color = appModel.theme.latestMove,
318 | );
319 | }
320 | }
321 |
322 | void _drawCheckHint(Canvas canvas) {
323 | if (checkHintTile != null) {
324 | canvas.drawRect(
325 | Rect.fromLTWH(
326 | getXFromTile(checkHintTile!, tileSize ?? 0, appModel),
327 | getYFromTile(checkHintTile!, tileSize ?? 0, appModel),
328 | tileSize ?? 0,
329 | tileSize ?? 0,
330 | ),
331 | Paint()..color = appModel.theme.checkHint,
332 | );
333 | }
334 | }
335 |
336 | void _drawSelectedPieceHint(Canvas canvas) {
337 | if (selectedPiece != null) {
338 | canvas.drawRect(
339 | Rect.fromLTWH(
340 | getXFromTile(selectedPiece!.tile, tileSize ?? 0, appModel),
341 | getYFromTile(selectedPiece!.tile, tileSize ?? 0, appModel),
342 | tileSize ?? 0,
343 | tileSize ?? 0,
344 | ),
345 | Paint()..color = appModel.theme.moveHint,
346 | );
347 | }
348 | }
349 | }
350 |
--------------------------------------------------------------------------------
/lib/logic/chess_board.dart:
--------------------------------------------------------------------------------
1 | import 'package:en_passant/logic/move_calculation/move_classes/move_stack_object.dart';
2 | import 'package:en_passant/logic/move_calculation/openings.dart';
3 | import 'package:en_passant/logic/shared_functions.dart';
4 | import 'package:en_passant/views/components/main_menu_view/game_options/side_picker.dart';
5 |
6 | import 'chess_piece.dart';
7 | import 'move_calculation/move_calculation.dart';
8 | import 'move_calculation/move_classes/move.dart';
9 | import 'move_calculation/move_classes/move_meta.dart';
10 | import 'move_calculation/piece_square_tables.dart';
11 |
12 | const KING_ROW_PIECES = [
13 | ChessPieceType.rook,
14 | ChessPieceType.knight,
15 | ChessPieceType.bishop,
16 | ChessPieceType.queen,
17 | ChessPieceType.king,
18 | ChessPieceType.bishop,
19 | ChessPieceType.knight,
20 | ChessPieceType.rook
21 | ];
22 |
23 | class ChessBoard {
24 | List tiles = List.filled(64, null);
25 | List moveStack = [];
26 | List redoStack = [];
27 | List player1Pieces = [];
28 | List player2Pieces = [];
29 | List player1Rooks = [];
30 | List player2Rooks = [];
31 | List player1Queens = [];
32 | List player2Queens = [];
33 | ChessPiece? player1King;
34 | ChessPiece? player2King;
35 | ChessPiece? enPassantPiece;
36 | bool player1KingInCheck = false;
37 | bool player2KingInCheck = false;
38 | List> possibleOpenings = List.from(openings);
39 | int moveCount = 0;
40 |
41 | ChessBoard() {
42 | _addPiecesForPlayer(Player.player1);
43 | _addPiecesForPlayer(Player.player2);
44 | }
45 |
46 | void _addPiecesForPlayer(Player player) {
47 | var kingRowOffset = player == Player.player1 ? 56 : 0;
48 | var pawnRowOffset = player == Player.player1 ? -8 : 8;
49 | var index = 0;
50 | for (var pieceType in KING_ROW_PIECES) {
51 | var id = player == Player.player1 ? index * 2 : index * 2 + 16;
52 | var piece = ChessPiece(id, pieceType, player, kingRowOffset + index);
53 | var pawn = ChessPiece(id + 1, ChessPieceType.pawn, player,
54 | kingRowOffset + pawnRowOffset + index);
55 | _setTile(piece.tile, piece, this);
56 | _setTile(pawn.tile, pawn, this);
57 | piecesForPlayer(player, this).addAll([piece, pawn]);
58 | if (piece.type == ChessPieceType.king) {
59 | player == Player.player1 ? player1King = piece : player2King = piece;
60 | } else if (piece.type == ChessPieceType.queen) {
61 | _queensForPlayer(player, this).add(piece);
62 | } else if (piece.type == ChessPieceType.rook) {
63 | rooksForPlayer(player, this).add(piece);
64 | }
65 | index++;
66 | }
67 | }
68 | }
69 |
70 | int boardValue(ChessBoard board) {
71 | int value = 0;
72 | for (var piece in board.player1Pieces + board.player2Pieces) {
73 | value += piece.value + squareValue(piece, _inEndGame(board));
74 | }
75 | return value;
76 | }
77 |
78 | MoveMeta push(Move move, ChessBoard board,
79 | {bool getMeta = false,
80 | ChessPieceType promotionType = ChessPieceType.promotion}) {
81 | var mso = MoveStackObject(move, board.tiles[move.from], board.tiles[move.to],
82 | board.enPassantPiece, List.from(board.possibleOpenings));
83 | var meta = MoveMeta(move, mso.movedPiece?.player, mso.movedPiece?.type);
84 | if (board.possibleOpenings.isNotEmpty) {
85 | _filterPossibleOpenings(board, move);
86 | }
87 | if (getMeta) {
88 | _checkMoveAmbiguity(move, meta, board);
89 | }
90 | if (_castled(mso.movedPiece, mso.takenPiece)) {
91 | _castle(board, mso, meta);
92 | } else {
93 | _standardMove(board, mso, meta);
94 | if (mso.movedPiece?.type == ChessPieceType.pawn) {
95 | if (_promotion(mso.movedPiece)) {
96 | mso.promotionType = promotionType;
97 | meta.promotionType = promotionType;
98 | _promote(board, mso, meta);
99 | }
100 | _checkEnPassant(board, mso, meta);
101 | }
102 | }
103 | if (_canTakeEnPassant(mso.movedPiece)) {
104 | board.enPassantPiece = mso.movedPiece;
105 | } else {
106 | board.enPassantPiece = null;
107 | }
108 | if (meta.type == ChessPieceType.pawn && meta.took) {
109 | meta.rowIsAmbiguous = true;
110 | }
111 | board.moveStack.add(mso);
112 | board.moveCount++;
113 | return meta;
114 | }
115 |
116 | MoveMeta pushMSO(MoveStackObject mso, ChessBoard board) {
117 | return push(mso.move, board,
118 | promotionType: mso.promotionType ?? ChessPieceType.promotion);
119 | }
120 |
121 | MoveStackObject pop(ChessBoard board) {
122 | var mso = board.moveStack.removeLast();
123 | board.enPassantPiece = mso.enPassantPiece;
124 | board.possibleOpenings = mso.possibleOpenings ?? [];
125 | if (mso.castled) {
126 | _undoCastle(board, mso);
127 | } else {
128 | _undoStandardMove(board, mso);
129 | if (mso.promotion) {
130 | _undoPromote(board, mso);
131 | }
132 | if (mso.enPassant) {
133 | _addPiece(mso.enPassantPiece, board);
134 | _setTile(mso.enPassantPiece?.tile, mso.enPassantPiece, board);
135 | }
136 | }
137 | board.moveCount--;
138 | return mso;
139 | }
140 |
141 | void _standardMove(ChessBoard board, MoveStackObject mso, MoveMeta meta) {
142 | _setTile(mso.move.to, mso.movedPiece, board);
143 | _setTile(mso.move.from, null, board);
144 | mso.movedPiece?.moveCount++;
145 | if (mso.takenPiece != null) {
146 | _removePiece(mso.takenPiece, board);
147 | meta.took = true;
148 | }
149 | }
150 |
151 | void _undoStandardMove(ChessBoard board, MoveStackObject mso) {
152 | _setTile(mso.move.from, mso.movedPiece, board);
153 | _setTile(mso.move.to, null, board);
154 | if (mso.takenPiece != null) {
155 | _addPiece(mso.takenPiece, board);
156 | _setTile(mso.move.to, mso.takenPiece, board);
157 | }
158 | mso.movedPiece?.moveCount--;
159 | }
160 |
161 | void _castle(ChessBoard board, MoveStackObject mso, MoveMeta meta) {
162 | var king = mso.movedPiece?.type == ChessPieceType.king
163 | ? mso.movedPiece
164 | : mso.takenPiece;
165 | var rook = mso.movedPiece?.type == ChessPieceType.rook
166 | ? mso.movedPiece
167 | : mso.takenPiece;
168 | _setTile(king?.tile, null, board);
169 | _setTile(rook?.tile, null, board);
170 | var kingCol = tileToCol(rook?.tile ?? 0) == 0 ? 2 : 6;
171 | var rookCol = tileToCol(rook?.tile ?? 0) == 0 ? 3 : 5;
172 | _setTile(tileToRow(king?.tile ?? 0) * 8 + kingCol, king, board);
173 | _setTile(tileToRow(rook?.tile ?? 0) * 8 + rookCol, rook, board);
174 | tileToCol(rook?.tile ?? 0) == 3
175 | ? meta.queenCastle = true
176 | : meta.kingCastle = true;
177 | king?.moveCount++;
178 | rook?.moveCount++;
179 | mso.castled = true;
180 | }
181 |
182 | void _undoCastle(ChessBoard board, MoveStackObject mso) {
183 | var king = mso.movedPiece?.type == ChessPieceType.king
184 | ? mso.movedPiece
185 | : mso.takenPiece;
186 | var rook = mso.movedPiece?.type == ChessPieceType.rook
187 | ? mso.movedPiece
188 | : mso.takenPiece;
189 | _setTile(king?.tile, null, board);
190 | _setTile(rook?.tile, null, board);
191 | var rookCol = tileToCol(rook?.tile ?? 0) == 3 ? 0 : 7;
192 | _setTile(tileToRow(king?.tile ?? 0) * 8 + 4, king, board);
193 | _setTile(tileToRow(rook?.tile ?? 0) * 8 + rookCol, rook, board);
194 | king?.moveCount--;
195 | rook?.moveCount--;
196 | }
197 |
198 | void _promote(ChessBoard board, MoveStackObject mso, MoveMeta meta) {
199 | mso.movedPiece?.type = mso.promotionType ?? ChessPieceType.promotion;
200 | if (mso.promotionType != ChessPieceType.promotion) {
201 | addPromotedPiece(board, mso);
202 | }
203 | meta.promotion = true;
204 | mso.promotion = true;
205 | }
206 |
207 | void addPromotedPiece(ChessBoard board, MoveStackObject mso) {
208 | switch (mso.promotionType) {
209 | case ChessPieceType.queen:
210 | {
211 | if (mso.movedPiece != null) {
212 | _queensForPlayer(mso.movedPiece?.player ?? Player.player1, board)
213 | .add(mso.movedPiece!);
214 | }
215 | }
216 | break;
217 | case ChessPieceType.rook:
218 | {
219 | if (mso.movedPiece != null) {
220 | rooksForPlayer(mso.movedPiece?.player ?? Player.player1, board)
221 | .add(mso.movedPiece!);
222 | }
223 | }
224 | break;
225 | default:
226 | {}
227 | }
228 | }
229 |
230 | void _undoPromote(ChessBoard board, MoveStackObject mso) {
231 | mso.movedPiece?.type = ChessPieceType.pawn;
232 | switch (mso.promotionType) {
233 | case ChessPieceType.queen:
234 | {
235 | _queensForPlayer(mso.movedPiece?.player ?? Player.player1, board)
236 | .remove(mso.movedPiece);
237 | }
238 | break;
239 | case ChessPieceType.rook:
240 | {
241 | rooksForPlayer(mso.movedPiece?.player ?? Player.player1, board)
242 | .remove(mso.movedPiece);
243 | }
244 | break;
245 | default:
246 | {}
247 | }
248 | }
249 |
250 | void _checkEnPassant(ChessBoard board, MoveStackObject mso, MoveMeta meta) {
251 | var offset = mso.movedPiece?.player == Player.player1 ? 8 : -8;
252 | var tile = (mso.movedPiece?.tile ?? 0) + offset;
253 | var takenPiece = board.tiles[tile];
254 | if (takenPiece != null && takenPiece == board.enPassantPiece) {
255 | _removePiece(takenPiece, board);
256 | _setTile(takenPiece.tile, null, board);
257 | mso.enPassant = true;
258 | }
259 | }
260 |
261 | void _checkMoveAmbiguity(Move move, MoveMeta moveMeta, ChessBoard board) {
262 | var piece = board.tiles[move.from];
263 | for (var otherPiece
264 | in _piecesOfTypeForPlayer(piece?.type, piece?.player, board)) {
265 | if (piece != otherPiece) {
266 | if (movesForPiece(otherPiece, board).contains(move.to)) {
267 | if (tileToCol(otherPiece.tile) == tileToCol(piece?.tile ?? 0)) {
268 | moveMeta.colIsAmbiguous = true;
269 | } else {
270 | moveMeta.rowIsAmbiguous = true;
271 | }
272 | }
273 | }
274 | }
275 | }
276 |
277 | void _filterPossibleOpenings(ChessBoard board, Move move) {
278 | board.possibleOpenings = board.possibleOpenings
279 | .where((opening) =>
280 | opening[board.moveCount] == move &&
281 | opening.length > board.moveCount + 1)
282 | .toList();
283 | }
284 |
285 | void _setTile(int? tile, ChessPiece? piece, ChessBoard board) {
286 | if (tile != null) {
287 | board.tiles[tile] = piece;
288 | }
289 | if (piece != null) {
290 | piece.tile = tile ?? 0;
291 | }
292 | }
293 |
294 | void _addPiece(ChessPiece? piece, ChessBoard board) {
295 | if (piece != null) {
296 | piecesForPlayer(piece.player, board).add(piece);
297 | if (piece.type == ChessPieceType.rook) {
298 | rooksForPlayer(piece.player, board).add(piece);
299 | }
300 | if (piece.type == ChessPieceType.queen) {
301 | _queensForPlayer(piece.player, board).add(piece);
302 | }
303 | }
304 | }
305 |
306 | void _removePiece(ChessPiece? piece, ChessBoard board) {
307 | if (piece != null) {
308 | piecesForPlayer(piece.player, board).remove(piece);
309 | if (piece.type == ChessPieceType.rook) {
310 | rooksForPlayer(piece.player, board).remove(piece);
311 | }
312 | if (piece.type == ChessPieceType.queen) {
313 | _queensForPlayer(piece.player, board).remove(piece);
314 | }
315 | }
316 | }
317 |
318 | List piecesForPlayer(Player player, ChessBoard board) {
319 | return player == Player.player1 ? board.player1Pieces : board.player2Pieces;
320 | }
321 |
322 | ChessPiece? kingForPlayer(Player player, ChessBoard board) {
323 | return player == Player.player1 ? board.player1King : board.player2King;
324 | }
325 |
326 | List rooksForPlayer(Player player, ChessBoard board) {
327 | return player == Player.player1 ? board.player1Rooks : board.player2Rooks;
328 | }
329 |
330 | List _queensForPlayer(Player player, ChessBoard board) {
331 | return player == Player.player1 ? board.player1Queens : board.player2Queens;
332 | }
333 |
334 | List _piecesOfTypeForPlayer(
335 | ChessPieceType? type, Player? player, ChessBoard board) {
336 | List pieces = [];
337 | if (type != null && player != null) {
338 | for (var piece in piecesForPlayer(player, board)) {
339 | if (piece.type == type) {
340 | pieces.add(piece);
341 | }
342 | }
343 | }
344 | return pieces;
345 | }
346 |
347 | bool _castled(ChessPiece? movedPiece, ChessPiece? takenPiece) {
348 | return takenPiece != null && takenPiece.player == movedPiece?.player;
349 | }
350 |
351 | bool _promotion(ChessPiece? movedPiece) {
352 | return movedPiece?.type == ChessPieceType.pawn &&
353 | (tileToRow(movedPiece?.tile ?? 0) == 7 ||
354 | tileToRow(movedPiece?.tile ?? 0) == 0);
355 | }
356 |
357 | bool _canTakeEnPassant(ChessPiece? movedPiece) {
358 | return movedPiece?.moveCount == 1 &&
359 | movedPiece?.type == ChessPieceType.pawn &&
360 | (tileToRow(movedPiece?.tile ?? 0) == 3 ||
361 | tileToRow(movedPiece?.tile ?? 0) == 4);
362 | }
363 |
364 | bool _inEndGame(ChessBoard board) {
365 | return (_queensForPlayer(Player.player1, board).isEmpty &&
366 | _queensForPlayer(Player.player2, board).isEmpty) ||
367 | piecesForPlayer(Player.player1, board).length <= 3 ||
368 | piecesForPlayer(Player.player2, board).length <= 3;
369 | }
370 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 51;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
12 | 3C44AB63D4EFC8CB2C5AA18B /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FDEA1FE002B71AC8DA98877F /* Pods_Runner.framework */; };
13 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
14 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
15 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
16 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXCopyFilesBuildPhase section */
20 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
21 | isa = PBXCopyFilesBuildPhase;
22 | buildActionMask = 2147483647;
23 | dstPath = "";
24 | dstSubfolderSpec = 10;
25 | files = (
26 | );
27 | name = "Embed Frameworks";
28 | runOnlyForDeploymentPostprocessing = 0;
29 | };
30 | /* End PBXCopyFilesBuildPhase section */
31 |
32 | /* Begin PBXFileReference section */
33 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
34 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
35 | 31CDE7A3FC45BD8481EFF020 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
36 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
37 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
38 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
39 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
40 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
41 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
42 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
43 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
44 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
45 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
46 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
47 | C88316130FDE678B7DA9DF23 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
48 | DD0A2C228581C3B9DF1CF17A /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
49 | F7EE8C1B25A2D68100211DE9 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; };
50 | FDEA1FE002B71AC8DA98877F /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
51 | /* End PBXFileReference section */
52 |
53 | /* Begin PBXFrameworksBuildPhase section */
54 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
55 | isa = PBXFrameworksBuildPhase;
56 | buildActionMask = 2147483647;
57 | files = (
58 | 3C44AB63D4EFC8CB2C5AA18B /* Pods_Runner.framework in Frameworks */,
59 | );
60 | runOnlyForDeploymentPostprocessing = 0;
61 | };
62 | /* End PBXFrameworksBuildPhase section */
63 |
64 | /* Begin PBXGroup section */
65 | 482B0E5AF436022460FB3D5A /* Pods */ = {
66 | isa = PBXGroup;
67 | children = (
68 | 31CDE7A3FC45BD8481EFF020 /* Pods-Runner.debug.xcconfig */,
69 | DD0A2C228581C3B9DF1CF17A /* Pods-Runner.release.xcconfig */,
70 | C88316130FDE678B7DA9DF23 /* Pods-Runner.profile.xcconfig */,
71 | );
72 | path = Pods;
73 | sourceTree = "";
74 | };
75 | 9740EEB11CF90186004384FC /* Flutter */ = {
76 | isa = PBXGroup;
77 | children = (
78 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
79 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
80 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
81 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
82 | );
83 | name = Flutter;
84 | sourceTree = "";
85 | };
86 | 97C146E51CF9000F007C117D = {
87 | isa = PBXGroup;
88 | children = (
89 | 9740EEB11CF90186004384FC /* Flutter */,
90 | 97C146F01CF9000F007C117D /* Runner */,
91 | 97C146EF1CF9000F007C117D /* Products */,
92 | 482B0E5AF436022460FB3D5A /* Pods */,
93 | FC61BF6918D204E06EF93CBB /* Frameworks */,
94 | );
95 | sourceTree = "";
96 | };
97 | 97C146EF1CF9000F007C117D /* Products */ = {
98 | isa = PBXGroup;
99 | children = (
100 | 97C146EE1CF9000F007C117D /* Runner.app */,
101 | );
102 | name = Products;
103 | sourceTree = "";
104 | };
105 | 97C146F01CF9000F007C117D /* Runner */ = {
106 | isa = PBXGroup;
107 | children = (
108 | F7EE8C1B25A2D68100211DE9 /* Runner.entitlements */,
109 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
110 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
111 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
112 | 97C147021CF9000F007C117D /* Info.plist */,
113 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
114 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
115 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
116 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
117 | );
118 | path = Runner;
119 | sourceTree = "";
120 | };
121 | FC61BF6918D204E06EF93CBB /* Frameworks */ = {
122 | isa = PBXGroup;
123 | children = (
124 | FDEA1FE002B71AC8DA98877F /* Pods_Runner.framework */,
125 | );
126 | name = Frameworks;
127 | sourceTree = "";
128 | };
129 | /* End PBXGroup section */
130 |
131 | /* Begin PBXNativeTarget section */
132 | 97C146ED1CF9000F007C117D /* Runner */ = {
133 | isa = PBXNativeTarget;
134 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
135 | buildPhases = (
136 | AA9EF834C0F29F5E2941E497 /* [CP] Check Pods Manifest.lock */,
137 | 9740EEB61CF901F6004384FC /* Run Script */,
138 | 97C146EA1CF9000F007C117D /* Sources */,
139 | 97C146EB1CF9000F007C117D /* Frameworks */,
140 | 97C146EC1CF9000F007C117D /* Resources */,
141 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
142 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
143 | 5606DDAEC1E3948199FB8624 /* [CP] Embed Pods Frameworks */,
144 | );
145 | buildRules = (
146 | );
147 | dependencies = (
148 | );
149 | name = Runner;
150 | productName = Runner;
151 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
152 | productType = "com.apple.product-type.application";
153 | };
154 | /* End PBXNativeTarget section */
155 |
156 | /* Begin PBXProject section */
157 | 97C146E61CF9000F007C117D /* Project object */ = {
158 | isa = PBXProject;
159 | attributes = {
160 | LastUpgradeCheck = 1230;
161 | ORGANIZATIONNAME = "";
162 | TargetAttributes = {
163 | 97C146ED1CF9000F007C117D = {
164 | CreatedOnToolsVersion = 7.3.1;
165 | LastSwiftMigration = 1100;
166 | };
167 | };
168 | };
169 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
170 | compatibilityVersion = "Xcode 9.3";
171 | developmentRegion = en;
172 | hasScannedForEncodings = 0;
173 | knownRegions = (
174 | en,
175 | Base,
176 | );
177 | mainGroup = 97C146E51CF9000F007C117D;
178 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
179 | projectDirPath = "";
180 | projectRoot = "";
181 | targets = (
182 | 97C146ED1CF9000F007C117D /* Runner */,
183 | );
184 | };
185 | /* End PBXProject section */
186 |
187 | /* Begin PBXResourcesBuildPhase section */
188 | 97C146EC1CF9000F007C117D /* Resources */ = {
189 | isa = PBXResourcesBuildPhase;
190 | buildActionMask = 2147483647;
191 | files = (
192 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
193 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
194 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
195 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
196 | );
197 | runOnlyForDeploymentPostprocessing = 0;
198 | };
199 | /* End PBXResourcesBuildPhase section */
200 |
201 | /* Begin PBXShellScriptBuildPhase section */
202 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
203 | isa = PBXShellScriptBuildPhase;
204 | buildActionMask = 2147483647;
205 | files = (
206 | );
207 | inputPaths = (
208 | );
209 | name = "Thin Binary";
210 | outputPaths = (
211 | );
212 | runOnlyForDeploymentPostprocessing = 0;
213 | shellPath = /bin/sh;
214 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
215 | };
216 | 5606DDAEC1E3948199FB8624 /* [CP] Embed Pods Frameworks */ = {
217 | isa = PBXShellScriptBuildPhase;
218 | buildActionMask = 2147483647;
219 | files = (
220 | );
221 | inputFileListPaths = (
222 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
223 | );
224 | name = "[CP] Embed Pods Frameworks";
225 | outputFileListPaths = (
226 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
227 | );
228 | runOnlyForDeploymentPostprocessing = 0;
229 | shellPath = /bin/sh;
230 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
231 | showEnvVarsInLog = 0;
232 | };
233 | 9740EEB61CF901F6004384FC /* Run Script */ = {
234 | isa = PBXShellScriptBuildPhase;
235 | buildActionMask = 2147483647;
236 | files = (
237 | );
238 | inputPaths = (
239 | );
240 | name = "Run Script";
241 | outputPaths = (
242 | );
243 | runOnlyForDeploymentPostprocessing = 0;
244 | shellPath = /bin/sh;
245 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
246 | };
247 | AA9EF834C0F29F5E2941E497 /* [CP] Check Pods Manifest.lock */ = {
248 | isa = PBXShellScriptBuildPhase;
249 | buildActionMask = 2147483647;
250 | files = (
251 | );
252 | inputFileListPaths = (
253 | );
254 | inputPaths = (
255 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
256 | "${PODS_ROOT}/Manifest.lock",
257 | );
258 | name = "[CP] Check Pods Manifest.lock";
259 | outputFileListPaths = (
260 | );
261 | outputPaths = (
262 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
263 | );
264 | runOnlyForDeploymentPostprocessing = 0;
265 | shellPath = /bin/sh;
266 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
267 | showEnvVarsInLog = 0;
268 | };
269 | /* End PBXShellScriptBuildPhase section */
270 |
271 | /* Begin PBXSourcesBuildPhase section */
272 | 97C146EA1CF9000F007C117D /* Sources */ = {
273 | isa = PBXSourcesBuildPhase;
274 | buildActionMask = 2147483647;
275 | files = (
276 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
277 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
278 | );
279 | runOnlyForDeploymentPostprocessing = 0;
280 | };
281 | /* End PBXSourcesBuildPhase section */
282 |
283 | /* Begin PBXVariantGroup section */
284 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
285 | isa = PBXVariantGroup;
286 | children = (
287 | 97C146FB1CF9000F007C117D /* Base */,
288 | );
289 | name = Main.storyboard;
290 | sourceTree = "";
291 | };
292 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
293 | isa = PBXVariantGroup;
294 | children = (
295 | 97C147001CF9000F007C117D /* Base */,
296 | );
297 | name = LaunchScreen.storyboard;
298 | sourceTree = "";
299 | };
300 | /* End PBXVariantGroup section */
301 |
302 | /* Begin XCBuildConfiguration section */
303 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
304 | isa = XCBuildConfiguration;
305 | buildSettings = {
306 | ALWAYS_SEARCH_USER_PATHS = NO;
307 | CLANG_ANALYZER_NONNULL = YES;
308 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
309 | CLANG_CXX_LIBRARY = "libc++";
310 | CLANG_ENABLE_MODULES = YES;
311 | CLANG_ENABLE_OBJC_ARC = YES;
312 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
313 | CLANG_WARN_BOOL_CONVERSION = YES;
314 | CLANG_WARN_COMMA = YES;
315 | CLANG_WARN_CONSTANT_CONVERSION = YES;
316 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
317 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
318 | CLANG_WARN_EMPTY_BODY = YES;
319 | CLANG_WARN_ENUM_CONVERSION = YES;
320 | CLANG_WARN_INFINITE_RECURSION = YES;
321 | CLANG_WARN_INT_CONVERSION = YES;
322 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
323 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
324 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
325 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
326 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
327 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
328 | CLANG_WARN_STRICT_PROTOTYPES = YES;
329 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
330 | CLANG_WARN_UNREACHABLE_CODE = YES;
331 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
332 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
333 | COPY_PHASE_STRIP = NO;
334 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
335 | ENABLE_NS_ASSERTIONS = NO;
336 | ENABLE_STRICT_OBJC_MSGSEND = YES;
337 | GCC_C_LANGUAGE_STANDARD = gnu99;
338 | GCC_NO_COMMON_BLOCKS = YES;
339 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
340 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
341 | GCC_WARN_UNDECLARED_SELECTOR = YES;
342 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
343 | GCC_WARN_UNUSED_FUNCTION = YES;
344 | GCC_WARN_UNUSED_VARIABLE = YES;
345 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
346 | MTL_ENABLE_DEBUG_INFO = NO;
347 | SDKROOT = iphoneos;
348 | SUPPORTED_PLATFORMS = iphoneos;
349 | TARGETED_DEVICE_FAMILY = "1,2";
350 | VALIDATE_PRODUCT = YES;
351 | };
352 | name = Profile;
353 | };
354 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
355 | isa = XCBuildConfiguration;
356 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
357 | buildSettings = {
358 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
359 | CLANG_ENABLE_MODULES = YES;
360 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
361 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
362 | DEVELOPMENT_TEAM = DKFDXK99VA;
363 | ENABLE_BITCODE = NO;
364 | FRAMEWORK_SEARCH_PATHS = (
365 | "$(inherited)",
366 | "$(PROJECT_DIR)/Flutter",
367 | );
368 | INFOPLIST_FILE = Runner/Info.plist;
369 | LD_RUNPATH_SEARCH_PATHS = (
370 | "$(inherited)",
371 | "@executable_path/Frameworks",
372 | );
373 | LIBRARY_SEARCH_PATHS = (
374 | "$(inherited)",
375 | "$(PROJECT_DIR)/Flutter",
376 | );
377 | PRODUCT_BUNDLE_IDENTIFIER = "com.pscottzero.en-passant";
378 | PRODUCT_NAME = "$(TARGET_NAME)";
379 | SUPPORTS_MACCATALYST = NO;
380 | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
381 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
382 | SWIFT_VERSION = 5.0;
383 | TARGETED_DEVICE_FAMILY = 1;
384 | VERSIONING_SYSTEM = "apple-generic";
385 | };
386 | name = Profile;
387 | };
388 | 97C147031CF9000F007C117D /* Debug */ = {
389 | isa = XCBuildConfiguration;
390 | buildSettings = {
391 | ALWAYS_SEARCH_USER_PATHS = NO;
392 | CLANG_ANALYZER_NONNULL = YES;
393 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
394 | CLANG_CXX_LIBRARY = "libc++";
395 | CLANG_ENABLE_MODULES = YES;
396 | CLANG_ENABLE_OBJC_ARC = YES;
397 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
398 | CLANG_WARN_BOOL_CONVERSION = YES;
399 | CLANG_WARN_COMMA = YES;
400 | CLANG_WARN_CONSTANT_CONVERSION = YES;
401 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
402 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
403 | CLANG_WARN_EMPTY_BODY = YES;
404 | CLANG_WARN_ENUM_CONVERSION = YES;
405 | CLANG_WARN_INFINITE_RECURSION = YES;
406 | CLANG_WARN_INT_CONVERSION = YES;
407 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
408 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
409 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
410 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
411 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
412 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
413 | CLANG_WARN_STRICT_PROTOTYPES = YES;
414 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
415 | CLANG_WARN_UNREACHABLE_CODE = YES;
416 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
417 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
418 | COPY_PHASE_STRIP = NO;
419 | DEBUG_INFORMATION_FORMAT = dwarf;
420 | ENABLE_STRICT_OBJC_MSGSEND = YES;
421 | ENABLE_TESTABILITY = YES;
422 | GCC_C_LANGUAGE_STANDARD = gnu99;
423 | GCC_DYNAMIC_NO_PIC = NO;
424 | GCC_NO_COMMON_BLOCKS = YES;
425 | GCC_OPTIMIZATION_LEVEL = 0;
426 | GCC_PREPROCESSOR_DEFINITIONS = (
427 | "DEBUG=1",
428 | "$(inherited)",
429 | );
430 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
431 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
432 | GCC_WARN_UNDECLARED_SELECTOR = YES;
433 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
434 | GCC_WARN_UNUSED_FUNCTION = YES;
435 | GCC_WARN_UNUSED_VARIABLE = YES;
436 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
437 | MTL_ENABLE_DEBUG_INFO = YES;
438 | ONLY_ACTIVE_ARCH = YES;
439 | SDKROOT = iphoneos;
440 | TARGETED_DEVICE_FAMILY = "1,2";
441 | };
442 | name = Debug;
443 | };
444 | 97C147041CF9000F007C117D /* Release */ = {
445 | isa = XCBuildConfiguration;
446 | buildSettings = {
447 | ALWAYS_SEARCH_USER_PATHS = NO;
448 | CLANG_ANALYZER_NONNULL = YES;
449 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
450 | CLANG_CXX_LIBRARY = "libc++";
451 | CLANG_ENABLE_MODULES = YES;
452 | CLANG_ENABLE_OBJC_ARC = YES;
453 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
454 | CLANG_WARN_BOOL_CONVERSION = YES;
455 | CLANG_WARN_COMMA = YES;
456 | CLANG_WARN_CONSTANT_CONVERSION = YES;
457 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
458 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
459 | CLANG_WARN_EMPTY_BODY = YES;
460 | CLANG_WARN_ENUM_CONVERSION = YES;
461 | CLANG_WARN_INFINITE_RECURSION = YES;
462 | CLANG_WARN_INT_CONVERSION = YES;
463 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
464 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
465 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
466 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
467 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
468 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
469 | CLANG_WARN_STRICT_PROTOTYPES = YES;
470 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
471 | CLANG_WARN_UNREACHABLE_CODE = YES;
472 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
473 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
474 | COPY_PHASE_STRIP = NO;
475 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
476 | ENABLE_NS_ASSERTIONS = NO;
477 | ENABLE_STRICT_OBJC_MSGSEND = YES;
478 | GCC_C_LANGUAGE_STANDARD = gnu99;
479 | GCC_NO_COMMON_BLOCKS = YES;
480 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
481 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
482 | GCC_WARN_UNDECLARED_SELECTOR = YES;
483 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
484 | GCC_WARN_UNUSED_FUNCTION = YES;
485 | GCC_WARN_UNUSED_VARIABLE = YES;
486 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
487 | MTL_ENABLE_DEBUG_INFO = NO;
488 | SDKROOT = iphoneos;
489 | SUPPORTED_PLATFORMS = iphoneos;
490 | SWIFT_COMPILATION_MODE = wholemodule;
491 | SWIFT_OPTIMIZATION_LEVEL = "-O";
492 | TARGETED_DEVICE_FAMILY = "1,2";
493 | VALIDATE_PRODUCT = YES;
494 | };
495 | name = Release;
496 | };
497 | 97C147061CF9000F007C117D /* Debug */ = {
498 | isa = XCBuildConfiguration;
499 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
500 | buildSettings = {
501 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
502 | CLANG_ENABLE_MODULES = YES;
503 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
504 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
505 | DEVELOPMENT_TEAM = DKFDXK99VA;
506 | ENABLE_BITCODE = NO;
507 | FRAMEWORK_SEARCH_PATHS = (
508 | "$(inherited)",
509 | "$(PROJECT_DIR)/Flutter",
510 | );
511 | INFOPLIST_FILE = Runner/Info.plist;
512 | LD_RUNPATH_SEARCH_PATHS = (
513 | "$(inherited)",
514 | "@executable_path/Frameworks",
515 | );
516 | LIBRARY_SEARCH_PATHS = (
517 | "$(inherited)",
518 | "$(PROJECT_DIR)/Flutter",
519 | );
520 | PRODUCT_BUNDLE_IDENTIFIER = "com.pscottzero.en-passant";
521 | PRODUCT_NAME = "$(TARGET_NAME)";
522 | SUPPORTS_MACCATALYST = NO;
523 | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
524 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
525 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
526 | SWIFT_VERSION = 5.0;
527 | TARGETED_DEVICE_FAMILY = 1;
528 | VERSIONING_SYSTEM = "apple-generic";
529 | };
530 | name = Debug;
531 | };
532 | 97C147071CF9000F007C117D /* Release */ = {
533 | isa = XCBuildConfiguration;
534 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
535 | buildSettings = {
536 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
537 | CLANG_ENABLE_MODULES = YES;
538 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
539 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
540 | DEVELOPMENT_TEAM = DKFDXK99VA;
541 | ENABLE_BITCODE = NO;
542 | FRAMEWORK_SEARCH_PATHS = (
543 | "$(inherited)",
544 | "$(PROJECT_DIR)/Flutter",
545 | );
546 | INFOPLIST_FILE = Runner/Info.plist;
547 | LD_RUNPATH_SEARCH_PATHS = (
548 | "$(inherited)",
549 | "@executable_path/Frameworks",
550 | );
551 | LIBRARY_SEARCH_PATHS = (
552 | "$(inherited)",
553 | "$(PROJECT_DIR)/Flutter",
554 | );
555 | PRODUCT_BUNDLE_IDENTIFIER = "com.pscottzero.en-passant";
556 | PRODUCT_NAME = "$(TARGET_NAME)";
557 | SUPPORTS_MACCATALYST = NO;
558 | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
559 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
560 | SWIFT_VERSION = 5.0;
561 | TARGETED_DEVICE_FAMILY = 1;
562 | VERSIONING_SYSTEM = "apple-generic";
563 | };
564 | name = Release;
565 | };
566 | /* End XCBuildConfiguration section */
567 |
568 | /* Begin XCConfigurationList section */
569 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
570 | isa = XCConfigurationList;
571 | buildConfigurations = (
572 | 97C147031CF9000F007C117D /* Debug */,
573 | 97C147041CF9000F007C117D /* Release */,
574 | 249021D3217E4FDB00AE95B9 /* Profile */,
575 | );
576 | defaultConfigurationIsVisible = 0;
577 | defaultConfigurationName = Release;
578 | };
579 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
580 | isa = XCConfigurationList;
581 | buildConfigurations = (
582 | 97C147061CF9000F007C117D /* Debug */,
583 | 97C147071CF9000F007C117D /* Release */,
584 | 249021D4217E4FDB00AE95B9 /* Profile */,
585 | );
586 | defaultConfigurationIsVisible = 0;
587 | defaultConfigurationName = Release;
588 | };
589 | /* End XCConfigurationList section */
590 | };
591 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
592 | }
593 |
--------------------------------------------------------------------------------